MVVM Dynamic Menu UI from binding with ViewModel MVVM Dynamic Menu UI from binding with ViewModel wpf wpf

MVVM Dynamic Menu UI from binding with ViewModel


Try something like this:

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

Assume that your DataContext has a property called MenuItems which is a list of MenuItemViewModel. Something like this should work, then:

<Window x:Class="WpfApplication1.Window1"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        xmlns:self="clr-namespace:WpfApplication1"        Title="Window1" Height="300" Width="300">    <Window.Resources>        <HierarchicalDataTemplate DataType="{x:Type self:MenuItemViewModel}"                                  ItemsSource="{Binding Path=MenuItems}">            <ContentPresenter Content="{Binding Path=Text}" />        </HierarchicalDataTemplate>    </Window.Resources>    <DockPanel>        <Menu DockPanel.Dock="Top" ItemsSource="{Binding Path=MenuItems}" />        <Grid />    </DockPanel></Window>


This should get you where you are going

<UserControl x:Class="WindowsUI.Views.Default.MenuView"         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"          xmlns:d="http://schemas.microsoft.com/expression/blend/2008"          xmlns:ViewModels="clr-namespace:WindowsUI.ViewModels"         mc:Ignorable="d"          d:DesignHeight="300" d:DesignWidth="300"><UserControl.Resources>    <Style TargetType="{x:Type MenuItem}">        <Setter Property="Header" Value="{Binding Path=DisplayName}"/>        <Setter Property="Command" Value="{Binding Path=Command}"/>    </Style>    <HierarchicalDataTemplate         DataType="{x:Type ViewModels:MenuItemViewModel}"        ItemsSource="{Binding Path=Items}">    </HierarchicalDataTemplate></UserControl.Resources><Menu DockPanel.Dock="Top" ItemsSource="{Binding Path=Items}"/>

Note that in my example, my menu Item has a property of type ICommand called Command.


This solution doesn't need any code in code behind and that makes it simpler solution.

        <Menu>            <MenuItem ItemsSource="{Binding Path=ChildMenuItems}" Header="{Binding Path=Header}">                <MenuItem.Resources>                    <HierarchicalDataTemplate DataType="{x:Type vm:MenuItemViewModel}" ItemsSource="{Binding ChildMenuItems}">                        <MenuItem Header="{Binding Path=Header}" Command="{Binding Path=Command}"/>                    </HierarchicalDataTemplate>                    <DataTemplate DataType="{x:Type vm:SeparatorViewModel}">                        <Separator>                            <Separator.Template>                                <ControlTemplate>                                    <Line X1="0" X2="1" Stroke="Black" StrokeThickness="1" Stretch="Fill"/>                                </ControlTemplate>                            </Separator.Template>                        </Separator>                    </DataTemplate>                </MenuItem.Resources>            </MenuItem>        </Menu>

And MenuItem is represented as:

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

The concrete MenuItems can be either instantiated directly or you could make your own SubTypes through inheritance.