Wpf - How to Create Menu and Submenus Using Binding

WPF - How can I create menu and submenus using binding

For me, it worked with this simple template:

<Menu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding Command}" />
</Style>
</Menu.ItemContainerStyle>
<Menu.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}" ItemsSource="{Binding Path=MenuItems}">
<TextBlock Text="{Binding Header}"/>
</HierarchicalDataTemplate>
</Menu.ItemTemplate>

Here is the complete example:

MainWindow.xaml:

<Window x:Class="WpfApplication14.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication14"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<Menu DockPanel.Dock="Top" ItemsSource="{Binding MenuItems}">
<Menu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Command" Value="{Binding Command}" />
</Style>
</Menu.ItemContainerStyle>
<Menu.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}" ItemsSource="{Binding Path=MenuItems}">
<TextBlock Text="{Binding Header}"/>
</HierarchicalDataTemplate>
</Menu.ItemTemplate>
</Menu>
<Grid>
</Grid>
</DockPanel>
</Window>

MainWindow.xaml.cs:

using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;

namespace WpfApplication14
{
public partial class MainWindow : Window
{
public ObservableCollection<MenuItemViewModel> MenuItems { get; set; }

public MainWindow()
{
InitializeComponent();

MenuItems = new ObservableCollection<MenuItemViewModel>
{
new MenuItemViewModel { Header = "Alpha" },
new MenuItemViewModel { Header = "Beta",
MenuItems = new ObservableCollection<MenuItemViewModel>
{
new MenuItemViewModel { Header = "Beta1" },
new MenuItemViewModel { Header = "Beta2",
MenuItems = new ObservableCollection<MenuItemViewModel>
{
new MenuItemViewModel { Header = "Beta1a" },
new MenuItemViewModel { Header = "Beta1b" },
new MenuItemViewModel { Header = "Beta1c" }
}
},
new MenuItemViewModel { Header = "Beta3" }
}
},
new MenuItemViewModel { Header = "Gamma" }
};

DataContext = this;
}
}

public class MenuItemViewModel
{
private readonly ICommand _command;

public MenuItemViewModel()
{
_command = new CommandViewModel(Execute);
}

public string Header { get; set; }

public ObservableCollection<MenuItemViewModel> MenuItems { get; set; }

public ICommand Command
{
get
{
return _command;
}
}

private void Execute()
{
// (NOTE: In a view model, you normally should not use MessageBox.Show()).
MessageBox.Show("Clicked at " + Header);
}
}

public class CommandViewModel : ICommand
{
private readonly Action _action;

public CommandViewModel(Action action)
{
_action = action;
}

public void Execute(object o)
{
_action();
}

public bool CanExecute(object o)
{
return true;
}

public event EventHandler CanExecuteChanged
{
add { }
remove { }
}
}
}

The resulting window looks like this:

screen shot

WPF Binding menu item with bounded Submenu

Don't add a MenuItem element in the ItemTemplate. There is a MenuItem element generated implicitly for each item in the ItemsSource. You should set the ItemTemplate to an HierarchicalDataTemplate.

Try this:

<Menu>
<Menu.Resources>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{Binding MenuItemCommand}" />
</Style>
</Menu.Resources>
<MenuItem Header="Minor Graph" ItemsSource="{Binding GraphMenuItems}">
<MenuItem.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding SubItems}">
<TextBlock Text="{Binding Header}" />
</HierarchicalDataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
</Menu>

wpf: Binding of nested Menu items

You could use this

<Menu>
<MenuItem Header="Select Source:"
ItemsSource="{Binding FirstViewModel.MenuItemsSecondLevel}">
<MenuItem.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:MySecondViewModel}"
ItemsSource="{Binding MenuItemsThirdLevel}">
<TextBlock Text="{Binding DisplayName}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:MyThirdViewModel}">
<CheckBox Content="{Binding DisplayName}" />
</DataTemplate>
</MenuItem.Resources>
</MenuItem>
</Menu>

Assuming FirstViewModel is a property of your viewmodel.

How to bind Menu items with observableCollection in xaml and wpf?

MenuItems have an ItemsSource property.

<Menu>
<MenuItem Header="Item Collection" ItemsSource="{Binding ItemCollection}">
<MenuItem.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding }"
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
</Menu>

See this question for a more complete answer.

Dynamic menus and submenus with Caliburn Micro, how can I bind the commands?

Add a setter to your Style that sets the cal:Message.Attach attached property and passes the $executionContext:

<Menu x:Name="ToolBarMenuItems">
<Menu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding Path=Text}" />
<Setter Property="ItemsSource" Value="{Binding Path=Children}" />
<Setter Property="cal:Message.Attach" Value="RunCommand($executionContext)" />
</Style>
</Menu.ItemContainerStyle>
</Menu>

You need the context in your interface and implementation to be able to stop the event from bubbeling:

public void RunCommand(ActionExecutionContext context)
{
if (context?.EventArgs is RoutedEventArgs routedEventArgs)
routedEventArgs.Handled = true;

MessageBox.Show("Run!");
}

Please refer to this question for more information about this.

XAML and Binding Submenu items in a ContextMenu?

Guess I should have experimented more. Turns out this was relatively simple:

<my:DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Add to" ItemsSource="{Binding MyItems}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem CommandTarget="{Binding}" Click="AddClick">
<MenuItem.Header>
<TextBlock>
<TextBlock.Text><Binding StringFormat="Add to {0}" /></TextBlock.Text>
</TextBlock>
</MenuItem.Header>
</MenuItem>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
<MenuItem Header="Remove from All" />
</ContextMenu>
</my:DataGrid.ContextMenu>

How to properly create a sub-menu for a menu item in WPF

Unless you're a XAML ninja, the best way to work with any template is to start by extracting the default template.

Because it is very very easy to totally break controls when you start doing this sort of stuff. A template totally utterly replaces everything that makes up your control. In particular, be very careful to ensure any contentpresenter or named part is still in there once you finish.

Step by step:

Add a control of the type you want (menuitem) to a view.

Select it.

Over in the properties window find the Miscellaneous group.

Scroll down to template.

Click the little box on the right.

Choose Convert to new resource.

You can find you need to add references to stuff for some templates.

In any case, ensure that works.

You are now starting with a working template ( rather than a broken one ).

Make a small change and test.

Repeat.

Creep up on your requirement by a teeny tiny baby step at a time.

Also.

Rather than defining menuitems in code, template them out from a bound hierarchical collection.



Related Topics



Leave a reply



Submit