WPF binding error with ICommand

I have a simple WPF example that is trying to bind a ListBox Selected event to ICommand in a view model.

Xaml

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    <Grid>
        <ListBox ItemsSource="{Binding Items}" 
                 Selected="{Binding DoSomething}"/>

    </Grid>
</Window>

Show model

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext = new ViewModel();
        }
    }

    public class ViewModel : INotifyPropertyChanged
    {
        public ViewModel()
        {
            Items = new List<string>();
            Items.Add("A");
            Items.Add("B");
            Items.Add("C");

            DoSomething = new MyCommand();
        }

        public List<string> Items { get; set; }


        public event PropertyChangedEventHandler PropertyChanged;

        public ICommand DoSomething { get; set; }
    }

    public class MyCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter) { return true; }

        public void Execute(object parameter) { }
    }
}

An error occurs in the constructor of InitializeComponent.

XamlParseException: The binding cannot be set to the "AddSelectedHandler" property of the "ListBox" type. Binding can be set to the DependencyProperty of a DependencyObject.

enter image description here

How can I call ICommand in my view model from a selected event of a ListBox control?

+4
source share
2 answers

Selected in a ListBox is an event. You have a SelectedItem that you can bind to a property of the same type as the list item in the viewmodel:

<Grid>
    <ListBox ItemsSource="{Binding Items}" 
             SelectedItem="{Binding MyItem}"/>
</Grid>

.

public class ViewModel : INotifyPropertyChanged
{
    public string MyItem { get; set; }
}

, , CommandSource, Button:

<Button Command="{Binding DoSomething}" CommandParameter="{Binding}" />

, WPF ICommand. CommandParameter .

+5

, "Selected" - , Actualy, . . WPF EventArgs . System.Windows.Interactivity.

<Window x:Class="Example.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Example"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <ListView
        ItemsSource="{Binding Country}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">
                <local:InteractiveCommand Command="{Binding SelectedCountryCommand}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </ListView>
   <Grid
       Grid.Column="1">
       <Grid.RowDefinitions>
           <RowDefinition Height="Auto"/>
           <RowDefinition/>
       </Grid.RowDefinitions>
       <Label
           HorizontalAlignment="Center"
           Content="SELECTED ITEMS:"/>
       <ListView
           Grid.Row="1"
           ItemsSource="{Binding SelectedCountry}"/>
   </Grid>
</Grid>

 public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainViewModel();
    }

}

public class MainViewModel:INotifyPropertyChanged
{
    public List<string> Country { get; set; } = new List<string>
    {
        "USA",
        "CANADA",
        "FRANCE",
        "GERMAN",
        "JAPAN",
        "ITALY",
        "UKARAINE",
        "POLAND",
        "GREAT BRITAIN",
        "TURKEY"
    };

    public ObservableCollection<string> SelectedCountry { get; set; } = new ObservableCollection<string>();

    public ICommand SelectedCountryCommand =>
        _selectedCountryCommand ?? (_selectedCountryCommand = new RelayCommand(
            param =>
            {
                SelectedCountry.Clear();
                SelectedCountry.Add((param as SelectionChangedEventArgs).AddedItems[0].ToString());
            }));

    private ICommand _selectedCountryCommand;

    //INotifyPropertyChanged implementation
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class RelayCommand : ICommand
{

    private readonly Action<object> _execute;
    private readonly Predicate<object> _canExecute;


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


    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        _execute = execute ?? throw new ArgumentNullException(nameof(execute));
        _canExecute = canExecute;
    }

    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return _canExecute?.Invoke(parameter) ?? true;
    }

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

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

}

public class InteractiveCommand : TriggerAction<DependencyObject>
{
    protected override void Invoke(object parameter)
    {
        if (AssociatedObject == null)
            return;
        var command = ResolveCommand();
        if (command != null && command.CanExecute(parameter))
        {
            command.Execute(parameter);
        }
    }

    private ICommand ResolveCommand()
    {
        ICommand command = null;
        if (Command != null)
        {
            return Command;
        }
        if (AssociatedObject != null)
        {
            foreach (var info in AssociatedObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                if (typeof(ICommand).IsAssignableFrom(info.PropertyType) && string.Equals(info.Name, CommandName, StringComparison.Ordinal))
                {
                    command = (ICommand)info.GetValue(AssociatedObject, null);
                }
            }
        }
        return command;
    }

    private string _commandName;
    public string CommandName
    {
        get
        {
            ReadPreamble();
            return _commandName;
        }
        set
        {
            if (CommandName == value)
                return;
            WritePreamble();
            _commandName = value;
            WritePostscript();
        }
    }

    #region Command
    public ICommand Command
    {
        get => (ICommand)GetValue(CommandProperty);
        set => SetValue(CommandProperty, value);
    }

    // Using a DependencyProperty as the backing store for Command.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register("Command", typeof(ICommand), typeof(InteractiveCommand), new UIPropertyMetadata(null));
    #endregion
}
+1

Source: https://habr.com/ru/post/1695371/


All Articles