考虑参考Josh Smith的文章WPF Apps with Model-View-ViewModel Design Pattern,特别是a的示例实现RelayCommand(图3).(无需阅读整篇文章以了解此问题.)
在一般情况下,我想实现是优秀的,但我有一个代表团的问题CanExecuteChanged订阅到CommandManager的RequerySuggested事件.各州的文件RequerySuggested:
由于此事件是静态的,因此它只会作为弱引用保留在处理程序中.侦听此事件的对象应该对其事件处理程序保持强引用,以避免它被垃圾回收.这可以通过拥有私有字段并在附加到此事件之前或之后将处理程序指定为值来实现.
然而,示例实现RelayCommand不会对订阅的处理程序维护任何此类:
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
Run Code Online (Sandbox Code Playgroud)
RelayCommand客户端的漏洞,要求用户RelayCommand了解自己的实施CanExecuteChanged并维护一个实时参考?如果是这样,例如,修改实现RelayCommand类似于以下内容以减轻CanExecuteChanged订户的潜在过早GC 是否有意义:
// This event never actually fires. It's purely lifetime mgm't.
private event EventHandler canExecChangedRef;
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value; …Run Code Online (Sandbox Code Playgroud)调用CommandManager.InvalidateRequerySuggested()比我想要的更长时间才能生效(在UI控件被禁用之前1-2秒延迟).
我有一个系统,我将任务提交给基于后台线程的任务处理器.此提交发生在WPF UI线程上.
当这个提交发生时,管理我的后台线程的对象做了两件事:
它引发了一个"忙"事件(仍然在UI线程上),几个视图模型响应; 当他们收到这个事件时,他们IsEnabled会给自己设置一面旗帜false.我的视图中的控件(数据绑定到此属性)会立即显示为灰色,这正是我所期望的.
它通知我的WPF ICommand对象不应该允许它们执行(同样,仍然在UI线程上).因为没有像对象那样INotifyPropertyChanged的ICommand东西,我被迫调用CommandManager.InvalidateRequerySuggested()强制WPF重新考虑我的所有命令对象的CanExecute状态(是的,我实际上需要这样做:否则,这些控件都不会被禁用).但是,与第1项不同,我的按钮/菜单项/等使用ICommand对象在视觉上更改为禁用状态所需的时间要长得多,而对于IsEnabled手动设置其属性的UI控件则需要更长的时间.
问题是,从用户体验的角度来看,这看起来很糟糕 ; 我的一半控件立即显示为灰色(因为它们的IsEnabled属性设置为false),然后整整1-2秒后,我的控件的另一半跟随(因为他们的CanExecute方法最终被重新评估).
所以,我的问题的第一部分:
听起来很愚蠢,有没有办法让CommandManager.InvalidateRequerySuggested()我的工作更快?我怀疑没有.
很公平,我的问题的第2部分:
我如何解决这个问题?我希望我的所有控件都可以同时禁用.它只是看起来不专业而且很尴尬.有任何想法吗?:-)
在选项卡页面上的用户控件上的上下文菜单中绑定命令时遇到问题.我第一次使用菜单(右键单击选项卡)它工作得很好,但如果我切换选项卡,命令将使用第一次使用的数据绑定实例.
如果我在usercontrol中放置一个绑定到该命令的按钮,它按预期工作...
有人可以告诉我,我做错了什么?
这是一个暴露问题的测试项目:
App.xaml.cs:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
CompanyViewModel model = new CompanyViewModel();
Window1 window = new Window1();
window.DataContext = model;
window.Show();
}
}
Run Code Online (Sandbox Code Playgroud)
Window1.xaml:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vw="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<DataTemplate x:Key="HeaderTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type vw:PersonViewModel}">
<vw:UserControl1/>
</DataTemplate>
</Window.Resources>
<Grid>
<TabControl ItemsSource="{Binding Path=Persons}"
ItemTemplate="{StaticResource HeaderTemplate}"
IsSynchronizedWithCurrentItem="True" />
</Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)
UserControl1.xaml:
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MinWidth="200">
<UserControl.ContextMenu>
<ContextMenu > …Run Code Online (Sandbox Code Playgroud) 在查看 Josh Smith 关于 的文章时CommandGroup,我注意到互联网上有许多关于如何实施ICommand.CanExecuteChanged.
在 StackOverflow 上发布了一个类似的问题,但是
以供参考:
CommandGroupRelayCommand使用CommandManager 实现的CanExecuteChangedRoutedCommand使用CommandManager 实现的CanExecuteChanged我对 WPF 比较陌生,我想知道CanExecuteChanged应该如何在 Josh Smith's 中实现该事件CommandGroup以避免任何意外行为或内存泄漏?
Josh Smith:使用 CommandGroup 聚合 WPF 命令
Josh Smith:采用 MVVM 设计模式的 WPF 应用程序
StackOverflow:Josh Smith 的 RelayCommand 实现有缺陷吗?