C#和WPF中的命令

C#和WPF中的命令,c#,wpf,C#,Wpf,我有非常简单的代码,但它不工作 我有一个命令: public class SetYesCommand : ICommand , INotifyPropertyChanged { public event EventHandler CanExecuteChanged; public event PropertyChangedEventHandler PropertyChanged; ViewModelBase view = new View

我有非常简单的代码,但它不工作

我有一个命令:

public class SetYesCommand : ICommand , INotifyPropertyChanged
    {
        public event EventHandler CanExecuteChanged;
        public event PropertyChangedEventHandler PropertyChanged;

        ViewModelBase view = new ViewModelBase();

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

        public void Execute(object parameter)
        {
            view.Sname = "Yes";
            MessageBox.Show("Command works");
            onpropertychanged("Sname");
        }

        private void onpropertychanged(string propertyname)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
            }
        }
    }
}
这是我的基本视图模型类:

 public class ViewModelBase : INotifyPropertyChanged
    {
        private  string _s;
        public  string Sname {
            get { return _s; }
            set { _s = value;
                onPropertyChanged("Sname");
            }

        }

        private void onPropertyChanged(string propertyname)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
这是我的XAML代码:

<Window x:Class="Test.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:Test"
        mc:Ignorable="d"
        xmlns:viewmodel="clr-namespace:Test.ViewModel"
         xmlns:commands="clr-namespace:Test.ViewModel.Commands"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <viewmodel:ViewModelBase  x:Key="base" ></viewmodel:ViewModelBase>
        <viewmodel:Converters  x:Key="convert" ></viewmodel:Converters>
        <commands:SetYesCommand x:Key="setyes"/>
    </Window.Resources>
    <StackPanel>
        <Button Width="100" Height="30" Command="{StaticResource setyes}"/>
        <TextBox DataContext="{StaticResource base}" Text="{Binding Sname , Mode=TwoWay}"/>
        <CheckBox DataContext="{StaticResource base}" IsChecked="{Binding Sname , Mode=TwoWay , Converter={StaticResource convert}}"  />
        <TextBox />
    </StackPanel>
</Window>


正如您所看到的,我将UI中的两个元素绑定到视图模型基类中的字符串属性,并为UI中的按钮定义一个命令。该命令之所以有效,是因为正如您所看到的,我使用messagebox对其进行了检查,但UI中另外两个元素(textbox和checkbox)的值没有改变。

您似乎对命令和viewmodel之间的关系感到困惑

命令对象应该是viewmodel的属性,而不是反过来

从基本的通用ICommand实现开始

public class BasicCommand: ICommand
{
    private readonly Action _execute;

    public BasicCommand(Action execute)
    {
        _execute = execute;
    }

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

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

    public event EventHandler CanExecuteChanged;
}
而不是在viewmodel中,将命令定义为类似以下内容的属性

public class MyViewModel: ViewModelBase
{
    public MyViewModel()
    {
        DoSomethingCommand = new BasicCommamd(()=>OnDoSomething());
    }

    public ICommand DoSomethingCommand {get;}

    private void OnDoSomething()
    {
        // put whatever you want the command to do here
    }
}

现在,您可以将窗口的DataContext设置为MyViewModel的实例,并将按钮的command属性绑定到DoSomethingCommand。

您正在SetYesCommand内创建ViewModelBase的新实例,因此view.Sname=“Yes”不会更改绑定到元素的视图模型的Sname属性

这是有效的:

<Window x:Class="Test.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:Test"
        mc:Ignorable="d"
        xmlns:viewmodel="clr-namespace:Test.ViewModel"
        xmlns:commands="clr-namespace:Test.ViewModel.Commands"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <viewmodel:ViewModelBase  x:Key="base" ></viewmodel:ViewModelBase>
        <viewmodel:Converters  x:Key="convert" ></viewmodel:Converters>
    </Window.Resources>
    <StackPanel>
        <Button Width="100" Height="30" Command="{Binding Source={StaticResource base},Path=YesCommand}"/>
        <TextBox DataContext="{StaticResource base}" Text="{Binding Source={StaticResource base},Path=Sname , Mode=TwoWay}"/>
        <CheckBox DataContext="{StaticResource base}" IsChecked="{Binding Sname , Mode=TwoWay , Converter={StaticResource convert}}"  />
        <TextBox />
    </StackPanel>
</Window>

public class ViewModelBase : INotifyPropertyChanged
    {
        private string _s;

        private Commands.SetYesCommand _yesCommand;

        public ViewModelBase()
        {
            _yesCommand = new SetYesCommand(this);
        }

        public string Sname
        {
            get { return _s; }
            set
            {
                _s = value;
                onPropertyChanged("Sname");
            }

        }

        public SetYesCommand YesCommand => _yesCommand;

        private void onPropertyChanged(string propertyname)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

public class SetYesCommand : ICommand, INotifyPropertyChanged
{
    public event EventHandler CanExecuteChanged;
    public event PropertyChangedEventHandler PropertyChanged;

    private ViewModelBase view;

    public SetYesCommand(ViewModelBase view)
    {
        this.view = view;
    }

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

    public void Execute(object parameter)
    {
        view.Sname = "Yes";
        MessageBox.Show("Command works");
        onpropertychanged("Sname");
    }

    private void onpropertychanged(string propertyname)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
        }
    }
}

