简体   繁体   中英

How do I properly bind my ContextMenu command to a RelayCommand?

So I have a few buttons setup to a RelayCommand and it's working perfectly, but when trying to bind the Command property of a ContextMenu Menu Item it just doesn't react to it. I read something about having to set the AncestorType of level or something but it was a very vast description not explaining why or how.

So I have my ListView

<ListView x:Name="PlayerListView"
                  Width="200"
                  Height="330"
                  VerticalAlignment="Top"
                  Margin="0,80,15,0"
                  HorizontalAlignment="Right"
                  Background="#252525"
                  VerticalContentAlignment="Center"
                  ItemsSource="{Binding ServerViewModel.Players}">

            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" 
                                VerticalAlignment="Stretch" 
                                HorizontalAlignment="Stretch"
                                Width="190"
                                Background="#222222">

                        <StackPanel.ContextMenu>
                            <ContextMenu>
                                <MenuItem Header="Command One">
                                    <MenuItem.Icon>
                                        <Image Source="../../Assets/image.png"
                                               RenderOptions.BitmapScalingMode="Fant"/>
                                    </MenuItem.Icon>
                                </MenuItem>

                                <MenuItem Header="Command Two"
                                          Command="{Binding ServerViewModel.MyCommand,
                                    RelativeSource={RelativeSource AncestorType=ListViewItem}}">
                                    <MenuItem.Icon>
                                        <Image Source="../../Assets/image.png"
                                               RenderOptions.BitmapScalingMode="Fant"/>
                                    </MenuItem.Icon>
                                </MenuItem>
                            </ContextMenu>
                        </StackPanel.ContextMenu>

                        <Image Source="../../Assets/image.png"
                               Width="20"
                               Height="20"/>

                        <TextBlock Text="{Binding Username}" 
                                   Foreground="White"
                                   HorizontalAlignment="Stretch"
                                   VerticalAlignment="Center" 
                                   Margin="5"/>
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

And as you can see on the second item I am trying to bind it to my RelayCommand. It should work since the viewmodels and datacontext is setup properly for my buttons.

public class BaseViewModel : ObservableObject
    {
        public ServerViewModel ServerViewModel { get; set; } = new ServerViewModel();
    }

ViewModel

public RelayCommand MyCommand { get; set; }

public ServerViewModel()
        {
            MyCommand = new RelayCommand(DoSomething);
        }
public void DoSomething(object parameter)
        {
            MessageBox.Show("Working!");
        }

And ofcourse the RelayCommand itself. Again the RelayCommands work for buttons but not the ContextMenu Items

public class RelayCommand : ObservableObject, ICommand
    {
        private readonly Action<object> _execute;
        private readonly Predicate<object> _canExecute;

        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
                throw new ArgumentException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }

        public RelayCommand(Action<object> execute) : this(execute, null)
        {

        }

        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _execute.Invoke(parameter);
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    }

And this is where I set the DataContext

public MainWindow()
        {
            InitializeComponent();
            DataContext = new BaseViewModel();
        }

This code

Command="{Binding ServerViewModel.MyCommand, RelativeSource={RelativeSource AncestorType=ListViewItem}}"

tries to find the property ServerViewModel in the ListViewItem class and will not find it. If the objects returned by ServerViewModel.Players are themselves ViewModel objects, you could remove the RelativeSource part and add your command to the Player ViewModel.

Example:

Command="{Binding MyCommand}"

and in PlayerViewModel:

    public RelayCommand MyCommand { get; set; }

    public PlayerViewModel()
    {
        MyCommand = new RelayCommand(DoSomething);
    }
    public void DoSomething(object parameter)
    {
        MessageBox.Show("Player Working!");
    }

For alternative solutions, see here: WPF: Binding a ContextMenu to an MVVM Command

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM