基于 TextBox 值 (WPF) 启用按钮 [英] Enable button based on TextBox value (WPF)

查看:26
本文介绍了基于 TextBox 值 (WPF) 启用按钮的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

This is MVVM application. There is a window and related view model class.

表单上有TextBoxButtonListBox.按钮绑定到具有 CanExecute 功能的 DelegateCommand.想法是用户在文本框中输入一些数据,按下按钮并将数据附加到列表框.

There is TextBox, Button and ListBox on form. Button is bound to DelegateCommand that has CanExecute function. Idea is that user enters some data in text box, presses button and data is appended to list box.

当用户在 TextBox 中输入正确数据时,我想启用命令(和按钮).事情现在是这样的:

I would like to enable command (and button) when user enters correct data in TextBox. Things work like this now:

  • CanExecute() 方法包含检查绑定到文本框的属性中的数据是否正确的代码.
  • 文本框绑定到视图模型中的属性
  • UpdateSourceTrigger 设置为 PropertyChanged 并且视图模型中的属性在用户按下每个键后更新.
  • CanExecute() method contains code that checks if data in property bound to text box is correct.
  • Text box is bound to property in view model
  • UpdateSourceTrigger is set to PropertyChanged and property in view model is updated after each key user presses.

问题是当用户在文本框中输入数据时,CanExecute() 不会触发.即使文本框失去焦点也不会触发.

Problem is that CanExecute() does not fire when user enters data in text box. It doesn't fire even when text box lose focus.

我怎样才能做到这一点?

How could I make this work?


Re Yanko 的评论:
Delegate 命令在 MVVM 工具包模板中实现,当您创建新的 MVVM 项目时,解决方案中有 Delegate 命令.正如我在 Prism 视频中看到的那样,这应该是同一类(或至少非常相似).


Re Yanko's comment:
Delegate command is implemented in MVVM toolkit template and when you create new MVVM project, there is Delegate command in solution. As much as I saw in Prism videos this should be the same class (or at least very similar).

这是 XAML 代码段:

Here is XAML snippet:

    ...
    <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>
   ...

查看模型:

   // 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;
    }

正如我在问题的第一部分中所写,以下事情有效:

As I wrote in the first part of question, following things work:

  • ObjectName 的属性设置器在文本框中的每次按键时触发
  • 如果我将 return true; 放入 CanAddObject(),则命令处于活动状态(按钮)
  • property setter for ObjectName is triggered on every keypress in textbox
  • if I put return true; in CanAddObject(), command is active (button to)

在我看来绑定是正确的.

It looks to me that binding is correct.

我不知道的是如何让 CanExecute() 从上述代码的 ObjectName 属性的设置器中触发.

Thing that I don't know is how to make CanExecute() fire in setter of ObjectName property from above code.

Re Ben 和 Abe 的回答:

Re Ben's and Abe's answers:

  • CanExecuteChanged() 是事件处理程序,编译器报错:

  • CanExecuteChanged() is event handler and compiler complains:

事件'System.Windows.Input.ICommand.CanExecuteChanged'只能出现在左侧+= 或 -=

The event 'System.Windows.Input.ICommand.CanExecuteChanged' can only appear on the left hand side of += or -=

  • ICommand只有两个成员:Execute()CanExecute()

    您是否有一些示例说明如何进行命令调用 CanExecute().

    Do you have some example that shows how can I make command call CanExecute().

    我在 DelegateCommand.cs 中找到了命令管理器助手类,我会研究一下,也许有一些可以提供帮助的机制.

    I found command manager helper class in DelegateCommand.cs and I'll look into it, maybe there is some mechanism that could help.

    无论如何,为了根据用户输入激活命令,需要在属性设置器代码中轻推"命令对象的想法看起来很笨拙.它将引入依赖关系,而 MVVM 的一大要点就是减少它们.

    Anyway, idea that in order to activate command based on user input, one needs to "nudge" command object in property setter code looks clumsy. It will introduce dependencies and one of big points of MVVM is reducing them.

    编辑 2:

    我尝试通过从上面的代码调用 addObjectCommand.RaiseCanExecuteChanged()ObjectName 属性设置器来激活 CanExecute.这也无济于事.CanExecute() 会在表单初始化时触发几次,但之后就再也不会执行了.这是代码:

    I tried to activate CanExecute by calling addObjectCommand.RaiseCanExecuteChanged() to ObjectName property setter from above code. This does not help either. CanExecute() is fired few times when form is initialized, but after that it never gets executed again. This is the code:

       // Property bound to textbox
       public string ObjectName
        {
            get { return objectName; }
            set { 
                objectName = value;
                addObjectCommand.RaiseCanExecuteChanged();              
                OnPropertyChanged("ObjectName");
            }
        }
    

    编辑 3:解决方案

    作为 Yanko YankovJerKimball 写道,问题是静态资源.当我像 Yanko 建议的那样更改按钮绑定时:

    As Yanko Yankov and JerKimball wrote, problem is static resource. When I changed button binding like Yanko suggested:

    <Button Command="{Binding AddObjectCommand}">Add</Button>
    

    事情立即开始运作.我什至不需要 RaiseCanExecuteChanged().现在 CanExecute 会自动触发.

    things started to work immediately. I don't even need RaiseCanExecuteChanged(). Now CanExecute fires automatically.

    我为什么首先使用静态资源?
    原始代码来自 WPF MVVM 工具包 手册.该手册中的示例将命令定义为静态资源,然后将其绑定到菜单项.不同之处在于,在我的示例中,MVVM 手册不是使用字符串属性,而是使用 ObservableCollection.

    Why did I use static resource in first place?
    Original code was from WPF MVVM toolkit manual. Example in that manual defines commands as static resource and then binds it to menu item. Difference is that instead of string property in my example, MVVM manual works with ObservableCollection.

    编辑 4:最终解释

    我终于明白了.我需要做的就是阅读 CommandReference 类中的注释.它说:

    I finally got it. All I needed to do was to read comment in CommandReference class. It says:

    /// <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>
    

    因此,CommandReference 用于KeyBinding,而不用于视觉元素中的绑定.在上面的代码中,资源中定义的命令引用适用于 KeyBinding,我在此用户控件上没有.
    当然,WPF MVVM 工具包附带的示例代码是正确的,但我看错了,在可视元素绑定中使用了 CommandReference.
    这个 WPF MVVM 有时真的很棘手.

    So, CommandReference is used for KeyBinding, it is not for binding in visual elements. In above code, command references defined in resources would work for KeyBinding, which I don't have on this user control.
    Of course, sample code that came with WPF MVVM toolkit were correct, but I misread it and used CommandReference in visual elements binding.
    This WPF MVVM really is tricky sometimes.

    推荐答案

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

    Things look much clearer now with the edits, thanks! This might be a stupid question (I'm somewhat tired of a long day's work), but why don't you bind to the command directly, instead of through a static resource?

    <Button Command="{Binding AddObjectCommand}">Add</Button>
    

    这篇关于基于 TextBox 值 (WPF) 启用按钮的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