MVVM Menu dinamico Interfaccia utente dall’associazione con ViewModel

Sono nuovo di WPF e MVVM. Sto lavorando con un team sull’applicazione LoB. Ci piacerebbe avere un controllo Menu dinamico, che crea il menu in base al profilo utente connesso. Negli scenari di sviluppo precedenti (ovvero ASP.NET), utilizziamo per scorrere i dati che descrivono la raccolta e generare MenuItem modo dinamico. In MVVM come farei questo? Posso separare la vista XAML da ViewModel che descrive gli elementi del menu?

Soluzione:

Con gli input dei commentatori sono riuscito a bind Menu modo dinamico con i dati di ViewModel. Anche questo articolo è stato di grande aiuto.

XAML:

    [...]      

Classe di dati del 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 } 

Prova qualcosa del genere:

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

Supponiamo che il tuo DataContext abbia una proprietà chiamata MenuItems che è un elenco di MenuItemViewModel. Qualcosa del genere dovrebbe funzionare, quindi:

            

Questo dovrebbe portarti dove stai andando

        

Nota che nel mio esempio, la mia voce di menu ha una proprietà di tipo ICommand chiamata Command.

Questa soluzione non richiede alcun codice nel codice e ciò rende la soluzione più semplice.

                    

E MenuItem è rappresentato come:

 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() { } } 

I MenuItem concreti possono essere istanziati direttamente oppure è ansible creare sottotipi personalizzati attraverso l’ereditarietà.

So che questo è un vecchio post, ma ho bisogno di questo oltre a come bind i comandi.

Per quanto riguarda la domanda di Guge su come associare i comandi: VMMenuItems è una proprietà nel mio tipo di class del modello di visualizzazione

 ObservableCollection 

e Menu è la class sopra definita. La proprietà Command di MenuItem è associata alla proprietà Command della class Menu. A mio modo di vedere la class del modello

 Menu.Command = _fou 

dove

 private ICommand _fou; 

Lo xaml

        

Se ti stai chiedendo come fare separatori è davvero abbastanza facile.

Il codice seguente è parte del mio ViewModel. Poiché XAML utilizza la reflection, tutto ciò che devo fare è restituire “object” che può essere un MenuItemViewModel , un Separator o (se per qualche motivo ho bisogno di farlo) un MenuItem effettivo.

Sto usando yield per generare dynamicmente gli articoli perché sembra leggere meglio per me. Anche se sto usando yield – se gli elementi cambiano, ho ancora bisogno di generare un evento PropertyChanged per "ContextMenu" come al solito, ma non genererò inutilmente l’elenco finché non sarà necessario.

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