Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用ICommand的WPF绑定错误_C#_Wpf_Xaml_Data Binding - Fatal编程技术网

C# 使用ICommand的WPF绑定错误

C# 使用ICommand的WPF绑定错误,c#,wpf,xaml,data-binding,C#,Wpf,Xaml,Data Binding,我有一个简单的WPF示例,试图将ListBox的选定事件绑定到视图模型中的ICommand 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:

我有一个简单的WPF示例,试图将ListBox的选定事件绑定到视图模型中的ICommand

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>

查看模型

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) { }
    }
}
名称空间WpfApp1
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
DataContext=新的ViewModel();
}
}
公共类视图模型:INotifyPropertyChanged
{
公共视图模型()
{
项目=新列表();
项目。添加(“A”);
项目。添加(“B”);
项目。添加(“C”);
DoSomething=新的MyCommand();
}
公共列表项{get;set;}
公共事件属性更改事件处理程序属性更改;
公共ICommand DoSomething{get;set;}
}
公共类MyCommand:ICommand
{
公共事件处理程序CanExecuteChanged;
public bool CanExecute(对象参数){return true;}
public void Execute(对象参数){}
}
}
该错误发生在InitializeComponent的构造函数中

XamlParseException:无法在上设置“绑定” “ListBox”类型的“AddSelectedHandler”属性。“绑定”只能 可以根据DependencyObject的DependencyProperty设置


如何从ListBox控件的选定事件在视图模型中调用ICommand?

在ListBox上选择是一个事件。您拥有SelectedItem,可以将其绑定到与viewmodel上列表元素类型相同的属性:

<Grid>
    <ListBox ItemsSource="{Binding Items}" 
             SelectedItem="{Binding MyItem}"/>
</Grid>
对于您的命令,您需要一个处理CommandSource的控件,如按钮:

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

像这样绑定它,将使WPF能够识别您的ICommand。CommandParameter是可选的。

这是因为“Selected”是事件,实际上您不能将命令直接绑定到任何事件。但是有几种可行的方法来解决这个问题。 在下面的示例中,我使用自定义命令实现绑定到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>

公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
DataContext=新的MainViewModel();
}
}
公共类MainViewModel:INotifyPropertyChanged
{
公共列表国家{get;set;}=新列表
{
“美国”,
“加拿大”,
“法国”,
“德语”,
“日本”,
“意大利”,
“乌克兰”,
“波兰”,
“大不列颠”,
“土耳其”
};
public ObservableCollection SelectedCountry{get;set;}=new ObservableCollection();
公共ICommand SelectedCountryCommand=>
_selectedCountryCommand???(\u selectedCountryCommand=new RelayCommand(
参数=>
{
SelectedCountry.Clear();
SelectedCountry.Add((参数为SelectionChangedEventArgs.AddedItems[0].ToString());
}));
专用ICommand_selectedCountryCommand;
//INotifyPropertyChanged实现
公共事件属性更改事件处理程序属性更改;
[NotifyPropertyChangedInvocator]
受保护的虚拟void OnPropertyChanged([CallerMemberName]字符串propertyName=null)
{
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
}
}
公共类中继命令:ICommand
{
私有只读操作\u执行;
私有只读谓词_canExecute;
公共中继命令(操作执行)
:此(执行,空)
{
}
公共RelayCommand(操作执行,谓词canExecute)
{
_execute=execute??抛出新的ArgumentNullException(nameof(execute));
_canExecute=canExecute;
}
[调试步骤至]
公共布尔CanExecute(对象参数)
{
返回_canExecute?.Invoke(参数)?true;
}
公共事件事件处理程序CanExecuteChanged
{
add=>CommandManager.RequerySuggested+=值;
remove=>CommandManager.RequerySuggested-=值;
}
public void Execute(对象参数)
{
_执行(参数);
}
}
公共类InteractiveCommand:TriggerAction
{
受保护的覆盖无效调用(对象参数)
{
if(AssociatedObject==null)
返回;
var command=ResolveCommand();
if(command!=null&&command.CanExecute(参数))
{
command.Execute(参数);
}
}
专用ICommand ResolveCommand()
{
ICommand命令=null;
if(命令!=null)
{
返回命令;
}
if(AssociatedObject!=null)
{
foreach(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);
}
}
}
返回命令;
}
私有字符串_commandName;
公共字符串命令名
{
得到
{
ReadPremission();
返回命令名;
}
设置
{
if(CommandName==值)
返回;
writeStreamble();
_commandName=值;
WritePostscript();
}
}
#地区司令部
公共ICommand命令
{
get=>(ICommand)GetValue(CommandProperty);
set=>SetValue(CommandProperty,value);
}
//使用依赖项
<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
}