RelayCommand 未触发 CanExecute
我正在尝试创建一个绑定到按钮的命令,并依赖于视图模型的层次结构来表示 wp7 应用程序中的枢轴和枢轴项目。它是这样的(我将省略尽可能多的样板代码):
父视图模型:
public RelayCommand RefreshCommand
{
get
{
return _refreshCommand;
}
set
{
if (_refreshCommand == value)
{
return;
}
var oldValue = _refreshCommand;
_refreshCommand = value;
// Update bindings, no broadcast
RaisePropertyChanged(RefreshCommandPropertyName);
}
}
public RelayCommand<RoutedEventArgs> LoadedCommand
{
get
{
Action<RoutedEventArgs> getCurrentViewmodel = (args) =>
{
CurrentViewModel = SearchByLocationViewModel; // maybe something better...
RefreshCommand = CurrentViewModel.RefreshResultsCommand;
RefreshCommand.RaiseCanExecuteChanged();
};
return new RelayCommand<RoutedEventArgs>(getCurrentViewmodel);
}
}
public RelayCommand<SelectionChangedEventArgs> PivotItemChangedCommand
{
get
{
Action<SelectionChangedEventArgs> pivotChanged = (args) =>
{
if (args != null)
{
// update current viewmodel
CurrentViewModel = ((Microsoft.Phone.Controls.PivotItem) args.AddedItems[0]).DataContext as ISearchViewModelBase;
RefreshCommand = CurrentViewModel.RefreshResultsCommand;
}
};
return new RelayCommand<SelectionChangedEventArgs>(pivotChanged);
}
}
因此,我在每次加载时将父视图模型的 RefreshCommand 属性设置为子命令,并且在选定时执行相同的操作枢轴项更改。
Xaml
<Button Command="{Binding RefreshCommand}" />
Child viewmodel
public Func<bool> CanRefresh
{
get { return () => !IsLoading; }
}
private RelayCommand refreshResultsCommand;
public RelayCommand RefreshResultsCommand
{
get
{
Action doRefresh = () =>
{
SearchResults.Clear();
this._pageNumber = 0;
AddItems();
};
return refreshResultsCommand = refreshResultsCommand ?? new RelayCommand(doRefresh, CanRefresh);
}
}
发生的情况是,CanRefresh 永远不会被调用。这些命令工作正常,具体取决于它调用一个 AddItems (这是在每个子视图模型中以不同方式实现的虚拟方法)或另一个的枢轴项,但就像永远不会引发 CanExecute 一样。我正在使用 MVVM Light 工具包。 谢谢!
I'm trying to create a command that binds to a button, and depends on a hierarchy of viewmodels to represent a pivot and pivotitems in a wp7 app. It goes something like this (i'll omit as much boilerplate code as possible):
Parent viewmodel :
public RelayCommand RefreshCommand
{
get
{
return _refreshCommand;
}
set
{
if (_refreshCommand == value)
{
return;
}
var oldValue = _refreshCommand;
_refreshCommand = value;
// Update bindings, no broadcast
RaisePropertyChanged(RefreshCommandPropertyName);
}
}
public RelayCommand<RoutedEventArgs> LoadedCommand
{
get
{
Action<RoutedEventArgs> getCurrentViewmodel = (args) =>
{
CurrentViewModel = SearchByLocationViewModel; // maybe something better...
RefreshCommand = CurrentViewModel.RefreshResultsCommand;
RefreshCommand.RaiseCanExecuteChanged();
};
return new RelayCommand<RoutedEventArgs>(getCurrentViewmodel);
}
}
public RelayCommand<SelectionChangedEventArgs> PivotItemChangedCommand
{
get
{
Action<SelectionChangedEventArgs> pivotChanged = (args) =>
{
if (args != null)
{
// update current viewmodel
CurrentViewModel = ((Microsoft.Phone.Controls.PivotItem) args.AddedItems[0]).DataContext as ISearchViewModelBase;
RefreshCommand = CurrentViewModel.RefreshResultsCommand;
}
};
return new RelayCommand<SelectionChangedEventArgs>(pivotChanged);
}
}
So, i'm setting the parent view model's RefreshCommand property to the child command each time it loads, and I do the same when the selected pivotitem changes.
Xaml
<Button Command="{Binding RefreshCommand}" />
Child viewmodel
public Func<bool> CanRefresh
{
get { return () => !IsLoading; }
}
private RelayCommand refreshResultsCommand;
public RelayCommand RefreshResultsCommand
{
get
{
Action doRefresh = () =>
{
SearchResults.Clear();
this._pageNumber = 0;
AddItems();
};
return refreshResultsCommand = refreshResultsCommand ?? new RelayCommand(doRefresh, CanRefresh);
}
}
What happens is, the CanRefresh is NEVER called. The commands work fine, depending on the pivotitem it calls one AddItems (that's a virtual method implemented differently in each child viewmodel) or the other, but it's like CanExecute is never raised. I'm using MVVM Light toolkit.
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我怀疑
CanExecute
方法永远不会被调用,因为RelayCommand
的CanExecuteChanged
事件永远不会在视图模型对象上触发view-layer 当前绑定到。由于您要在大多数属性访问上创建命令,因此有很多命令,并且很可能您在尚未被视图层绑定的命令或未绑定的命令上触发事件不再束缚。我从未见过有人在每次调用属性 getter 时创建新命令。您可以尝试在构造函数中创建一次命令,而不是在每个属性访问中创建命令,然后看看是否可以解决问题?
I suspect that the
CanExecute
method is never being called because theCanExecuteChanged
event of theRelayCommand
is never being fired on a view-model object that the view-layer is currently bound to. Since you're creating commands on most property accesses, there are a lot of commands about, and it's quite possible that you're firing the event on a command that isn't yet bound to by the view-layer or one that is no longer bound to.I've never seen anyone create new commands every time the property getter is called. Could you try creating the commands once in a constructor instead of on every property access instead, and see if that fixes things?
好吧,每次调用
LoadedCommand
和PivotChangedComman
属性时,您都会创建一个新的中继命令。由于 SL/WPF 非常频繁地调用这些属性,因此您必须确保每次调用该属性时都不会创建命令。实际上,您的RefreshResultsCommand
实现了正确的模式。确保正确实现属性/命令的最佳方法是使用 Laurent 的 MVVM片段。将它们下载到您的代码片段目录并使用它们。除了生成始终相同的样板代码并从而提高质量之外,它们还大大加快速度!
您可以使用安装程序来安装代码片段。
Well you are creating a new relay command everytime you call your
LoadedCommand
andPivotChangedComman
properties. As SL/WPF calls these properties quite frequently you have to ensue that you not create a command everytime the property is called. Actually yourRefreshResultsCommand
implements the correct pattern.The best way to ensure you implementing the properties/commands properly is to use Laurent's MVVM snippets. Download them to your snippet directory and just use them. Besides producing always the same boilerplate code and thus improving quality, they also speed up things considerably!
You can use the installer to install the snippets as well.