Given the following code:
<MenuItem x:Name="MenuItem_Root" Header="Root">
<MenuItem x:Name="MenuItem_Item1" IsCheckable="True" Header="item1" />
<MenuItem x:Name="MenuItem_Item2" IsCheckable="True" Header="item2"/>
<MenuItem x:Name="MenuItem_Item3" IsCheckable="True" Header="item3"/>
</MenuItem>
In XAML, is there a way to create checkable menuitem's that are mutually exclusive? Where is the user checks item2, item's 1 and 3 are automatically unchecked.
I can accomplish this in the code behind by monitoring the click events on the menu, determining which item was checked, and unchecking the other menuitems. I'm thinking there is an easier way.
Any ideas?
I find that I get mutually exclusive menu items when binding MenuItem.IsChecked to a variable.
But it has one quirk: If you click the selected menu item, it gets invalid, shown by the usual red rectangle. I solved it by adding a handler for MenuItem.Click that prevents unselecting by just setting IsChecked back to true.
The code... I'm binding to an enum type, so I use an enum converter that returns true if the bound property is equal to the supplied parameter. Here is the XAML:
And here is the code behind:
Several years after i see this post with the keywords i wrote... i thought there was an easy solution, in wpf... Perhaps it's me, but i think it's a bit special to have a such massive arsenal for a so little thing as accepted solution. I don't even talk about the solution with 6likes i didn't understood where to click to have this options.
So perhaps it's really no elegant at all... But here a simple solution. What it do is simple.. a loop to all elements contained by the parent, to put it at false. The most of time people split this part from the others parts, of course it's only correct in this case.
that's all and easy, xaml is a classic code with absolutaly nothing particular
Of course you could have a need of the click method, it's not a problem, you can make a method that accept an object sender and each of your click method will use this method. It's old, it's ugly but for the while it works. And i have some problems to imagine so much code line for a so little thing, it's probably me that have a problem with xaml, but it seems incredible to have to do this to obtains to just have only one menuitem selected.
Adding this at the bottom since I don't have the reputation yet...
As helpful as Patrick's answer is, it doesn't ensure that items cannot be unchecked. In order to do that, the Checked handler should be changed to a Click handler, and changed to the following:
Yes, this can be done easily by making every MenuItem a RadioButton. This can be done by Editing Template of MenuItem.
Right-Click the MenuItem in the Document-Outline left pane > EditTemplate > EditCopy. This will add the code for editing under Window.Resources.
Now, you have to do only two-changes which are very simple.
a. Add the RadioButton with some Resources to hide its circle portion.
b. Change BorderThickness = 0 for MenuItem Border part.
These changes are shown below as comments, rest of the generated style should be used as is :
Apply the Style ,
A small addition to the @Patrick answer.
As @MK10 mentioned, this solution allows user to deselect all items in a group. But the changes he suggested doesn't work for me now. Maybe, the WPF model was changed since that time, but now
Checked
event doesn't fired when an item is unchecked.To avoid it, I would suggest to process the
Unchecked
event forMenuItem
.I changed these procedures:
and added the next handler:
Now the checked item remains checked when user clicks it second time.
Here is yet another way – not easy by any stretch but it is MVVM compatible, bindable and highly unit testable. If you have the freedom to add a Converter to your project and don’t mind a little garbage in the form of a new list of items every time the context menu opens, this works really well. It meets the original question of how to provide a mutually exclusive set of checked items in a context menu.
I think if you want to extract all of this into a user control you could make it into a reusable library component to reuse across your application. Components used are Type3.Xaml with a simple grid, one text block and the context menu. Right-click anywhere in the grid to make the menu appear.
A value converter named AllValuesEqualToBooleanConverter is used to compare each menu item’s value to the current value of the group and show the checkmark next to the menu item that is currently selected.
A simple class that represent your menu choices is used for illustration. The sample container uses Tuple with String and Integer properties that make is fairly easy to have a tightly coupled human readable snippet of text paired with a machine-friendly value. You can use strings alone or String and an Enum to keep track of the Value for making decisions over what is current. Type3VM.cs is the ViewModel that is assigned to the DataContext for Type3.Xaml. However you contrive to assign your data context in your existing application framework, use the same mechanism here. The application framework in use relies on INotifyPropertyChanged to communicate changed values to WPF and its binding goo. If you have dependency properties you may need to tweak the code a little bit.
The drawback to this implementation, aside from the converter and its length, is that a garbage list is created every time the context menu is opened. For single user applications this is probably ok but you should be aware of it.
The application uses an implementation of RelayCommand that is readily available from the Haacked website or any other ICommand-compatible helper class available in whatever framework you are using.