首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将ContextMenu命令绑定到ItemSource中的命令到ViewModel中的命令

将ContextMenu命令绑定到ItemSource中的命令到ViewModel中的命令
EN

Stack Overflow用户
提问于 2022-08-07 20:48:15
回答 1查看 38关注 0票数 0

我有一个ItemsControl控件,其中有ContextMenu控件。

ItemsControl将其ItemsSource绑定到List<Person>

我想要做的是将Person绑定到a DisplayNameCommandDisplaySurnameCommand到相应的上下文菜单项,其中两个命令都位于MainWindowViewModel -而不是绑定E 117对象!E 218中。

重要的是,ContextMenu仍然需要有ItemsSource数据上下文,因为我需要访问绑定对象属性以将其包含在命令参数中。

ItemsControl:

代码语言:javascript
运行
复制
<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类:

代码语言:javascript
运行
复制
    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命令 (接受答案)

代码语言:javascript
运行
复制
<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.设置一个相对命令

代码语言:javascript
运行
复制
<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'.

3. 无法将ContextMenu操作绑定到命令

接受的答案首先绑定到person对象,更新后的解决方案甚至没有工作,但我尝试过的第二个答案是:

代码语言:javascript
运行
复制
<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。这是我的第一篇文章,所以如果你有任何评论,请告诉我。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-08-08 11:02:49

好的,第二天我找到了一个基于解决方案的解决方案。它工作得很好,使用comamnds触发器,但是-更改了上下文菜单的DataContext,因此绑定的Person对象不再可用。因此,为了解决这个问题,为了访问当前对象,我在Person中添加了一个ViewModel属性,每当用户单击打开上下文菜单的图像时,都会更新。因此,这样你就可以知道点击了什么项目。

这个解决方案既可以访问绑定对象,也可以处理任意数量的命令。

这不是最好的解决办法,但效果很好。

工作项目演示

Xaml:

代码语言:javascript
运行
复制
<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:

代码语言:javascript
运行
复制
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; }
    }

如果你有任何问题或评论,请让我知道!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73270944

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档