簡體   English   中英

將 ItemSource 內的 ContextMenu 命令綁定到 ViewModel 內的命令

[英]Bind a ContextMenu Command inside of a ItemSource to a command inside the ViewModel

我有一個ItemsControl控件,其中有ContextMenu控件。
ItemsControl將其ItemsSource綁定到List<Person>

我想要做的是將DisplayNameCommandDisplaySurnameCommand綁定到它們相應的上下文菜單項,其中兩個命令都在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'.

3. 無法將 ContextMenu 操作綁定到命令

接受的答案首先綁定到一個人 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM