2012-05-18 69 views
0

這更多的是MVVM應用程序設計問題。我試圖實現一個非常基本的基於用戶的權限管理,其中我的應用程序中某些控件的可見性來自當前用戶角色。這裏我簡單的模型:MVVM UI控件依賴用戶使用WPF可見性

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. 創建一個自定義的轉換器,該轉換器具有根據允許的角色派生Visibility並將其綁定到MenuItem.Visibility Value屬性的邏輯。問題在於:a)允許此控件的角色需要在運行時傳遞,因爲它們來自數據庫,並且不能將CommandParameters綁定到角色集合。 b)轉換器如何訪問User.Role以獲取可見性?
  2. 在我的UI模型(例如MenuItemModel)中創建屬性內的可見性邏輯。但在這裏我不想創建我的用戶和MenuItemModel類之間的依賴關係。

什麼是最簡潔的方式來派生UI控件基於User.Role動態可見性沒有運行到緊耦合方案(依賴)?

謝謝!

解決方案:所以這就是我最終如何根據@fmunkert的建議來解決它。請注意,我不得不改變MenuItemModel.Items屬性,以訪問「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

由於您正在ViewModel中生成菜單項,我建議完全不使用MenuItem.Visibility。相反,請讓您的ViewModel確定允許用戶查看哪些菜單項,並僅使用菜單項的子集填充MainMenu集合。即您的MainViewModel必須知道用戶可以看到哪些菜單項。

I.e.,你可以使用這樣的事情在你的MainViewModel的構造函數:

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

有趣的想法@fmunkert,我從來沒有想過這樣的說法,但非常有意義。讓我們看看我得到的其他建議,但到目前爲止,這可能是潛在的答案。謝謝你的幫助 –