2017-02-25 42 views
1

當使用ICommand接口並綁定到通過Command和CommandParameters(或者只是命令)的控件時,通常會意識到按鈕/控件不會自動變爲啓用/禁用(調用CanExecute)當正在使用的值更改。如何使用ICommand輕鬆管理UpdateCanExecute/CanExecute for Multiplex模型

+0

有堆棧溢出的問題已經討論了確保'CanExecuteChanged'在適當的時候引發的各種策略。如標記重複。另見https://stackoverflow.com/questions/7350845/canexecute-logic-for-delegatecommand,https://stackoverflow.com/questions/6425923/canexecutechanged-event-of-icommand,https://stackoverflow.com/問題/ 30002300 /如何使用的最canexecute法外之ICommand的-ON-wpfhttps://計算器。com/questions/14479303/icommand-canexecute-not-triggering-after-propertychanged,and ... –

+0

https://stackoverflow.com/questions/31078633/wpf-icommand-canexecute-raisecanexecutechanged-or-automatic-handling-via - 二。你的問題不是重寫所有已經寫好的東西,就是堆棧溢出的一個太寬泛的問題(讓我們暫時假設你的問題不僅僅是發佈鏈接到你的網頁的藉口)。如果你確實有一個問題需要幫助,請發佈一個更具體的新問題,其中包括一個好的[mcve],並詳細說明你正在嘗試解決的問題,而你不能。 –

+0

@PeterDuniho上面爲您評論。 –

回答

0

只要有人在這裏感興趣的是一個小回購,迫使ICommand隨時根據需要通過RelayCommand進行更新。這不需要在視圖中做出額外的工作,這使得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; } 
} 

這裏是視圖模型

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

這裏的按鈕來設置新名稱啓用.. 。

Setting Name

這裏的按鈕,同時激活再次禁用...

Name Set

這裏名稱設置和停止按鈕被激活......

Stopping Multiplex

這裏,一旦停止,視圖又回到了開始。

Stopped

在這個例子中,你看到不同的屬性設置有直線前進命令,在視圖的方式應該是結合,IMO觀的基調。只是認爲這會有所幫助...

+0

@PeterDuniho如果人們想要使用Git Repo,我可以不在乎。我花時間寫這個例子,所以人們可以看到這個演示工作,只是爲了幫助任何可能被抓到的人嘗試處理在純MVVM架構中修改CanExecute的多個變量。回購只是爲了提供見解/幫助,並且完全沒有用於維護任何其他目的。 –