I'm working on a C# desktop app and am looking for a way to programmatically highlight/select a MenuItem
, I came across this suggestion: https://stackoverflow.com/a/71115000/4247806
That looks ok, but my menu is populated by binding ItemsSource
to a list of ICommand
classes, and not explicitly in Xaml markup. So WPF creates the required MenuItem
instances behind-the-scenes. How can I make ContextMenu use my custom MenuItem class?
During previous work on a custom DataGrid
I stumbled across a GetContainerForItemOverride
method that the ContextMenu
class has as well. This lead me to this approach:
public class MyContextMenu : ContextMenu
{
protected override DependencyObject GetContainerForItemOverride()
{
return new MyMenuItem();
}
}
public class MyMenuItem : MenuItem
{
public MyMenuItem()
{
}
public new bool IsHighlighted
{
get => base.IsHighlighted;
set => base.IsHighlighted = value;
}
}
However, I would like to exactly mimick/imitate the original behavior, except that I need a MyMenuItem
instance. Looking at the implementation of ContextMenu.GetContainerForItemOverride
I've found this:
protected override DependencyObject GetContainerForItemOverride()
{
object currentItem = _currentItem;
_currentItem = null;
if (UsesItemContainerTemplate)
{
DataTemplate dataTemplate = ItemContainerTemplateSelector.SelectTemplate(currentItem, this);
if (dataTemplate != null)
{
object obj = dataTemplate.LoadContent();
if (obj is MenuItem || obj is Separator)
{
return obj as DependencyObject;
}
throw new InvalidOperationException(SR.Get("InvalidItemContainer", GetType().Name, typeof(MenuItem).Name, typeof(Separator).Name, obj));
}
}
return new MenuItem();
}
I can't reproduce this behavior due to the private object _currentItem
being used. If I ignore this, in which scenarios could this cause problems?
CodePudding user response:
If you look in the source code, you'll see that the private field _currentItem
is only used in two methods so you could easily replicate this code in your custom MyContextMenu
and simply change type from MenuItem
to MyMenuItem
if that's what you want:
private object _currentItem;
protected override bool IsItemItsOwnContainerOverride(object item)
{
bool ret = (item is MenuItem) || (item is Separator);
if (!ret)
{
_currentItem = item;
}
return ret;
}
protected override DependencyObject GetContainerForItemOverride()
{
object currentItem = _currentItem;
_currentItem = null;
if (UsesItemContainerTemplate)
{
DataTemplate itemContainerTemplate = ItemContainerTemplateSelector.SelectTemplate(currentItem, this);
if (itemContainerTemplate != null)
{
object itemContainer = itemContainerTemplate.LoadContent();
if (itemContainer is MenuItem || itemContainer is Separator)
{
return itemContainer as DependencyObject;
}
else
{
throw new InvalidOperationException(SR.Get(SRID.InvalidItemContainer, this.GetType().Name, typeof(MenuItem).Name, typeof(Separator).Name, itemContainer));
}
}
}
return new MenuItem();
}