公共类ViewModelBase:INotifyPropertyChanged
{
私有字符串;
private Commands.SetYesCommand _yesCommand;
公共ViewModelBase()
{
_yesCommand=新设置yesCommand(此);
}
公共字符串Sname
{
获取{return}
设置
{
_s=值;
不动产变更(“Sname”);
}
}
公共设置YesCommand和YesCommand=>\u YesCommand;
私有void onPropertyChanged(字符串propertyname)
{
if(PropertyChanged!=null)
{
PropertyChanged(这是新的PropertyChangedEventArgs(propertyname));
}
}
公共事件属性更改事件处理程序属性更改;
}
公共类SetYesCommand:ICommand,INotifyPropertyChanged
{
公共事件处理程序CanExecuteChanged;
公共事件属性更改事件处理程序属性更改;
私有视图模型库视图;
公共设置是命令(ViewModelBase视图)
{
this.view=视图;
}
公共布尔CanExecute(对象参数)
{
返回true;
}
public void Execute(对象参数)
{
view.Sname=“是”;
MessageBox.Show(“命令工作”);
不动产变更(“Sname”);
}
私有void onpropertychanged(字符串propertyname)
{
if(PropertyChanged!=null)
{
PropertyChanged(这是新的PropertyChangedEventArgs(propertyname));
}
}
}

您正在命令中创建
ViewModelBase
的新实例。应该是视图模型创建命令,而不是相反

ICommand
接口的典型实现通常接受要执行的
操作
,以及决定是否执行命令的
谓词

public class SetYesCommand : ICommand
{
    public event EventHandler CanExecuteChanged;
    private readonly Action<object> _execute;
    private readonly Predicate<object> _canExecute;

    public SetYesCommand(Action<object> execute, Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

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

    public void Execute(object parameter)
    {
        if (_execute != null)
            _execute(parameter);
    }
}
在视图中,您绑定到视图模型的命令属性,该属性返回
ICommand
实现的实例:

<Button Width="100" Height="30" DataContext="{StaticResource base}" Command="{Binding TheCommand}"/>


您正在命令中创建ViewModelBase的新实例。应该创建命令的是视图模型,而不是相反的方式。@mm8我也用静态属性尝试过它,但它不能以那种方式工作。是的,我是MVVM的新手,有点困惑,谢谢。看看我的博客,看看我对WPF/MVVM的看法——这太好了,谢谢你,但我仍然无法理解为什么即使我的属性是静态的,它也不能工作。
<Button Width="100" Height="30" DataContext="{StaticResource base}" Command="{Binding TheCommand}"/>