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);
        }
    }
}

ここで、Menu を宣言してバインドする 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. 一部のコントロールは複数の役割で表示される場合があります (例: 開発者とビジネス アナリスト)

これまでの私の2つのオプション

  1. 許可されたロールに基づいて可視性を導出するロジックを持つカスタム コンバーターを作成し、それを MenuItem.Visibility Value プロパティにバインドします。これに関する問題: a) このコントロールに許可されたロールは、データベースから取得され、ロールのコレクションに CommandParameters をバインドできないため、実行時に渡す必要があります。b) 可視性を引き出すために、コンバーターは User.Role にどのようにアクセスできますか?
  2. UI モデル (MenuItemModel など) のプロパティ内に可視性ロジックを作成します。しかし、ここでは User クラスと MenuItemModel クラスの間に依存関係を作成したくありません。

密結合のシナリオ (依存関係) に遭遇することなく、User.Role に基づいて UI コントロールの可視性を動的に導出する最もクリーンな方法は何ですか?

ありがとう!

解決策:これが@fmunkertの提案に基づいて解決した方法です。「RemoveAll」メソッドにアクセスするには、MenuItemModel.Items プロパティを List に変更する必要があることに注意してください。

    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禁止された項目を再帰的に削除する my のメソッド:

    /// <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 に答える