2017-02-25 2 views
1

ICommandインターフェイスを使用し、CommandとCommandParameters(または単にコマンド)を介してコントロールにバインドすると、ボタン/コントロールが自動的に有効/使用されている値が変更されると無効になります(CanExecuteを呼び出します)。ICommandでUpdateCanExecute/CanExecuteをマルチプレックスモデル用に簡単に管理する方法

+0

Stack Overflowに関する質問は、適切な時に 'CanExecuteChanged'を確実にするためのさまざまな戦略について議論しています。マークされた複製など。 https://stackoverflow.com/questions/7350845/canexecute-logic-for-delegatecommand、https://stackoverflow.com/questions/6425923/canexecutechanged-event-of-icommand、https://stackoverflow.com/も参照してください。質問/ 30002300/how-to-use-canexecute-method-icommand-on-wpfhttps:// stackoverflowを参照してください。com/questions/14479303/icommand-canexecute-not-triggered-after-propertychanged ... –

+0

https://stackoverflow.com/questions/31078633/wpf-icommand-canexecute-raisecanexecutechanged-or-automatic-handling-via -di。あなたの質問は、既に書かれたすべてのものの再ハッシュか、まったく広範なStack Overflowの質問です。あなたの質問はあなたのウェブページへのリンクを投稿する単なる言い訳ではないと考えてみましょう。あなたが本当に助けたいと思う質問がある場合は、より具体的な新しい質問を投稿してください。これには良い[mcve]とあなたが解決しようとしている解決策の詳細な説明が含まれています。 –

+0

@PeterDunihoあなたのための上記のコメント。 –

答えて

0

ここに興味のある人は、RelayCommandを介してICommandを常に必要に応じて強制的に更新する少しのレポがあります。これは実用的なIMOになるビューで余分な作業を必要としません。

Auto Relay Command Example

中継コマンドは容易のICommandインターフェースを自動化する方法の一例であり、全ての溶液修正することを意味するものではありません。

ここRelayCommand

public class RelayCommand : ICommand 
{ 
    private readonly RelayCommandBindings relayCommandBindings; 
    public event EventHandler CanExecuteChanged; 

    internal RelayCommand(RelayCommandBindings relayCommandBindings) 
    { 
     this.relayCommandBindings = relayCommandBindings; 

     relayCommandBindings.BindingModel.PropertyChanged += (s, e) => 
     { 
      if (relayCommandBindings.BindingProperties.Any(p => p == e.PropertyName)) 
       CanExecuteChanged?.Invoke(this, EventArgs.Empty); 
     }; 
    } 

    public bool CanExecute(object parameter) => (relayCommandBindings.CanExecuteChecks?.All(p => p.Invoke(parameter))).GetValueOrDefault(); 
    public void Execute(object parameter) => relayCommandBindings?.Execute?.Invoke(parameter); 
} 

ここでは、ここでRelayCommandBindings

internal class RelayCommandBindings 
{ 
    public Action<object> Execute { get; set; } 
    public IEnumerable<Predicate<object>> CanExecuteChecks { get; set; } 
    public INotifyPropertyChanged BindingModel { get; set; } 
    public IEnumerable<string> BindingProperties { get; set; } 
} 

ですViewModelに

public class MultiplexViewModel : INotifyPropertyChanged 
{ 
    private const string NoName = "(no name)"; 
    private bool isActive; 
    private bool isActiveChanging; 
    private string name; 
    private readonly MultiPlexModel multiPlexModel; 
    private readonly SynchronizationContext synchronizationContext; 

    public MultiplexViewModel() 
    { 
     multiPlexModel = new MultiPlexModel(); 
     synchronizationContext = SynchronizationContext.Current; 

     var bindingProperties = new[] 
     { 
      nameof(IsActive), 
      nameof(IsActiveChanging) 
     }; 

     var setNewNameBindings = new RelayCommandBindings() 
     { 
      Execute = async (obj) => await multiPlexModel.StartMultiplexModelAsync(obj.ToString()), 
      CanExecuteChecks = new List<Predicate<object>> 
      { 
       (obj) => IsValidName(obj?.ToString()), 
       (obj) => IsActive == false, 
       (obj) => IsActiveChanging == false 
      }, 
      BindingModel = this, 
      BindingProperties = bindingProperties 
     }; 

     var stopMultiplexBindings = new RelayCommandBindings() 
     { 
      Execute = async (obj) => await multiPlexModel.StopMultiplexModelAsync(), 
      CanExecuteChecks = new List<Predicate<object>> 
      { 
       (obj) => IsActive == true, 
       (obj) => IsActiveChanging == false 
      }, 
      BindingModel = this, 
      BindingProperties = bindingProperties 
     }; 

     SetNewNameCommand = new RelayCommand(setNewNameBindings); 
     StopMultiplexCommand = new RelayCommand(stopMultiplexBindings); 

     multiPlexModel.PropertyChanged += (s, e) => GetType().GetProperties().Where(p => p.Name == e.PropertyName).FirstOrDefault()?.SetValue(this, multiPlexModel.GetType().GetProperty(e.PropertyName).GetValue(multiPlexModel)); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    public void Notify([CallerMemberName] string propertyName = "") => synchronizationContext.Post((o) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)), null); 

    public bool IsActive 
    { 
     get { return isActive; } 
     private set 
     { 
      isActive = value; 
      Notify(); 
     } 
    } 

    public bool IsActiveChanging 
    { 
     get { return isActiveChanging; } 
     private set 
     { 
      isActiveChanging = value; 
      Notify(); 
     } 
    } 

    public string Name 
    { 
     get { return string.IsNullOrEmpty(name) ? NoName : name; } 
     private set 
     { 
      name = value; 
      Notify(); 
     } 
    } 

    private bool IsValidName(string name) => (name?.StartsWith("@")).GetValueOrDefault(); 
    public RelayCommand SetNewNameCommand { get; private set; } 
    public RelayCommand StopMultiplexCommand { get; private set; } 
} 

