Вы можете сделать это, не используя событие Click или что-либо замысловатое.
Проблема в том, что у вашей Команды есть один DataContext (ViewModel), а у элемента есть другой. Таким образом, есть два варианта: либо поместить команду на элементы в ItemsSource (более гибкую, поскольку они могут иметь разные команды), либо выполнить привязку RelativeSource обратно к представлению, получить ViewModel через view.DataContext и получить команду из тот. Это избавит вас от лишних хлопот, передавая команду всем этим элементам данных.
Обратите внимание, что, поскольку мы делаем это с помощью стиля, мы будем привязывать одну и ту же команду к каждому элементу меню, если получим команду из некоторого DataContext, который является общим для всех пунктов меню с похожим стилем. Но так как мы сами генерируем элементы из списка похожих элементов данных, это, вероятно, то, что вы хотите. Если нет, поместите команды в элементы данных.
Если элементы в вашем ItemsSource имеют команду, это открытое свойство элемента данных, которое можно легко привязать к MenuItem.Command
в вашем ItemContainerStyle
. Больше C #, меньше XAML.
Это дает дополнительное преимущество - одинаково хорошо работает только с одним локализованным подменю в большой системе меню, где другие пункты меню определяются обычным способом. Вот частичная реализация списка MRU. Вы можете очень легко сделать то же самое для других аналогичных подменю - или с очень небольшим количеством дальнейшей работы, всего дерева главного меню.
Для простоты я предполагаю, что у проекта есть одно пространство имен, которое в XAML определено как local
, и что этот XAML находится в представлении, называемом MainWindow.
Оба они были протестированы в полной реализации, но то, что ниже, не является полным: ради управляемого ответа SO, оно сокращено до почти минимума, чтобы XAML имел смысл. Я закончил тем, что использовал версию RelativeSource AncestorType
, потому что она немного проще, и мне не нужно давать некоторым элементам списка другие команды, но я оставил другую версию закомментированной.
<Window.Resources>
<!-- ... -->
<DataTemplate DataType="{x:Type local:MRUListItem}" >
<Label Content="{Binding HeaderText}" />
</DataTemplate>
<!-- ... -->
</Window.Resources>
<!-- ... -->
<Menu>
<MenuItem Header="_File">
<MenuItem Header="_Save File"
Command="{Binding SaveFileCommand}" />
<!-- ... -->
<!-- etc. -->
<!-- ... -->
<MenuItem Header="_Recent Files"
ItemsSource="{Binding MRUList}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command"
Value="{Binding FileOpenCommand}" />
<Setter Property="CommandParameter"
Value="{Binding FileName}" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
<!-- etc. -->
</MenuItem>
<!-- ... -->
</Menu>
Альтернативная версия RelativeSource, получение команды прямо из ViewModel в XAML:
<!--
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command"
Value="{Binding RelativeSource={RelativeSource
AncestorType={x:Type local:MainWindow}},
Path=DataContext.MRUFileOpenCommand}" />
<Setter Property="CommandParameter"
Value="{Binding FileName}" />
</Style>
</MenuItem.ItemContainerStyle>
-->
C #
public class MRUList : ObservableCollection<MRUListItem>
{
// The owning ViewModel provides us with his FileOpenCommand
// initially.
public MRUList(ICommand fileOpenCommand)
{
FileOpenCommand = fileOpenCommand;
CollectionChanged += CollectionChangedHandler;
}
public ICommand FileOpenCommand { get; protected set; }
// Methods to renumber and prune when items are added,
// remove duplicates when existing item is re-added,
// and to assign FileOpenCommand to each new MRUListItem.
// etc. etc. etc.
}
public class MRUListItem : INotifyPropertyChanged
{
public ICommand FileOpenCommand { get; set; }
private int _number;
public int Number {
get { return _number; }
set
{
_number = value;
OnPropertyChanged("Number");
OnPropertyChanged("HeaderText");
}
}
public String HeaderText {
get {
return String.Format("_{0} {1}", Number, FileName);
}
}
// etc. etc. etc.
}