I try to get MenuItem from ContextMenu. If I open context menu at least once it works fine, otherwise I get error ItemCollection has no inner collection. As I understand this behavior is caused by ItemSource binding. How can I load Items without manual open context menu?
XAML:
<StackPanel>
<Rectangle Fill="Red" Height="100" Width="100">
<Rectangle.ContextMenu>
<ContextMenu x:Name="MainContextMenu" ItemsSource="{Binding Items}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding}"/>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Rectangle.ContextMenu>
</Rectangle>
<Button Content="Click" Command="{Binding GetMenuItemCommand}"
CommandParameter="{Binding ElementName=MainContextMenu}"
Height="30" Width="100"/>
</StackPanel>
ViewModel:
public class ViewModel
{
public List<string> Items { get; }
public MyCommand GetMenuItemCommand { get; }
public ViewModel()
{
Items = new List<string>()
{
"a0", "a1", "a2", "a3", "a4", "a5"
};
GetMenuItemCommand = new MyCommand(GetMenuItem);
}
public void GetMenuItem(object obj)
{
var contextMenu = (ContextMenu)obj;
// Here I get exception
var item = contextMenu.Items[0] as MenuItem;
var header = item.Header
}
}
MyCommand
public class MyCommand : ICommand
{
private Action<object> execute;
public MyCommand(Action<object> execute)
{
this.execute = execute;
}
public event EventHandler? CanExecuteChanged;
public bool CanExecute(object? parameter) => true;
public void Execute(object? parameter)
{
execute?.Invoke(parameter);
}
}
NOTE: It is demo code, I'm not following MVVM approach here
EDIT: Full exception message: System.InvalidOperationException: 'Operation is not valid while ItemCollection has no inner collection. ItemCollection is uninitialized or binding on ItemsControl.ItemSource supplied null for collection.'
EDIT 2: As people mentioned in the comments, probably purpose of getting MenuItem is not clear, so I introduce more details.
I'm trying to write helper class, that will merge child context menu with parent menu if needed. I do not know anything about context menus I will merge. I am currently trying to copy elements from parent menu and add them to child menu, when child menu is opening. For that reason I need to create new MenuItem, copy properties from parent's MenuItem and add this new MenuItem to child's context menu. My solution works fine, but only when parent menu was opened at least once.
I already asked straight question about merging context menus, but got no appropriate answers, so there I tried to ask something different.
CodePudding user response:
There is no MenuItem
until the ContextMenu
has been opened. And passing a ContextMenu
to a view model breaks the MVVM pattern.
You should get the underlying data value from the source collection instead of trying to access the eventually created visual element. The MVVM version of your code looks something like this:
public void GetMenuItem(object _)
{
var item = Items[0];
...
}
Obviously a view model cannot create additional MenuItem
elements. It may add more strings
to the source collection though.