返回提交历史
Added
XFEExtension.NetCore.WinUIHelper/Implements/AutoNavigatableViewModelBase.cs
+9
-0
Added
XFEExtension.NetCore.WinUIHelper/Implements/SearchableViewModelBase.cs
+35
-0
Added
XFEExtension.NetCore.WinUIHelper/Implements/ServiceBaseViewModelBase.cs
+12
-0
Added
XFEExtension.NetCore.WinUIHelper/Implements/Services/PermissionVisibilityService.cs
+26
-0
Added
XFEExtension.NetCore.WinUIHelper/Interface/IAsyncRefreshableViewModel.cs
+6
-0
Added
XFEExtension.NetCore.WinUIHelper/Interface/IListViewModel.cs
+71
-0
Added
XFEExtension.NetCore.WinUIHelper/Interface/IRefreshableViewModel.cs
+6
-0
Added
XFEExtension.NetCore.WinUIHelper/Interface/ISearchableViewModel.cs
+34
-0
Added
XFEExtension.NetCore.WinUIHelper/Interface/Services/IPermissionVisibilityService.cs
+14
-0
Modified
XFEExtension.NetCore.WinUIHelper/Utilities/Addition/NavigationAddition.cs
+45
-1
Added
XFEExtension.NetCore.WinUIHelper/Utilities/Addition/PermissionAddition.cs
+36
-0
Added
XFEExtension.NetCore.WinUIHelper/Utilities/Helper/ObjectHelper.cs
+136
-0
Added
XFEExtension.NetCore.WinUIHelper/Utilities/Helper/PermissionHelper.cs
+77
-0
Modified
XFEExtension.NetCore.WinUIHelper/XFEExtension.NetCore.WinUIHelper.csproj
+1
-0
XFEstudio/XFEExtension.NetCore.WinUIHelper
新增导航、权限管理及搜索相关功能支持
新增导航附加属性类 `NavigationAddition`,支持为 `NavigationViewItem` 指定导航目标和参数。 引入 `CommunityToolkit.Mvvm`,支持 MVVM 模式下的属性通知。 新增多个抽象类和接口(如 `AutoNavigatableViewModelBase`、`SearchableViewModelBase`、`IListViewModel` 等),实现搜索、导航和权限管理功能。 新增 `PermissionVisibilityService` 和 `PermissionAddition`,支持基于权限级别的 UI 可见性管理。 新增工具类 `ObjectHelper` 和 `PermissionHelper`,提供对象搜索、值复制及权限可见性设置等功能。
0298b1c
代码差异
14 个文件
+508
-1
@@ -0,0 +1,9 @@
1
using XFEExtension.NetCore.WinUIHelper.Interface.Services;
2
using XFEExtension.NetCore.WinUIHelper.Utilities;
3
4
namespace XFEExtension.NetCore.WinUIHelper.Implements;
5
6
public abstract partial class AutoNavigatableViewModelBase<T> : ViewModelBase
7
{
8
public IAutoNavigationParameterService<T> AutoNavigationParameterService { get; } = ServiceManager.GetService<IAutoNavigationParameterService<T>>();
9
}
@@ -0,0 +1,35 @@
1
using CommunityToolkit.Mvvm.ComponentModel;
2
using System.Collections.ObjectModel;
3
using XFEExtension.NetCore.DelegateExtension;
4
using XFEExtension.NetCore.WinUIHelper.Interface;
5
6
namespace XFEExtension.NetCore.WinUIHelper.Implements;
7
8
public abstract partial class SearchableViewModelBase<T, F> : ServiceBaseViewModelBase<F>, ISearchableViewModel<T> where T : class
9
{
10
[ObservableProperty]
11
private T? selectedItem;
12
[ObservableProperty]
13
private string searchText = string.Empty;
14
public bool AutoSearch { get; set; } = true;
15
public ObservableCollection<T> ViewList { get; set; } = [];
16
public List<T> ModelList { get; set; } = [];
17
public Func<string, T, bool> SearchPredicate { get; set; } = (text, item) => ObjectHelper.Search(item, text);
18
19
public event XFEEventHandler<string>? SearchTextChanged;
20
21
partial void OnSearchTextChanged(string value)
22
{
23
SearchTextChanged?.Invoke(value);
24
if (AutoSearch)
25
Search();
26
}
27
28
protected virtual void Add() { }
29
protected virtual async Task AddAsync() => await Task.CompletedTask;
30
protected virtual void Remove() { }
31
protected virtual async Task RemoveAsync() => await Task.CompletedTask;
32
protected virtual void Edit() { }
33
protected virtual async Task EditAsync() => await Task.CompletedTask;
34
protected void Search() => (this as ISearchableViewModel<T>).SearchAndLoadToList();
35
}
@@ -0,0 +1,12 @@
1
using XFEExtension.NetCore.WinUIHelper.Interface.Services;
2
using XFEExtension.NetCore.WinUIHelper.Utilities;
3
4
namespace XFEExtension.NetCore.WinUIHelper.Implements;
5
6
public abstract partial class ServiceBaseViewModelBase<T> : AutoNavigatableViewModelBase<T>
7
{
8
public IDialogService DialogService { get; } = ServiceManager.GetService<IDialogService>();
9
public INavigationViewService? NavigationViewService { get; } = ServiceManager.GetGlobalService<INavigationViewService>();
10
public IMessageService? MessageService { get; } = ServiceManager.GetGlobalService<IMessageService>();
11
public ILoadingService? LoadingService { get; } = ServiceManager.GetGlobalService<ILoadingService>();
12
}
@@ -0,0 +1,26 @@
1
using XFEExtension.NetCore.WinUIHelper.Interface.Services;
2
using XFEExtension.NetCore.WinUIHelper.Utilities.Helpers;
3
4
namespace XFEExtension.NetCore.WinUIHelper.Implements.Services;
5
6
/// <summary>
7
/// Provides functionality to manage the visibility of page elements based on permission levels within the application.
8
/// </summary>
9
/// <remarks>Use this service to initialize the current page context and update the visibility of its child
10
/// elements according to the specified permission level. This service is typically used to control access to UI
11
/// components depending on user roles or permissions.</remarks>
12
public class PermissionVisibilityService : GlobalServiceBase, IPermissionVisibilityService
13
{
14
private Page? currentPage;
15
/// <inheritdoc/>
16
public Page? CurrentPage => currentPage;
17
18
/// <inheritdoc/>
19
public void Initialize(Page page)
20
{
21
currentPage = page;
22
}
23
24
/// <inheritdoc/>
25
public void Refresh(int permissionLevel) => PermissionHelper.SetChildVisibility(currentPage!, permissionLevel);
26
}
@@ -0,0 +1,6 @@
1
namespace XFEExtension.NetCore.WinUIHelper.Interface;
2
3
public interface IAsyncRefreshableViewModel
4
{
5
Task RefreshAsync();
6
}
@@ -0,0 +1,71 @@
1
using System.Collections.ObjectModel;
2
3
namespace XFEExtension.NetCore.WinUIHelper.Interface;
4
5
/// <summary>
6
/// 指定类型列表的视图模型接口
7
/// </summary>
8
/// <typeparam name="T">模型类型</typeparam>
9
public interface IListViewModel<T> where T : class
10
{
11
ObservableCollection<T> ViewList { get; set; }
12
List<T> ModelList { get; set; }
13
14
/// <summary>
15
/// 加载到视图列表
16
/// </summary>
17
/// <param name="list"></param>
18
void LoadToViewList(IEnumerable<T> list)
19
{
20
Clear();
21
foreach (var item in list)
22
Add(item);
23
}
24
25
/// <summary>
26
/// 添加到视图列表
27
/// </summary>
28
/// <param name="list"></param>
29
void AddToViewList(IEnumerable<T> list)
30
{
31
foreach (var item in list)
32
ViewList.Add(item);
33
}
34
35
/// <summary>
36
/// 清除视图列表
37
/// </summary>
38
void Clear() => ViewList.Clear();
39
40
/// <summary>
41
/// 向视图列表添加一个元素
42
/// </summary>
43
/// <param name="item"></param>
44
void Add(T item) => ViewList.Add(item);
45
46
/// <summary>
47
/// 从视图列表中移除指定元素
48
/// </summary>
49
/// <param name="item"></param>
50
void Remove(T item) => ViewList.Remove(item);
51
52
/// <summary>
53
/// 在视图列表指定位置移除一个元素
54
/// </summary>
55
/// <param name="index"></param>
56
void RemoveAt(int index) => ViewList.RemoveAt(index);
57
58
/// <summary>
59
/// 视图列表中是否包含指定元素
60
/// </summary>
61
/// <param name="item"></param>
62
/// <returns></returns>
63
bool Contains(T item) => ViewList.Contains(item);
64
65
/// <summary>
66
/// 使用指定表达式搜索模型列表(而非视图列表)
67
/// </summary>
68
/// <param name="predicte"></param>
69
/// <returns></returns>
70
IEnumerable<T> Search(Func<T, bool> predicte) => ModelList.Where(item => predicte(item));
71
}
@@ -0,0 +1,6 @@
1
namespace XFEExtension.NetCore.WinUIHelper.Interface;
2
3
public interface IRefreshableViewModel
4
{
5
void Refresh();
6
}
@@ -0,0 +1,34 @@
1
namespace XFEExtension.NetCore.WinUIHelper.Interface;
2
3
/// <summary>
4
/// 可搜索视图模型接口
5
/// </summary>
6
/// <typeparam name="T"></typeparam>
7
public interface ISearchableViewModel<T> : IListViewModel<T> where T : class
8
{
9
/// <summary>
10
/// 搜索文本
11
/// </summary>
12
string SearchText { get; set; }
13
/// <summary>
14
/// 搜索预测
15
/// </summary>
16
Func<string, T, bool> SearchPredicate { get; set; }
17
18
/// <summary>
19
/// 搜索模型
20
/// </summary>
21
/// <returns></returns>
22
IEnumerable<T> SearchModels(string searchText) => ModelList.Where(item => SearchPredicate(searchText, item));
23
24
/// <summary>
25
/// 搜索模型
26
/// </summary>
27
/// <returns></returns>
28
IEnumerable<T> SearchModels() => ModelList.Where(item => SearchPredicate(SearchText, item));
29
30
/// <summary>
31
/// 搜索并加载模型
32
/// </summary>
33
void SearchAndLoadToList() => LoadToViewList(SearchModels());
34
}
@@ -0,0 +1,14 @@
1
namespace XFEExtension.NetCore.WinUIHelper.Interface.Services;
2
3
/// <summary>
4
/// Provides functionality to refresh the visibility state of permissions based on the specified permission level.
5
/// </summary>
6
public interface IPermissionVisibilityService : IGlobalService, IPageService
7
{
8
/// <summary>
9
/// Refreshes the current state based on the specified permission level.
10
/// </summary>
11
/// <param name="permissionLevel">The permission level to apply during the refresh operation. Must be a non-negative integer; higher values may
12
/// grant access to additional resources.</param>
13
void Refresh(int permissionLevel);
14
}
@@ -1,17 +1,61 @@
1
1
namespace XFEExtension.NetCore.WinUIHelper.Utilities.Addition;
2
2
3
3
/// <summary>
4
/// 导航附加属性
4
/// Provides attached properties for associating navigation targets and parameters with NavigationViewItem controls.
5
5
/// </summary>
6
/// <remarks>Use the attached properties defined by this class to specify navigation destinations and parameters
7
/// for individual NavigationViewItem instances in a NavigationView. These properties enable declarative navigation
8
/// configuration in XAML or code-behind, allowing navigation logic to retrieve target information and parameters when a
9
/// navigation item is invoked.</remarks>
6
10
public class NavigationAddition
7
11
{
12
/// <summary>
13
/// Retrieves the navigation target associated with the specified navigation view item.
14
/// </summary>
15
/// <param name="item">The navigation view item from which to obtain the navigation target. Cannot be null.</param>
16
/// <returns>A string representing the navigation target for the specified item, or null if no target is set.</returns>
8
17
public static string GetNavigateTo(NavigationViewItem item) => (string)item.GetValue(NavigateToProperty);
18
/// <summary>
19
/// Sets the navigation target value for the specified NavigationViewItem.
20
/// </summary>
21
/// <remarks>Use this method to attach a navigation target to a NavigationViewItem, enabling navigation
22
/// logic to identify the destination when the item is selected.</remarks>
23
/// <param name="item">The NavigationViewItem to associate with the navigation target value. Cannot be null.</param>
24
/// <param name="value">The navigation target value to assign. This value typically represents a page key or URI used for navigation.</param>
9
25
public static void SetNavigateTo(NavigationViewItem item, string value) => item.SetValue(NavigateToProperty, value);
26
/// <summary>
27
/// Identifies the NavigateTo attached property, which specifies the navigation target as a URI or page name for
28
/// supported UI elements.
29
/// </summary>
30
/// <remarks>This dependency property can be set on UI elements to enable navigation behavior, typically
31
/// in frameworks such as WPF or UWP. The value should be a valid URI or page identifier recognized by the
32
/// navigation system. The default value is an empty string.</remarks>
10
33
11
34
public static readonly DependencyProperty NavigateToProperty = DependencyProperty.RegisterAttached("NavigateTo", typeof(string), typeof(NavigationAddition), new PropertyMetadata(""));
12
35
36
/// <summary>
37
/// Retrieves the navigation parameter associated with the specified NavigationViewItem.
38
/// </summary>
39
/// <param name="item">The NavigationViewItem from which to obtain the navigation parameter. Cannot be null.</param>
40
/// <returns>An object representing the navigation parameter for the specified item, or null if no parameter is set.</returns>
13
41
public static object GetNavigateParameter(NavigationViewItem item) => item.GetValue(NavigateParameterProperty);
42
/// <summary>
43
/// Sets the navigation parameter value for the specified NavigationViewItem.
44
/// </summary>
45
/// <remarks>Use this method to attach contextual data to a NavigationViewItem, which can be accessed
46
/// during navigation events. This is useful for passing parameters between navigation targets in a
47
/// NavigationView.</remarks>
48
/// <param name="item">The NavigationViewItem for which to set the navigation parameter. Cannot be null.</param>
49
/// <param name="value">The value to associate with the navigation parameter. This value will be stored and can be retrieved when
50
/// navigating.</param>
14
51
public static void SetNavigateParameter(NavigationViewItem item, object value) => item.SetValue(NavigateParameterProperty, value);
15
52
53
/// <summary>
54
/// Identifies the NavigateParameter attached dependency property, which enables passing a navigation parameter to a
55
/// target element in XAML.
56
/// </summary>
57
/// <remarks>This property is typically used in navigation scenarios to associate additional data with a
58
/// UI element when initiating navigation. The value can be any object and is intended to be retrieved by navigation
59
/// logic or handlers. This property is commonly set in XAML using property element syntax.</remarks>
16
60
public static readonly DependencyProperty NavigateParameterProperty = DependencyProperty.RegisterAttached("NavigateParameter", typeof(object), typeof(NavigationAddition), new PropertyMetadata(null));
17
61
}
@@ -0,0 +1,36 @@
1
namespace XFEExtension.NetCore.WinUIHelper.Utilities.Additions;
2
3
/// <summary>
4
/// Provides an attached property for specifying the required permission level on UI elements.
5
/// </summary>
6
/// <remarks>The PermissionAddition class enables developers to associate a required permission value with any
7
/// UIElement using the RequiredPermission attached property. This can be used to control access or visibility of UI
8
/// elements based on user permissions in WPF applications.</remarks>
9
public class PermissionAddition
10
{
11
/// <summary>
12
/// Retrieves the required permission level associated with the specified UI element.
13
/// </summary>
14
/// <param name="item">The UI element from which to obtain the required permission level. Must not be null.</param>
15
/// <returns>An integer representing the required permission level for the specified UI element.</returns>
16
public static int GetRequiredPermission(UIElement item) => (int)item.GetValue(RequiredPermissionProperty);
17
/// <summary>
18
/// Sets the required permission value for the specified UI element.
19
/// </summary>
20
/// <remarks>This method attaches a permission value to the UI element using the RequiredPermission
21
/// attached property. Use this to control access or visibility based on permission levels in your
22
/// application.</remarks>
23
/// <param name="item">The UI element on which to set the required permission. Cannot be null.</param>
24
/// <param name="value">The permission value to assign to the UI element.</param>
25
public static void SetRequiredPermission(UIElement item, int value) => item.SetValue(RequiredPermissionProperty, value);
26
/// <summary>
27
/// Identifies the RequiredPermission attached dependency property, which specifies the required permission level
28
/// for a UI element.
29
/// </summary>
30
/// <remarks>This property can be attached to any DependencyObject to indicate the minimum permission
31
/// level necessary for interaction or visibility. It is typically used in scenarios where UI elements should be
32
/// enabled, visible, or accessible only to users with sufficient permissions. The default value is 0, representing
33
/// no required permission.</remarks>
34
35
public static readonly DependencyProperty RequiredPermissionProperty = DependencyProperty.RegisterAttached("RequiredPermission", typeof(int), typeof(PermissionAddition), new PropertyMetadata(0));
36
}
@@ -0,0 +1,136 @@
1
using System.Collections;
2
using System.Reflection;
3
4
namespace MultiPlatformTranslation.Core.Utilities.Helpers;
5
6
/// <summary>
7
/// 对象帮助类
8
/// </summary>
9
public static class ObjectHelper
10
{
11
/// <summary>
12
/// 判断对象及其子属性是否包含指定关键字
13
/// </summary>
14
public static bool Search(object obj, string keyword)
15
{
16
return SearchObject(obj, keyword, []);
17
}
18
19
private static bool SearchObject(object? obj, string keyword, HashSet<object> visited)
20
{
21
if (obj == null || visited.Contains(obj))
22
return false;
23
24
visited.Add(obj);
25
26
// string
27
if (obj is string str)
28
{
29
return str.Contains(keyword, StringComparison.OrdinalIgnoreCase);
30
}
31
32
// 集合
33
if (obj is IEnumerable enumerable && obj is not string)
34
{
35
foreach (var item in enumerable)
36
{
37
if (SearchObject(item, keyword, visited))
38
return true;
39
}
40
return false;
41
}
42
43
// 基础类型
44
if (obj.GetType().IsPrimitive || obj is decimal || obj is DateTime)
45
{
46
return obj.ToString()?.Contains(keyword, StringComparison.OrdinalIgnoreCase) == true;
47
}
48
49
// 复杂对象属性
50
foreach (var prop in obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
51
{
52
try
53
{
54
var value = prop.GetValue(obj);
55
if (SearchObject(value, keyword, visited))
56
return true;
57
}
58
catch { /* 忽略无法访问的属性 */ }
59
}
60
61
return false;
62
}
63
64
/// <summary>
65
/// 将 source 对象的值复制到 target 对象中,支持嵌套对象的递归复制
66
/// </summary>
67
/// <typeparam name="T"></typeparam>
68
/// <param name="source"></param>
69
/// <param name="target"></param>
70
public static void CopyValues<T>(this T source, T target)
71
{
72
if (source == null || target == null) return;
73
74
var type = typeof(T);
75
76
foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
77
{
78
if (!prop.CanRead || !prop.CanWrite) continue;
79
80
var value = prop.GetValue(source);
81
82
if (value == null)
83
{
84
prop.SetValue(target, null);
85
}
86
else if (prop.PropertyType.IsValueType || prop.PropertyType == typeof(string))
87
{
88
// 值类型和字符串直接赋值
89
prop.SetValue(target, value);
90
}
91
else
92
{
93
// 引用类型(子对象)
94
var targetValue = prop.GetValue(target);
95
if (targetValue == null)
96
{
97
targetValue = Activator.CreateInstance(prop.PropertyType);
98
prop.SetValue(target, targetValue);
99
}
100
101
// 递归复制
102
var method = typeof(ObjectHelper)
103
.GetMethod(nameof(CopyValues), BindingFlags.Static | BindingFlags.Public)!
104
.MakeGenericMethod(prop.PropertyType);
105
method.Invoke(null, [value, targetValue]);
106
}
107
}
108
109
foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.Instance))
110
{
111
var value = field.GetValue(source);
112
if (value == null)
113
{
114
field.SetValue(target, null);
115
}
116
else if (field.FieldType.IsValueType || field.FieldType == typeof(string))
117
{
118
field.SetValue(target, value);
119
}
120
else
121
{
122
var targetValue = field.GetValue(target);
123
if (targetValue == null)
124
{
125
targetValue = Activator.CreateInstance(field.FieldType);
126
field.SetValue(target, targetValue);
127
}
128
129
var method = typeof(ObjectHelper)
130
.GetMethod(nameof(CopyValues), BindingFlags.Static | BindingFlags.Public)!
131
.MakeGenericMethod(field.FieldType);
132
method.Invoke(null, [value, targetValue]);
133
}
134
}
135
}
136
}