MVVM UI 控件依赖于用户与 WPF 的可见性
本文关键字:WPF 可见性 用户 UI 控件 依赖于 MVVM | 更新日期: 2023-09-27 18:34:31
这更像是一个MVVM应用程序设计问题。我正在尝试实现一个非常基本的基于用户的权限管理,其中应用程序中某些控件的可见性派生自当前用户角色。这是我的简化模型:
public class User
{
public string UserName {get;set;}
public Role UserRole {get;set;}
}
public enum Role
{
Developer,
BusinessAnalyst
}
public class MenuItemModel
{
public ICommand Command {get;set;}
public string Header {get;set;}
public bool Visible {get;set;}
private List<MenuItemModel> _Items;
public List<MenuItemModel> Items
{
get { return _Items ?? (_Items = new List<MenuItemModel>()); }
set
{
_Items = value;
}
}
}
My MainViewModel 包含以下属性:
public class MainViewModel : ViewModelBase<MainViewModel>
{
private ObservableCollection<MenuItemModel> _MainMenu;
public ObservableCollection<MenuItemModel> MainMenu
{
get { return _MainMenu; }
set
{
_MainMenu = value;
NotifyPropertyChanged(x=>x.MainMenu);
}
}
private User _CurrentUser;
public User CurrentUser
{
get { return _CurrentUser; }
set {
_CurrentUser = value;
NotifyPropertyChanged(x=>x.CurrentUser);
}
}
}
这是我的 XAML,我在其中声明并绑定我的菜单:
<Menu DockPanel.Dock="Top" ItemsSource="{Binding Path=MainMenu}">
<Menu.ItemContainerStyle>
<Style>
<Setter Property="MenuItem.Header" Value="{Binding Path=Header}"/>
<Setter Property="MenuItem.ItemsSource" Value="{Binding Path=Items}"/>
<!-- How to bind Visibility????-->
<!--Setter Property="MenuItem.Visibility" /-->
</Style>
</Menu.ItemContainerStyle>
</Menu>
现在我的要求在这里:
- 某些 UI 控件(例如 MenuItems(的可见性取决于 User.Role。例如:MenuItemA 应该对 Role.Developer 可见,但对 Role.BusinessAnalyst 不可见。
- 某些控件可能对多个角色可见(例如开发人员和业务分析师(
到目前为止我的两个选择
- 创建一个自定义转换器,该转换器具有基于允许的角色派生可见性的逻辑,并将其绑定到 MenuItem.可见性值属性。这样做的问题:a(此控件允许的角色需要在运行时传递,因为它们来自数据库,并且您无法将命令参数绑定到角色集合。b(转换器如何访问User.Role以获得可见性?
- 在我的 UI 模型(例如 MenuItemModel(中的属性中创建可见性逻辑。但在这里,我不想在我的用户和 MenuItemModel 类之间创建依赖关系。
User.Role 动态派生 UI 控件可见性而不会遇到紧密耦合的方案(依赖项(的最干净方法是什么?
谢谢!
解决方案:这就是我根据@fmunkert建议最终解决它的方式。请注意,我必须将 MenuItemModel.Items 属性更改为 List 才能访问"RemoveAll"方法:
public MainViewModel()
{
//Create a new User with a Role
InitializeUser();
//Get all the Menus in the application
List<MenuItemModel> allItems = GetAllMenus();
//Remove recursively all Items that should not be visible for this user
allItems.RemoveAll(x=>!IsVisibleToUser(x));
//Set my MainMenu based on the filtered Menu list
_MainMenu = new ObservableCollection<MenuItemModel>(allItems);
}
private void InitializeUser()
{
CurrentUser = new User {UserName = "apsolis", UserRole = Role.Developer};
}
这是我MainViewModel
中递归删除禁止项目的方法:
/// <summary>
/// Method to check if current MenuItem is visible to user
/// and remove items that are forbidden to this user
/// </summary>
/// <param name="m"></param>
/// <returns></returns>
public bool IsVisibleToUser(MenuItemModel m)
{
if (m.Items != null && m.Items.Count > 0)
{
m.Items.RemoveAll(y=>!IsVisibleToUser(y));
}
return m.Roles == null || m.Roles.Contains(CurrentUser.UserRole);
}
这似乎工作正常
由于您是在 ViewModel 中生成菜单项,因此我建议根本不使用MenuItem.Visibility
。相反,请让 ViewModel 确定允许用户查看哪些菜单项,并仅使用该菜单项子集填充 MainMenu 集合。即您的 MainViewModel 必须知道允许用户查看哪些菜单项。
也就是说,您将在 MainViewModel 的构造函数中使用类似的东西:
_MainMenu = new ObservableCollection<MenuItemModel>(_allMenuItems.Select(m => IsVisibleToUser(m)));