Interface do Menu Dinâmico do MVVM da binding com o ViewModel

Eu sou novo no WPF e no MVVM. Eu estou trabalhando com uma equipe no aplicativo LoB. Gostaríamos de ter um controle de Menu dynamic, que cria o menu com base no perfil do usuário conectado. Em cenários de desenvolvimento anteriores (ou seja, ASP.NET), usamos para iterar dados que descrevem a coleção e geram MenuItem dinamicamente. No MVVM como eu faria isso? Posso separar a visualização XAML do ViewModel, que descreve os elementos do menu?

Solução:

Com as inputs dos comentaristas, consegui vincular o Menu dinamicamente com os dados do ViewModel. Este artigo foi de grande ajuda também.

XAML:

    [...]      

Classe de dados do Menu :

 public class Menu : ViewModelBase { public Menu() { IsEnabled = true; Children = new List(); } #region [ Menu Properties ] private bool _isEnabled; private string _menuText; private ICommand _command; private IList _children; public string MenuText { get { return _menuText; } set { _menuText = value; base.OnPropertyChanged("MenuText"); } } public bool IsEnabled { get { return _isEnabled; } set { _isEnabled = value; base.OnPropertyChanged("IsEnabled"); } } public ICommand Command { get { return _command; } set { _command = value; base.OnPropertyChanged("Command"); } } public IList Children { get { return _children; } set { _children = value; } } #endregion } 

Tente algo assim:

 public class MenuItemViewModel { public MenuItemViewModel() { this.MenuItems = new List(); } public string Text { get; set; } public IList MenuItems { get; private set; } } 

Suponha que seu DataContext tenha uma propriedade chamada MenuItems, que é uma lista de MenuItemViewModel. Algo como isso deve funcionar, então:

            

Isso deve te levar aonde você está indo

        

Note que no meu exemplo, meu menu Item possui uma propriedade do tipo ICommand chamada Command.

Esta solução não precisa de nenhum código no código por trás e isso torna a solução mais simples.

                    

E MenuItem é representado como:

 public class MenuItemViewModel : BaseViewModel { ///  /// Initializes a new instance of the  class. ///  /// The parent view model. public MenuItemViewModel(MenuItemViewModel parentViewModel) { ParentViewModel = parentViewModel; _childMenuItems = new ObservableCollection(); } private ObservableCollection _childMenuItems; ///  /// Gets the child menu items. ///  /// The child menu items. public ObservableCollection ChildMenuItems { get { return _childMenuItems; } } private string _header; ///  /// Gets or sets the header. ///  /// The header. public string Header { get { return _header; } set { _header = value; NotifyOnPropertyChanged("Header"); } } ///  /// Gets or sets the parent view model. ///  /// The parent view model. public MenuItemViewModel ParentViewModel { get; set; } public virtual void LoadChildMenuItems() { } } 

Os MenuItems concretos podem ser instanciados diretamente ou você pode criar seus próprios Subtipos por inheritance.

Eu sei que este é um post antigo, mas eu preciso disso, mais como vincular comandos.

Quanto à pergunta de Guge sobre como vincular comandos: VMMenuItems é uma propriedade em minha class de modelo de modo de exibição

 ObservableCollection 

e Menu é a class definida acima. Propriedade de comando do MenuItem está sendo vinculada a propriedade de comando da class Menu. Na minha opinião, class de modelo

 Menu.Command = _fou 

Onde

 private ICommand _fou; 

O xaml

        

Se você está se perguntando como separadores é realmente muito fácil.

O código abaixo é parte do meu ViewModel. Como o XAML usa a reflection, tudo que preciso fazer é retornar ‘object’, que pode ser um MenuItemViewModel , Separator ou (se por algum motivo estranho eu precisei) um MenuItem real.

Eu estou usando o yield para gerar dinamicamente os itens, porque parece ler melhor para mim. Mesmo que eu esteja usando o yield – se os itens mudarem, eu ainda preciso levantar um evento PropertyChanged para "ContextMenu" como de costume, mas eu não gero a lista desnecessariamente até que seja necessário.

  public IEnumerable ContextMenu { get { // ToArray() needed or else they get garbage collected return GetContextMenu().ToArray(); } } public IEnumerable GetContextMenu() { yield return new MenuItemViewModel() { Text = "Clear all flags", }; // adds a normal 'Separator' menuitem yield return new Separator(); yield return new MenuItemViewModel() { Text = "High Priority" }; yield return new MenuItemViewModel() { Text = "Medium Priority" }; yield return new MenuItemViewModel() { Text = "Low Priority" }; yield break; }