【问题标题】:WPF ICommand equivalent of Click -= Button_ClickWPF ICommand 等效于 Click -= Button_Click
【发布时间】:2020-06-25 20:15:22
【问题描述】:

对于 WPF ICommand,事件处理程序 -= 的等价物是什么?

我们有一个用户控制按钮,用于管理提交购买请求的功能,但需要用户先在工作站上注册。

WinForms的用法是:

this.Click -= this.btnRegister_Click;
this.Click -= this.btnSubmit_Click;

WPF 中的现代化版本具有单个 ICommand 属性和典型声明。

public ICommand ClickCommand { get; set; }
....
ClickCommand = new DelegateCommand(RegisterClicked);

一旦用户注册,用户控件将重新初始化到提交过程。存在一个简单的触发器来检查按钮的状态。从视觉上看,触发器工作正常,这表明程序正在处理初始化代码块。

<Label.Style>
    <Style TargetType="Label" BasedOn="{StaticResource ButtonLabel}">
        <Setter Property="Content" Value="Approvals"/>
        <Style.Triggers>
            <DataTrigger Binding="{Binding Path=ButtonState}" Value="{x:Static locdata:WorkflowButtonState.Register}">
                <Setter Property="Content" Value="Register"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=ButtonState}" Value="{x:Static locdata:WorkflowButtonState.Submit}">
                <Setter Property="Content" Value="Submit"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Label.Style>

初始化代码块

private void InitRegister()
{
    ButtonState = WorkflowButtonState.Register;
    ClickCommand = new DelegateCommand(RegisterClicked);
}
private void InitSubmit()
{
    ButtonState = WorkflowButtonState.Submit;
    ClickCommand = new DelegateCommand(SubmitClicked);
}

private void Reset()
{
    ClickCommand = null;
    ButtonState = WorkflowButtonState.Default;
}

调试模式清楚地表明 ClickCommand 执行方法是 SubmitClicked,但是 RegisterClicked 事件仍然会触发。这只发生在注册过程首先发生时,因为用户之前没有登录过工作站。

由于设置 ClickCommand = null 没有帮助,复制 EventHandler -= 行为需要什么?

更新

到目前为止,我的应用程序中的 ICommand 用法一直是单次使用。正如安迪的回答所说,它应该被视为一个属性并引发属性更改事件。

更新后的 ICommand 声明,正如我多次为属性所做的那样,所有需要改变的地方。

private ICommand _clickCommand;
public ICommand ClickCommand { get => _clickCommand; set { _clickCommand = value; OnPropertyChanged(); } }

【问题讨论】:

  • 在你的问题结束时,你有点迷失了我。你能否澄清最后两段,或者包括一个可重现的例子?

标签: wpf eventhandler icommand delegatecommand


【解决方案1】:

这里需要考虑两件事:

  1. 按钮上的命令不是事件,而是依赖属性。 https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.primitives.buttonbase.command?view=netcore-3.1

  2. 如何告诉视图中的依赖属性应该从视图模型中再次读取它的值?

您通知属性已更改。

一些示例标记:

    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <StackPanel>
        <Button Command="{Binding TestCommand}" Content="Test"/>
        <Button Command="{Binding ChangeCommand}" Content="Change Test Command"/>
    </StackPanel>
</Window>

有一个测试命令将作为一个命令开始,然后当您单击更改测试命令按钮时,它将更改为另一个命令。

我的视图模型:

    public class MainWindowViewModel : BindableBase
    {
        private DelegateCommand testCommand;
        public DelegateCommand TestCommand 
        {
            get => testCommand;
            set { testCommand = value; RaisePropertyChanged(); }
        }
        public DelegateCommand ChangeCommand { get; set; }
        public MainWindowViewModel()
        {
            TestCommand = new DelegateCommand(() => { MessageBox.Show("Original Command"); });
            ChangeCommand = new DelegateCommand(() => 
            {
                TestCommand = new DelegateCommand(() => { MessageBox.Show("Replacement is used"); });
            });
        }
    }

当调用changecommand时,testcommand的delegatecommand被替换为一个新的命令。

还有。

调用已更改的属性。

这告诉 UI 去获取那个新命令。

如果我随后删除从 TestCommand 更改的 raise 属性:

        public DelegateCommand TestCommand 
        {
            get => testCommand;
            set { testCommand = value;  }
        }

单击更改按钮,然后单击我的测试按钮,我得到原始命令运行。这是你看到的问题。因为你的命令看起来像:

public ICommand ClickCommand { get; set; }

没有改变 raise 属性。

注意:

如果我的更改命令是:

            ChangeCommand = new DelegateCommand(() => 
            {
                TestCommand = null;
            });

然后单击该更改按钮,单击测试按钮,没有任何反应。它的命令现在为空。

【讨论】:

    【解决方案2】:

    据我了解,您有一个按钮,其内容和功能的变化取决于某些条件。您还为每个 button 的功能实现了 2 个命令;但是,其中一个命令在它不应该采取行动时仍然采取行动,对吗?

    在这种情况下,我认为您可以修改 DelegteCommand(它继承 IComamnd 接口)以向其添加 CanExecute() 委托。稍后,当您为命令创建新实例时,只需添加一个委托以确定该命令是否可执行。像这样的:

    公共类 DelegateCommand: ICommand
    {
        私人行动_执行;
        私有函数 _canExecute;
    
        公共 DelegateCommand(动作执行,Func canExecute)
        {
             _execute = 执行;
             _canExecute = 可以执行;
        }
    
        公共布尔 CanExecute()
        {
            if (_canExecute != null && _execute)
                返回 _canExecute.Invoke();
        }
    
        公共无效执行()
        {
            如果(可以执行())
                _execute.Invoke();
        }
    }
    
    public ICommand RegisterClicked { get;放; }
    
    RegisterClicked = new DelegateCommand(RegisterInvoke, RegisterCanExecute);
    
    私人无效注册调用()
    {
    }
    私有布尔 RegisterCanExecute()
    {
        // 判断Register的执行时间并在此处执行
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-13
      • 2011-08-22
      • 1970-01-01
      • 1970-01-01
      • 2013-03-27
      • 1970-01-01
      • 1970-01-01
      • 2011-03-23
      相关资源
      最近更新 更多