[英]Bind a ContextMenu Command inside of a ItemSource to a command inside the ViewModel
我有一個ItemsControl
控件,其中有ContextMenu
控件。
ItemsControl
將其ItemsSource
綁定到List<Person>
。
我想要做的是將DisplayNameCommand
和DisplaySurnameCommand
綁定到它們相應的上下文菜單項,其中兩個命令都在MainWindowViewModel
內 -而不是綁定的Person
對象!!! .
重要的是ContextMenu
仍然需要具有ItemsSource
數據上下文,因為我需要訪問綁定的 object 屬性以將其包含在命令參數中。
項目控制:
<ItemsControl ItemsSource="{Binding PeopleList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Surname}"/>
<Image>
<Image.ContextMenu>
<ContextMenu>
<MenuItem Header="Display Name"
Command="{Binding DisplaySurnameCommand}"
CommandParameter="{Binding Name}">
</MenuItem>
<MenuItem Header="Display Surname"
Command="{Binding DisplaySurnameCommand}"
CommandParameter="{Binding Surname}">
</MenuItem>
</ContextMenu>
</Image.ContextMenu>
</Image>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
MainWindowViewModel 和 Person class:
public class MainWindowViewModel
{
public MainWindowViewModel()
{
DisplayNameCommand = new RelayCommand(DisplayName);
DisplaySurnameCommand = new RelayCommand(DisplaySurname);
PeopleList = new List<Person>();
PeopleList.Add(new Person("Julie", "Adams"));
PeopleList.Add(new Person("Mack", "McMack"));
PeopleList.Add(new Person("Josh", "Broccoli"));
}
public List<Person> PeopleList { get; set; }
public void DisplayName(object message)
{
MessageBox.Show("Name: " + (string)message);
}
public void DisplaySurname(object message)
{
MessageBox.Show("Surname: "+ (string)message);
}
public RelayCommand DisplayNameCommand { get; }
public RelayCommand DisplaySurnameCommand { get; }
}
public class Person
{
public Person(string name, string surname)
{
Name = name;
Surname = surname;
}
public string Name { get; set; }
public string Surname { get; set; }
}
我也知道可以將它綁定到Person
object,然后將其指向 viewmodel 命令,但這不是我想要的。
我為這個問題創建了一個演示項目。
我試過的
1. 在 DataTemplate 中為 MenuItem 指定命令(已接受的答案)
<ContextMenu>
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{Binding DataContext.DisplaySurname, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"/>
<Setter Property="CommandParameter" Value="{Binding Name}"/>
</Style>
</ContextMenu.ItemContainerStyle>
<MenuItem Header="Display Name">
<MenuItem Header="Display Surname">
</ContextMenu>
所以這是我得到的最接近結果的結果,這確實觸發了命令,但問題是所有菜單項只能有 1 個命令集。
如果有辦法通過設置樣式的名稱或使用 ItemContainerStyle 以外的其他東西來解決這個問題,它可以工作,但我想不出類似的東西。
2.設置相對命令
<ContextMenu>
<MenuItem Header="Display Name"
Command="{Binding DataContext.DisplayNameCommand, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"
CommandParameter="{Binding Name}"/>
<MenuItem Header="Display Surname"
Command="{Binding DataContext.DisplaySurnameCommand, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}"
CommandParameter="{Binding Surname}"/>
</ContextMenu>
這將返回一個綁定錯誤:
Cannot find source: RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1'.
接受的答案首先綁定到一個人 object,更新的解決方案甚至不起作用,但我嘗試過的第二個答案:
<MenuItem Header="Display Surname"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DisplaySurnameCommand}"
CommandParameter="{Binding Surname}"/>
返回以下綁定錯誤:
Cannot find source: RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1'.
...除了這三個之外,我還嘗試了更多的解決方案和變體,但幾乎沒有結果。
我花了一整天的時間試圖找到解決方案,請幫助我,wpf 正在奪走我的理智。
附言。 這是我的第一篇文章,所以如果您有任何意見,請告訴我。
好的,第二天我找到了基於此解決方案的解決方法。 它工作得很好,comamnds 觸發器,但是 - 它改變了上下文菜單的 DataContext ,所以綁定的Person
object 不再可用。 因此,為了解決這個問題,為了訪問當前的 object,我在 ViewModel 中添加了一個Person
屬性,每當用戶單擊打開上下文菜單的圖像時,該屬性就會更新。 所以這樣你就知道點擊了什么項目。
此解決方案既可以訪問綁定的 object,也可以處理任意數量的命令。
不是最漂亮的解決方案,但效果很好。
Xaml:
<ItemsControl ItemsSource="{Binding PeopleList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Surname}"/>
<Image Source="more_64px.png" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Window}}" >
<Image.InputBindings>
<MouseBinding Gesture="LeftClick" Command="{Binding DataContext.UpdateCurrentObjectCommand, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}" CommandParameter="{Binding}"/>
<MouseBinding Gesture="RightClick" Command="{Binding DataContext.UpdateCurrentObjectCommand, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}" CommandParameter="{Binding}"/>
</Image.InputBindings>
<Image.ContextMenu>
<ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={x:Static RelativeSource.Self}}">
<MenuItem Header="Display Name" Command="{Binding DisplayNameCommand}"/>
<MenuItem Header="Display Surname" Command="{Binding DisplaySurnameCommand}"/>
</ContextMenu>
</Image.ContextMenu>
</Image>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
ViewModel 與人 class:
public class MainWindowViewModel
{
public MainWindowViewModel()
{
DisplayNameCommand = new RelayCommand(DisplayName);
DisplaySurnameCommand = new RelayCommand(DisplaySurname);
PeopleList = new List<Person>();
PeopleList.Add(new Person("Julie", "Adams"));
PeopleList.Add(new Person("Mack", "McMack"));
PeopleList.Add(new Person("Josh", "Broccoli"));
UpdateCurrentObjectCommand = new RelayCommand(UpdateCurrentObject);
}
private void UpdateCurrentObject(object person)
{
CurrentPerson = (Person)person;
}
private Person CurrentPerson { get; set; }
public List<Person> PeopleList { get; set; }
public void DisplayName()
{
MessageBox.Show("Name: " + CurrentPerson.Name);
}
public void DisplaySurname()
{
MessageBox.Show("Name: " + CurrentPerson.Surname);
}
public RelayCommand DisplayNameCommand { get; }
public RelayCommand DisplaySurnameCommand { get; }
public RelayCommand UpdateCurrentObjectCommand { get; }
}
public class Person
{
public Person(string name, string surname)
{
Name = name;
Surname = surname;
}
public string Name { get; set; }
public string Surname { get; set; }
}
如果您有任何問題或意見,請告訴我!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.