簡體   English   中英

C#和WPF中的命令

[英]Command in C# and WPF

我有非常簡單的代碼,但是它不起作用。

我有一個命令:

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中其他兩個元素(文本框和復選框)的值未更改。

您正在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的新實例。 視圖模型應該創建命令,而不是相反。

ICommand接口的典型實現通常接受要執行的Action<object>和決定是否執行命令的Predicate<object>

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);
    }
}

然后在視圖模型中實現該邏輯:

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

    }

    public ViewModelBase()
    {
        TheCommand = new SetYesCommand(OnCommandExecuted, null);
    }

    private void OnCommandExecuted(object parameter)
    {
        Sname = "Yes";
        MessageBox.Show("Command works");
    }

    public ICommand TheCommand { get; private set; }

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

    public event PropertyChangedEventHandler PropertyChanged;
}

在視圖中,您綁定到視圖模型的command屬性,該屬性返回ICommand實現的實例:

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

您似乎對命令和視圖模型之間的關系感到困惑。

命令對象應該是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
    }
}

現在,您可以將Window的DataContext設置為MyViewModel的實例,並將按鈕的command屬性綁定到DoSomethingCommand。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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