基于TextBox值(WPF)启用按钮

zen*_*dar 9 wpf command mvvm

这是MVVM应用程序.有一个窗口和相关的视图模型类.

还有TextBox,ButtonListBox对形式.按钮绑定到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)

正如我在问题的第一部分写的那样,关注事情:

  • 属性设置器for 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 YankovJerKimball所写,问题是静态资源.当我改变像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有时候真的很棘手.

iro*_*bot 4

经过编辑,事情现在看起来更加清晰了,谢谢!这可能是一个愚蠢的问题(我有点厌倦了一整天的工作),但是为什么不直接绑定到命令,而不是通过静态资源呢?

<Button Command="{Binding AddObjectCommand}">Add</Button>
Run Code Online (Sandbox Code Playgroud)