ここでは、モデル

public class MultiPlexModel : INotifyPropertyChanged 
{ 
    private bool isActive; 
    private bool isActiveChanging; 
    private string name; 

    public event PropertyChangedEventHandler PropertyChanged; 
    public void Notify([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 

    public bool IsActive 
    { 
     get { return isActive; } 
     private set 
     { 
      isActive = value; 
      Notify(); 
     } 
    } 

    public bool IsActiveChanging 
    { 
     get { return isActiveChanging; } 
     private set 
     { 
      isActiveChanging = value; 
      Notify(); 
     } 
    } 

    public string Name 
    { 
     get { return name; } 
     private set 
     { 
      name = value; 
      Notify(); 
     } 
    } 

    public async Task StartMultiplexModelAsync(string newName) 
    { 
     await Task.Run(async() => 
     { 
      if (IsActiveChanging) 
       return; 

      IsActiveChanging = true; 
      await Task.Delay(2000); 

      Name = newName; 
      IsActive = true; 
      IsActiveChanging = false; 
     }); 
    } 

    public async Task StopMultiplexModelAsync() 
    { 
     await Task.Run(async() => 
     { 
      if (IsActiveChanging) 
       return; 

      IsActiveChanging = true; 
      await Task.Delay(2000); 

      Name = string.Empty; 
      IsActive = false; 
      IsActiveChanging = false; 
     }); 
    } 

} 
です

そして、ここに新しい名前を設定するために

<UserControl.DataContext> 
    <ViewModels:MultiplexViewModel /> 
</UserControl.DataContext> 

<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 

    <TextBlock Text="Auto Relay Command Example" 
       Margin="12, 40, 12, 12" 
       FontSize="32" 
       TextWrapping="Wrap" /> 

    <TextBlock Text="The purpose of this application is to demonstrate a method for automatically activating CanExecute in ICommand. This automatically triggers buttons to become enabled/disabled based on various binding properties at once." 
       Margin="12" 
       TextWrapping="Wrap" /> 

    <TextBlock Text="The name of the multiplex can only be set once if it starts with the @ symbol and the multiplex is not active." 
       Margin="12" 
       TextWrapping="Wrap" /> 

    <TextBlock Text="The multiplex is started when the name is being properly set. At that time the multiplex cannot be altered... once it is set it cannot be reset until it has been stopped." 
       Margin="12" 
       TextWrapping="Wrap" /> 

    <TextBlock Text="There is no code behind, triggers, converters, or other tricks used to make this work. This is purely binding to the commands in the ViewModel. The magic is in the RelayCommand and RelayCommandBindings in the ViewModels namespace." 
       Margin="12" 
       TextWrapping="Wrap" /> 

    <TextBox Name="TextBoxName" 
      Text="{Binding Name, Mode=OneWay}" 
      Margin="12" /> 

    <Button Content="Set New Name" 
      Margin="12" 
      Command="{Binding SetNewNameCommand}" 
      CommandParameter="{Binding Text, ElementName=TextBoxName}" /> 

    <Button Content="Stop Multiplex" 
      Margin="12" 
      Command="{Binding StopMultiplexCommand}" /> 

    <StackPanel Margin="12"> 
     <TextBlock Text="Multiplex Changing" /> 
     <TextBlock Text="{Binding IsActiveChanging}" /> 
    </StackPanel> 

    <StackPanel Margin="12"> 
     <TextBlock Text="Multiplex Active" /> 
     <TextBlock Text="{Binding IsActive}" /> 
    </StackPanel> 

    <StackPanel Margin="12"> 
     <TextBlock Text="Multiplex Name" /> 
     <TextBlock Text="{Binding Name}" /> 
    </StackPanel> 

</StackPanel> 

イメージ---------

Start

Name Edit

ここでボタンが有効になっているビュー..です。

ここでは...

Name Set

ここで名前が設定され、[停止]ボタンが有効になっている...

Stopping Multiplex

、一旦停止を活性化しながら、ここではボタンが再び無効になっている

、ビューは開始に戻ります。この例では

Stopped

あなたはビューでは、IMO、あるべき姿を結合まっすぐ進むのコマンドを使用して、ビューのトーンを設定するさまざまなプロパティを参照してください。ちょうどこれが助けになると思った...

+0

@PeterDuniho人々がGit Repoを使いたいのであれば、気にする必要はありません。私は例を書いて時間を費やしていたので、純粋なMVVMアーキテクチャーでCanExecuteを修正する複数の変数を処理しようとしている人を助けるためだけにデモが動作するのを見ることができました。レポは単に洞察力/助けを提供することに過ぎず、他の目的のために維持することは全く役に立たない。 –

関連する問題