0

这更像是一个 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>

现在这里是我的要求:

  1. 某些 UI 控件(例如 MenuItems)的可见性取决于 User.Role。例如:MenuItemA 应该对 Role.Developer 可见,但对 Role.BusinessAnalyst 不可见
  2. 某些控件可能对多个角色可见(例如开发人员和业务分析师)

到目前为止我的两个选择

  1. 创建一个自定义转换器,该转换器具有根据允许的角色派生可见性的逻辑并将其绑定到 MenuItem.Visibility 值属性。这样做的问题: a) 允许此控件的角色需要在运行时传递,因为它们来自数据库,并且您不能将 CommandParameters 绑定到角色集合。b) 转换器如何访问 User.Role 以获取可见性?
  2. 在我的 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);
    }

这似乎工作正常

4

1 回答 1

4

由于您在 ViewModel 中生成菜单项,我建议根本不要使用MenuItem.Visibility。相反,让您的 ViewModel 确定允许用户查看哪些菜单项,并仅使用该菜单项子集填充 MainMenu 集合。即您的 MainViewModel 必须知道允许用户查看哪些菜单项。

即,您将在 MainViewModel 的构造函数中使用类似的内容:

_MainMenu = new ObservableCollection<MenuItemModel>(_allMenuItems.Select(m => IsVisibleToUser(m)));
于 2012-05-18T13:56:18.183 回答