我有一个ItemsControl
控件,其中有ContextMenu
控件。
ItemsControl
将其ItemsSource
绑定到List<Person>
。
我想要做的是将Person
绑定到a DisplayNameCommand
和DisplaySurnameCommand
到相应的上下文菜单项,其中两个命令都位于MainWindowViewModel
-而不是绑定E 117
对象!E 218
中。
重要的是,ContextMenu
仍然需要有ItemsSource
数据上下文,因为我需要访问绑定对象属性以将其包含在命令参数中。
ItemsControl:
<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类:
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
对象,然后将其指向viewmodel命令,但这不是我要寻找的。
我已经为这个问题创建了一个演示项目。
我已经尝试过的
1. 在MenuItem中指定DataTemplate命令 (接受答案)
<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>
这是我得到的最接近的结果,这确实触发了命令,但问题是,对于所有菜单项,只能有一个命令集。
如果有办法通过为样式设置名称或使用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'.
接受的答案首先绑定到person对象,更新后的解决方案甚至没有工作,但我尝试过的第二个答案是:
<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正在夺走我的理智。
Ps。这是我的第一篇文章,所以如果你有任何评论,请告诉我。
发布于 2022-08-08 11:02:49
好的,第二天我找到了一个基于这解决方案的解决方案。它工作得很好,使用comamnds触发器,但是-更改了上下文菜单的DataContext,因此绑定的Person
对象不再可用。因此,为了解决这个问题,为了访问当前对象,我在Person
中添加了一个ViewModel属性,每当用户单击打开上下文菜单的图像时,都会更新。因此,这样你就可以知道点击了什么项目。
这个解决方案既可以访问绑定对象,也可以处理任意数量的命令。
这不是最好的解决办法,但效果很好。
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>
带有Person类的ViewModel:
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; }
}
如果你有任何问题或评论,请让我知道!
https://stackoverflow.com/questions/73270944
复制相似问题