c# - MVVM UI 使用 WPF 控制用户依赖的可见性

标签 c# wpf mvvm menuitem

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

这是我声明和绑定(bind)菜单的 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 不可见
  • 某些控件可能对多个角色可见(例如开发人员和业务分析师)

  • 到目前为止我的两个选择
  • 创建一个自定义转换器,该转换器具有根据允许的角色派生可见性的逻辑并将其绑定(bind)到 MenuItem.Visibility 值属性。这样做的问题: a) 允许此控件的角色需要在运行时传递,因为它们来自数据库,并且您不能将 CommandParameters 绑定(bind)到角色集合。 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);
        }
    

    这似乎工作正常

    最佳答案

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

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

    _MainMenu = new ObservableCollection<MenuItemModel>(_allMenuItems.Select(m => IsVisibleToUser(m)));
    

    关于c# - MVVM UI 使用 WPF 控制用户依赖的可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10653758/

    相关文章:

    c# - 开始事务时出现 SqlServer.Management.SMO.Server 错误

    c# - Winform 图表控件未创建正确的折线图

    c# - 如何在 LINQ 中对 2 个不同的序列进行分组?

    c# - 我应该在 WPF 中的哪个页面声明带有自定义控件的绑定(bind)选项

    wpf - 在 WPF 数据网格中使行不可聚焦

    html - 在剑道网格中解析日期 - mvvm 绑定(bind)

    c# - Java/C#类型系统有哪些不足?

    c# - 大型 RegEx 匹配导致程序挂起

    java - 无法从外部包访问

    c# - 使用 MVVM 在组合框中设置默认值