Mix dynamic and static XAML menu items

I have a scenario in which I need to have both static and dynamic menu items. Static elements will be defined in XAML and dynamic elements supplied by the view model. Each dynamic element will itself be represented by a VieModel, let's call it CommandViewModel. CommandViewModel has, among other things, a display name, it may also contain other CommandViewModels.

MainViewModel, which is used as the datacontext for the menu, looks like this:

public class MainMenuViewModel : INotifyPropertyChanged
{

  private ObservableCollection<CommandViewModel> m_CommandVMList;


  public MainMenuViewModel()
  {
    m_ CommandVMList = new ObservableCollection<CommandViewModel>();

    CommandViewModel cmv = new CommandViewModel();
    cmv.DisplayName = "Dynamic Menu 1";
    m_CommandVMList.Add(cmv);

    cmv = new CommandViewModel();
    cmv.DisplayName = "Dynamic Menu 2";
    m_CommandVMList.Add(cmv);

    cmv = new CommandViewModel();
    cmv.DisplayName = "Dynamic Menu 3";
    m_CommandVMList.Add(cmv);

  }

  public ObservableCollection<CommandViewModel> CommandList
  {
    get { return m_CommandVMList; }
    set
    {
      m_CommandVMList = value;
      OnPropertyChanged("CommandList");
    }
  }

... ... ...

XAML menu:

<Grid>
  <Grid.Resources>
    <HierarchicalDataTemplate DataType="{x:Type Fwf:CommandViewModel}" ItemsSource="{Binding Path=CommandViewModels}">
      <MenuItem Header="{Binding Path=DisplayName}"/>
    </HierarchicalDataTemplate>
  </Grid.Resources>

  <Menu VerticalAlignment="Top" HorizontalAlignment="Stretch">
    <MenuItem Header="Static Top Menu Item 1">
      <MenuItem Header="Static Menu Item 1"/>
        <MenuItem Header="Static Menu Item 2"/>
        <MenuItem Header="Static Menu Item 3"/>
        <ItemsControl ItemsSource="{Binding Path= CommandList}"/>
        <MenuItem Header="Static Menu Item 4"/>
      </MenuItem>
  </Menu>
</Grid>

, , , ItemsControl , , . , , . , , , , , . , ?

+5
1

"" XAML VM CommandViewModel.

, , , HierarchicalDataTemplate, - .

, , . .

EDIT:

, (, INotifyPropertyChanged), , . , , , DataTemplate .

XAML

<Window
    x:Class="WPFDynamicMenuItems.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPFDynamicMenuItems"
    Title="Window1" Height="300" Width="600">
    <Grid>
        <Grid.Resources>
            <HierarchicalDataTemplate DataType="{x:Type local:CommandViewModel}" ItemsSource="{Binding Path=CommandList}">
                <ContentPresenter
                    Content="{Binding Path=DisplayName}"
                    RecognizesAccessKey="True" />
            </HierarchicalDataTemplate>
        </Grid.Resources>
        <ToolBarTray>
            <ToolBar>
            <Menu>
                <Menu.ItemsSource>
                    <CompositeCollection>
                        <MenuItem Header="A"></MenuItem>
                        <MenuItem Header="B"></MenuItem>
                        <MenuItem Header="C"></MenuItem>

                        <CollectionContainer x:Name="dynamicMenuItems">
                        </CollectionContainer>

                        <MenuItem Header="D"></MenuItem>

                    </CompositeCollection>
                </Menu.ItemsSource>

            </Menu>
                </ToolBar>
        </ToolBarTray>
    </Grid>
</Window>

-:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;

namespace WPFDynamicMenuItems
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private MainMenuViewModel _mainMenuVM = new MainMenuViewModel();

        public Window1()
        {
            InitializeComponent();

            this.dynamicMenuItems.Collection = this._mainMenuVM.CommandList;
        }
    }


    public class MainMenuViewModel : INotifyPropertyChanged
    {
        private ObservableCollection<CommandViewModel> m_CommandVMList;

        public MainMenuViewModel()
        {
            m_CommandVMList = new ObservableCollection<CommandViewModel>();
            CommandViewModel cmv = new CommandViewModel();
            cmv.DisplayName = "Dynamic Menu 1";
            m_CommandVMList.Add(cmv);
            cmv = new CommandViewModel();
            cmv.DisplayName = "Dynamic Menu 2";
            m_CommandVMList.Add(cmv);
            cmv = new CommandViewModel();
            cmv.DisplayName = "Dynamic Menu 3";
            m_CommandVMList.Add(cmv);

            CommandViewModel nestedCMV = new CommandViewModel();
            nestedCMV.DisplayName = "Nested Menu 1";
            cmv.CommandList.Add(nestedCMV);

            nestedCMV = new CommandViewModel();
            nestedCMV.DisplayName = "Nested Menu 2";
            cmv.CommandList.Add(nestedCMV);
        }
        public ObservableCollection<CommandViewModel> CommandList
        {
            get { return m_CommandVMList; }
            set { m_CommandVMList = value; OnPropertyChanged("CommandList"); }
        }

        protected void OnPropertyChanged(string propertyName)
        {
            //  Hook up event...
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }

    public class CommandViewModel : INotifyPropertyChanged
    {
        private ObservableCollection<CommandViewModel> m_CommandVMList;

        public CommandViewModel()
        {
            this.m_CommandVMList = new ObservableCollection<CommandViewModel>();
        }

        public string DisplayName { get; set; }

        public ObservableCollection<CommandViewModel> CommandList
        {
            get { return m_CommandVMList; }
            set { m_CommandVMList = value; OnPropertyChanged("CommandList"); }
        }

        protected void OnPropertyChanged(string propertyName)
        {
            //  Hook up event...
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}
+5

All Articles