这更像是一个 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;
}
}
}
我的 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.Visibility 值属性。这样做的问题: a) 允许此控件的角色需要在运行时传递,因为它们来自数据库,并且您不能将 CommandParameters 绑定到角色集合。b) 转换器如何访问 User.Role 以获取可见性?
- 在我的 UI 模型(例如 MenuItemModel)的属性中创建可见性逻辑。但是在这里我不想在我的 User 和 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);
}
这似乎工作正常