这是MVVM应用程序.有一个窗口和相关的视图模型类.
还有TextBox,Button和ListBox对形式.按钮绑定到DelegateCommand具有CanExecute功能.想法是用户在文本框中输入一些数据,按下按钮并将数据附加到列表框中.
我想在用户输入正确的数据时启用命令(和按钮)TextBox.事情现在就像这样:
CanExecute() method包含用于检查绑定到文本框的属性中的数据是否正确的代码.UpdateSourceTrigger设置为,PropertyChanged并在每个关键用户按下后更新视图模型中的属性. 问题是CanExecute()用户在文本框中输入数据时不会触发.即使文本框失去焦点,它也不会触发.
我怎么能做这个工作?
编辑:
Re Yanko的评论:
Delegate命令在MVVM工具包模板中实现,当您创建新的MVVM项目时,解决方案中有Delegate命令.就像我在Prism视频中看到的那样,这应该是同一个类(或者至少非常相似).
这是XAML片段:
...
<UserControl.Resources>
<views:CommandReference x:Key="AddObjectCommandReference"
Command="{Binding AddObjectCommand}" />
</UserControl.Resources>
...
<TextBox Text="{Binding ObjectName, UpdateSourceTrigger=PropertyChanged}"> </TextBox>
<Button Command="{StaticResource AddObjectCommandReference}">Add</Button>
...
Run Code Online (Sandbox Code Playgroud)
查看型号:
// Property bound to textbox
public string ObjectName
{
get { return objectName; }
set {
objectName = value;
OnPropertyChanged("ObjectName");
}
}
// Command bound to button
public ICommand AddObjectCommand
{
get
{
if (addObjectCommand == null)
{
addObjectCommand = new DelegateCommand(AddObject, CanAddObject);
}
return addObjectCommand;
}
}
private void AddObject()
{
if (ObjectName == null || ObjectName.Length == 0)
return;
objectNames.AddSourceFile(ObjectName);
OnPropertyChanged("ObjectNames"); // refresh listbox
}
private bool CanAddObject()
{
return ObjectName != null && ObjectName.Length > 0;
}
Run Code Online (Sandbox Code Playgroud)
正如我在问题的第一部分写的那样,关注事情:
ObjectName在文本框中的每个按键上触发return true;输入CanAddObject(),命令是活动的(按钮到)在我看来,绑定是正确的.
我不知道的是如何从上面的代码中CanExecute()取得ObjectName财产的制造者.
Re Ben和Abe的答案:
CanExecuteChanged() 是事件处理程序和编译器抱怨:
事件'System.Windows.Input.ICommand.CanExecuteChanged'只能出现在+ =或 - =的左侧
只有两个成员ICommand:Execute()和CanExecute()
你有一些例子说明如何进行命令调用CanExecute().
我找到了命令管理器助手类DelegateCommand.cs,我会调查它,也许有一些机制可以提供帮助.
无论如何,想法为了激活基于用户输入的命令,需要在属性设置器代码中"轻推"命令对象看起来很笨拙.它将引入依赖关系,MVVM的一个重点是减少它们.
编辑2:
我尝试激活CanExecute调用addObjectCommand.RaiseCanExecuteChanged(),以ObjectName从上面的代码中的属性设置.这也无济于事.CanExecute()在初始化表单时会被触发几次,但之后它永远不会被再次执行.这是代码:
// Property bound to textbox
public string ObjectName
{
get { return objectName; }
set {
objectName = value;
addObjectCommand.RaiseCanExecuteChanged();
OnPropertyChanged("ObjectName");
}
}
Run Code Online (Sandbox Code Playgroud)
编辑3:解决方案
正如Yanko Yankov和JerKimball所写,问题是静态资源.当我改变像Yanko建议的按钮绑定时:
<Button Command="{Binding AddObjectCommand}">Add</Button>
Run Code Online (Sandbox Code Playgroud)
事情立即开始起作用.我甚至都不需要RaiseCanExecuteChanged().现在CanExecute自动开火.
为什么我首先使用静态资源?
原始代码来自WPF MVVM工具包手册.该手册中的示例将命令定义为静态资源,然后将其绑定到菜单项.区别在于我的示例中不是字符串属性,而是MVVM手册ObservableCollection.
编辑4:最终解释
我终于明白了.我需要做的就是在CommandReference课堂上阅读评论.它说:
/// <summary>
/// This class facilitates associating a key binding in XAML markup to a command
/// defined in a View Model by exposing a Command dependency property.
/// The class derives from Freezable to work around a limitation in WPF when
/// databinding from XAML.
/// </summary>
Run Code Online (Sandbox Code Playgroud)
因此,CommandReference用于KeyBinding,它不是用于视觉元素的绑定.在上面的代码中,资源中定义的命令引用适用于KeyBinding,我在此用户控件上没有.
当然,WPF MVVM工具包附带的示例代码是正确的,但我误读了它并用于CommandReference可视元素绑定.
这个WPF MVVM有时候真的很棘手.
经过编辑,事情现在看起来更加清晰了,谢谢!这可能是一个愚蠢的问题(我有点厌倦了一整天的工作),但是为什么不直接绑定到命令,而不是通过静态资源呢?
<Button Command="{Binding AddObjectCommand}">Add</Button>
Run Code Online (Sandbox Code Playgroud)