是否有一种干净的方法使CanExecute始终使用属性返回true?

时间:2010-03-03 01:16:18

标签: .net wpf data-binding attributes

我想我已经知道了我的问题的答案,但无论如何我想把它放在那里。我有一个带有大量命令处理程序的应用程序,每个命令处理程序在其CanExecute方法中都有特殊逻辑,以适当地启用绑定按钮。

现在我处于一种我不希望执行任何逻辑的情况,因为执行会导致调用我不想发生的库仅用于GUI更新 。我不能删除库调用,因为它们对应用程序其余部分的功能非常重要。

我查看了.NET中的条件属性,遗憾的是,这不起作用,因为它们只能处理返回void的方法。我可以使用#if和#define来使用我的逻辑或只返回true。我还可以查询viewmodel中的属性,并允许它确定是否只返回true。

问题是,我不是很懒,但我也不想做一堆咕噜咕噜的工作来做出我猜的修改是不可避免的。但是,如果有人知道如何在.NET中使用某些东西来自动启用我的按钮而无需调用CanExecute或至少避免使用底层逻辑,请发布答案! :)

2 个答案:

答案 0 :(得分:1)

我怀疑为什么用GUI逻辑调用这个库是不好的。您不希望启用不执行任何操作的按钮,因此在无法实际工作时禁用的命令可能是件好事。

使用MVVM模式时,我的ViewModel通常会直接公开ICommands。如果使用Prism,则会有一个DelegateCommand实现,可以在ViewModel中轻松实现这些命令。如果没有,或者CanExecute可能会改变,我会在一个单独的类中实现ICommand。

如果您有长时间运行/昂贵的操作,您始终可以缓存库调用的结果。我假设如果状态改变将启用/禁用命令,您将获得事件或回调。在这种情况下,在ICommand实现中,您将引发CanExecuteChanged事件,以便GUI反映对命令的更改。下面是一个使用支持服务的命令示例,该支持服务知道何时可以完成操作:

public class ExpensiveCommand : ICommand
{
    private readonly IExpensiveService service;
    private bool canExecute;

    public ExpensiveCommand (IExpensiveService service)
    {
        this.service = service;
        canExecute = service.CanExecute();
        service.CanExecuteChanged += OnCanExecuteChanged;
    }

    public void Execute(object parameter)
    {
        service.Execute();
    }

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

    public event EventHandler CanExecuteChanged;
    private void OnCanExecuteChanged(object sender, EventArgs e)
    {
        canExecute = service.CanExecute();

        if (CanExecuteChanged != null)
            CanExecuteChanged(this, EventArgs.Empty);
    }
}

或者,如果您始终希望命令可执行,则可以从CanExecute方法返回true。

答案 1 :(得分:0)

我不知道是否有一种属性的方法,但试试这个。在窗口的某处,启动代码循环遍历所有命令绑定,并为每个命令绑定处理PreviewCanExecute事件。

public MainWindow()
{
    foreach (CommandBinding cb in CommandBindings)
    {
        cb.PreviewCanExecute += new CanExecuteRoutedEventHandler(cb_PreviewCanExecute);
    }
}

void cb_PreviewCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = false; // disable / enable all commands
    e.Handled = true; // Set this to skip calling your existing logic
}