当使用ICommand接口并绑定到通过Command和CommandParameters(或者只是命令)的控件时,通常会意识到按钮/控件不会自动变为启用/禁用(调用CanExecute)当正在使用的值更改。如何使用ICommand轻松管理UpdateCanExecute/CanExecute for Multiplex模型
1
A
回答
0
只要有人在这里感兴趣的是一个小回购,迫使ICommand随时根据需要通过RelayCommand进行更新。这不需要在视图中做出额外的工作,这使得IMO成为现实。
中继命令仅仅是如何容易自动化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>
图片---------
这里的按钮来设置新名称启用.. 。
个这里的按钮,同时激活再次禁用...
这里名称设置和停止按钮被激活......
这里,一旦停止,视图又回到了开始。
在这个例子中,你看到不同的属性设置有直线前进命令,在视图的方式应该是结合,IMO观的基调。只是认为这会有所帮助...
+0
@PeterDuniho如果人们想要使用Git Repo,我可以不在乎。我花时间写这个例子,所以人们可以看到这个演示工作,只是为了帮助任何可能被抓到的人尝试处理在纯MVVM架构中修改CanExecute的多个变量。回购只是为了提供见解/帮助,并且完全没有用于维护任何其他目的。 –
相关问题
- 1. 如何轻松地处理在WPF
- 2. 如何轻松打印数字三角形?使用for循环:)
- 3. 如何使用python轻松过滤csv?
- 4. 使用Spring JDBC轻松处理事务?
- 5. 轻松访问模型领域
- 6. 轻松放入模型旋转
- 7. 轻松处理json对象
- 8. 如何在Django项目中轻松包含日历管理模块
- 9. 如何更轻松地使用reCAPTCHA?
- 10. 使用Github轻松部署?
- 11. 如何轻松地在Eclipse中创建模型/ UML?
- 12. 如何轻松测试Yii模型中的文件上传?
- 13. 使用轻灵还是不轻松?
- 14. 我应该如何使用Flask-SQLAlchemy,以便轻松添加新模型?
- 15. 如何使用Repository模式让ORM轻松切换?
- 16. 如何更轻松地使用IOS模拟器位置?
- 17. 如何轻松复制Loopback JS中的模型和相关模型
- 18. 使用servlets轻松连接
- 19. 如何轻松测试android
- 20. vmware如何轻松安装?
- 21. 如何从JSON update_attributes方法轻松
- 22. 如何用awk轻松过滤日志?
- 23. 如何使用ICommand更改模型的属性?
- 24. 如何轻松地使用CodeIgniter进行单元测试?
- 25. 如何处理python导入,使他们可以轻松地使用py2和py3?
- 26. 如何轻松禁用fancybox幻灯片?
- 27. 如何轻松禁用cron作业?
- 28. 如何轻松访问class setter?
- 29. 在expressjs中轻松使用助手类
- 30. 如何使用Spring轻松使用JSP页面作为电子邮件模板?
有堆栈溢出的问题已经讨论了确保'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 ... –
https://stackoverflow.com/questions/31078633/wpf-icommand-canexecute-raisecanexecutechanged-or-automatic-handling-via - 二。你的问题不是重写所有已经写好的东西,就是堆栈溢出的一个太宽泛的问题(让我们暂时假设你的问题不仅仅是发布链接到你的网页的借口)。如果你确实有一个问题需要帮助,请发布一个更具体的新问题,其中包括一个好的[mcve],并详细说明你正在尝试解决的问题,而你不能。 –
@PeterDuniho上面为您评论。 –