2017-02-25 24 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的多个变量。回购只是为了提供见解/帮助,并且完全没有用于维护任何其他目的。 –