与 "CanXXXX" 一起监听多个属性

Have a commande with the "CanXXXX" listening to multiple properties

我正在做一个可以显示向导(使用 WPF+Prism)的 UserControl

为此,我有两个控件:WizardWizardPage

我希望我能以这样的事情结束

<Wizard>
    <WizardPage CanGoToNext="{Binding SomePropertySayingThatThisPaneIsOk}">
        <TextBlock>Page one</TextBlock>
    </WizardPage>
    <WizardPage CanGoToNext="{Binding SomePropertySayingThatThisPaneIsOk}" CanGoToPrevious="False">
        <TextBlock>Page Four</TextBlock>
    </WizardPage>
    <WizardPage CanGoToNext="{Binding SomePropertySayingThatThisPaneIsOk}" CanGoToPrevious="True">
        <TextBlock>Page Three</TextBlock>
    </WizardPage>
</Wizard>

我目前卡在向导用户控件中的命令上。

我要3个Buttons:

我想在上面绑定 UserControl 的一些命令。

问题是如果按钮的命令可以执行则更新条件。

就我而言,我想:

//PseudoCode
CurrentPage != FirstPage
&& CurrentPage.CanGoToPrevious

但我不知道如何制作 DelegateCommand 并要求他们在 CurrentPage.CanGoToPrevious 的依赖性 属性 发生变化时再次检查其状况?

嗯,通常在 WPF 中,当人们想要强制某些控件刷新其命令 CanExecuted 时,他们使用 CommandManager.RequerySuggested 事件和 CommandManager.InvalidateRequerySuggested 方法。但是我不喜欢那样,也从不那样做,因为它非常低效(所以我不会详细介绍)。所以,我认为最好的方法是:

public class DelegateCommand : ICommand {
    private readonly Action<object> _execute;
    private readonly Predicate<object> _canExecute;

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

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

    public void Execute(object parameter) {
        _execute(parameter);
    }

    public void RefreshCanExecute() {
        var handler = CanExecuteChanged;
        if (handler != null)
            handler(this, EventArgs.Empty);
    }

    public event EventHandler CanExecuteChanged;
}

然后当事情发生变化时,只需调用 DelegateCommand.RefreshCanExecute:

    public partial class MainWindow : Window {
    public MainWindow() {
        InitializeComponent();
        this.BtnCommand = new DelegateCommand(_ => {
            MessageBox.Show("test");
        }, _ => CheckCanExecute());
        this.DataContext = this;            
    }

    private bool CheckCanExecute() {
        return SomeProperty == 1;
    }

    public int SomeProperty
    {
        get { return (int) GetValue(SomePropertyProperty); }
        set { SetValue(SomePropertyProperty, value); }
    }

    public static readonly DependencyProperty SomePropertyProperty =
        DependencyProperty.Register("SomeProperty", typeof(int), typeof(MainWindow), new PropertyMetadata(0, OnSomePropertyChanged));

    private static void OnSomePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
        ((MainWindow) d).BtnCommand.RefreshCanExecute();
    }

    public DelegateCommand BtnCommand { get; private set; }      
}

Xaml:

<Button Content="test" Command="{Binding BtnCommand}" />

编辑以回应评论。当然你可以绑定到多个属性,它只是与命令无关,所以我没有意识到你对此感兴趣。你可以这样做 - 首先创建多值转换器:

public class AndConverter : IMultiValueConverter {
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
        if (values.Length == 0) return false;
        return values.All(c => c != null && c != DependencyProperty.UnsetValue && (bool) c);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
        throw new NotImplementedException();
    }
}

它接受多个布尔值(null 被视为 false)并对它们进行求值。现在 xaml 只需将按钮的 IsEnabled 绑定到您的模型属性:

<Window.Resources>
    <wpf:AndConverter x:Key="and" />
</Window.Resources>
<Button Content="test" Command="{Binding BtnCommand}">
    <Button.IsEnabled>
        <MultiBinding Converter="{StaticResource and}">
            <Binding Path="IsFirstPage" />
            <Binding Path="CanGoToPrevious" />
        </MultiBinding>
    </Button.IsEnabled>
</Button>

现在,当任何绑定属性发生变化时,您的转换器将被重新评估并刷新按钮的 IsEnabled 属性。