Wpf MVVM指示灯-中继命令无法执行问题

Wpf MVVM指示灯-中继命令无法执行问题,wpf,mvvm-light,Wpf,Mvvm Light,我的MVVM灯有问题。我使用版本5.3.0.0 .XAML <DockPanel Dock="Top"> <Button Margin="5" VerticalAlignment="Top" HorizontalAlignment="Center" Command="{Binding CancelDownloadCommand}" FontSize="20" Background="Transparent" BorderThic

我的MVVM灯有问题。我使用版本5.3.0.0

.XAML

<DockPanel Dock="Top">
        <Button Margin="5" VerticalAlignment="Top" HorizontalAlignment="Center" Command="{Binding CancelDownloadCommand}" FontSize="20" 
                Background="Transparent" BorderThickness="2" BorderBrush="{StaticResource AccentColorBrush4}" ToolTip="Cancelar"
                DockPanel.Dock="Right">
            <StackPanel Orientation="Horizontal">
                <Image Source="Images/48x48/Error.png" Height="48" Width="48"/>
                <Label Content="{Binding ToolTip, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" FontFamily="Segoe UI Light"/>
            </StackPanel>
        </Button>
        <Button Margin="5" VerticalAlignment="Top" HorizontalAlignment="Center" Command="{Binding DownloadCommand}" FontSize="20" 
                Background="Transparent" BorderThickness="2" BorderBrush="{StaticResource AccentColorBrush4}" ToolTip="Descargar"
                DockPanel.Dock="Right">
            <StackPanel Orientation="Horizontal">
                <Image Source="Images/48x48/Download.png" Height="48" Width="48"/>
                <Label Content="{Binding ToolTip, RelativeSource={RelativeSource AncestorType={x:Type Button}}}" FontFamily="Segoe UI Light"/>
            </StackPanel>
        </Button>
    </DockPanel>
通过使用CommandManager.invalidateRequestSuggested(),我修复了它。但请阅读不推荐的地方,因为此命令检查所有RelayCommand。这以前没有发生在我身上

但如果在任务内,请运行,不要添加任何内容。它工作得很好。按钮被再次激活和停用

private async void Download()
{
    Reset();

    await Task.Run(() =>
    {
        // WIDTHOUT CODE
        // WIDTHOUT CODE
        // WIDTHOUT CODE
    });

    Reset();
}

我注意到的一点是,您的
已启用
属性(IsEnabled,IsEnabledCancel)是
私有的
,而它们应该是
公共的
。但是,这并不能解决您的问题:)

一个简单的修复方法是去掉命令中的
CanExecute
部分 乙二醇

并在
按钮上绑定到您的属性。我在xaml中启用了
属性
乙二醇


...

希望这有助于

当您更新
CanExecute
时,在您的情况下
IsEnabled
IsEnabledCancel
属性,您必须引发
CanExecuteChanged
事件

更重要的是,您可以稍微简化您的代码

private bool _isEnabled;

public bool IsEnabled
{
    get { return _isEnabled; }
    set
    {
        if (Set(ref _isEnabled, value))
        {
            DownloadCommand.RaiseCanExecuteChanged();
        }
    }
}
同样的方法更新您的
IsEnabledCancel
属性

当然,您必须将命令声明为
RelayCommand
,而不是
ICommand

private RelayCommand _downloadCommand;

public RelayCommand DownloadCommand
{
    get { return _downloadCommand ?? (_downloadCommand = new RelayCommand(Download, () => IsEnabled)); }
}
您还可以阅读:“。

查看,它基于
CommandManager.invalidateRequestSuggested()
(反)模式。由于(反)模式的全球性,你正确地说这是一个巨大的性能猪

问题在于构造函数<代码>公共RelayCommand(操作执行,函数执行)

由于
canExecute
Func
,因此无法(在运行时)获取属性名,因此无法绑定
INotifyPropertyChanged.PropertyChanged
事件。从而导致命令重新评估
canExecute

@kubakista向您展示了如何通过调用
RaiseCanExecuteChanged
方法强制重新评估。但这确实打破了单一责任原则,泄露了
ICommand
的实现

private RelayCommand _downloadCommand;

public RelayCommand DownloadCommand
{
    get { return _downloadCommand ?? (_downloadCommand = new RelayCommand(Download, () => IsEnabled)); }
}
我的建议是使用
ReactiveUI
ReactiveCommand
。这允许您执行以下操作:

DownloadCommand = ReactiveCommand.Create(Download, this.WhenAnyValue(x => x.IsEnabled).Select(enabled => enabled));
CancelDownloadCommand = ReactiveCommand.Create(CancelDownload, this.WhenAnyValue(x => x.IsEnabled).Select(enabled => false == enabled));


public bool IsEnabled
{ 
    get {return _isEnabled; } 
    set
    {
        _isEnabled = value;
        OnPropertyChanged();
    }
}
另请参见和中解释的错误
private RelayCommand _downloadCommand;

public RelayCommand DownloadCommand
{
    get { return _downloadCommand ?? (_downloadCommand = new RelayCommand(Download, () => IsEnabled)); }
}
DownloadCommand = ReactiveCommand.Create(Download, this.WhenAnyValue(x => x.IsEnabled).Select(enabled => enabled));
CancelDownloadCommand = ReactiveCommand.Create(CancelDownload, this.WhenAnyValue(x => x.IsEnabled).Select(enabled => false == enabled));


public bool IsEnabled
{ 
    get {return _isEnabled; } 
    set
    {
        _isEnabled = value;
        OnPropertyChanged();
    }
}