2016-06-21 7 views
1

MVVM-Lightに問題があります。私はメッセージボックスを使用しますが、私の場合には、読み込むメソッドを呼び出しバージョン5.3.0.0 ...MVVM-Light - RelayCommand CantExecute issue

の.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> 

DownloadViewModel.cs

を使用しますXML。この例は機能しません。ボタンは無効になっていますが、実行の最後には再アクティブ化されません。アクティブ化するにはUIをクリックする必要があります。 CommandManager.InvalidateRequerySuggested()を使用することにより

using GalaSoft.MvvmLight; 
using GalaSoft.MvvmLight.CommandWpf; 

private async void Download() 
{ 
    Reset(); 

    await Task.Run(() => 
    { 
     MessageBox.Show("Hello"); 
    }); 

    Reset(); 
} 

private void Reset() 
{ 
    IsEnabled = !IsEnabled; 
    IsEnabledCancel = !IsEnabledCancel; 
} 

private ICommand _downloadCommand; 
public ICommand DownloadCommand 
{ 
    get { return _downloadCommand ?? (_downloadCommand = new RelayCommand(Download,() => IsEnabled)); } 
} 

private ICommand _cancelDownloadCommand; 
public ICommand CancelDownloadCommand 
{ 
    get 
    { 
     return _cancelDownloadCommand ?? 
       (_cancelDownloadCommand = new RelayCommand(CancelDownload,() => IsEnabledCancel)); 
    } 
} 

private bool _isEnabled = true; 
private bool IsEnabled 
{ 
    get { return _isEnabled; } 
    set 
    { 
     if (_isEnabled != value) 
     { 
      _isEnabled = value; 
      RaisePropertyChanged(); 
     } 
    } 
} 

private bool _isEnabledCancel; 
private bool IsEnabledCancel 
{ 
    get { return _isEnabledCancel; } 
    set 
    { 
     if (_isEnabledCancel != value) 
     { 
      _isEnabledCancel = value; 
      RaisePropertyChanged(); 
     } 
    } 
} 

、私はそれを修正。しかし、このコマンドはすべてのRelayCommandをチェックするため、推奨されていない場所を読んでください。これは以前は私には起こりませんでした。

ただし、Task.Run内に何も追加しない場合。それは完全に動作します。ボタンは再び有効化され、無効化されます。私は予告をした

private async void Download() 
{ 
    Reset(); 

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

    Reset(); 
} 

答えて

0

ことの一つは、彼らがpublicあるべきときにEnabledプロパティ(でIsEnabled、IsEnabledCancel)がprivateであるということです。しかし、簡単な修正は、例えば

public ICommand DownloadCommand 
{ 
    get { return _downloadCommand ?? (_downloadCommand = new RelayCommand(Download)); } 
} 

とXAML などでButton.IsEnabled財産上のプロパティにバインドあなたのコマンドのCanExecute一部 を取り除くことであるあなたの問題を解決しない:)

<Button IsEnabled="{Binding IsEnabled}" Margin="5" VerticalAlignment="Top" 
     HorizontalAlignment="Center" Command="{Binding DownloadCommand}" 
     FontSize="20" Background="Transparent" BorderThickness="2" 
     BorderBrush="Red" ToolTip="Descargar" DockPanel.Dock="Right"> 
    ... 
</Button> 

あなたが更新すると

1

を役に立てば幸いCanExecute、あなたの場合IsEnabledIsEnabledCancelのプロパティでは、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)); } 
} 

A smart MVVM command」について読むこともできます。

1

source code for MVVM Lightを見ると、CommandManager.InvalidateRequerySuggested()(アンチ)パターンをベースにしています。あなたが正しく言っているのは、(反)パターンのグローバルな性質のために、大規模なパフォーマンスの豚です。

問題はコンストラクタにあります。canExecuteFunc<bool>された状態でpublic RelayCommand(Action execute, Func<bool> canExecute)

、(実行時に)プロパティ名を取得できるようにすることは不可能である、とINotifyPropertyChanged.PropertyChangedイベントにバインドすることは不可能です。したがって、コマンドはcanExecuteを再評価します。

@kubakistaはRaiseCanExecuteChangedメソッドを呼び出すことによって再評価を強制する方法を示します。しかし、それは本当に単一の責任の原則を破り、ICommandの実装を漏らします。

私の助言はReactiveUIReactiveCommandです。これにより、次の操作を実行できます。

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(); 
    } 
} 
関連する問題