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

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

问题描述

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



TextBox Button ListBox 。 Button绑定到具有 CanExecute 函数的 DelegateCommand 。想法是用户在文本框中输入一些数据,按下按钮并将数据附加到列表框中。



我想在用户输入正确的时候启用命令 TextBox 中的数据。现在的工作方式如下:




  • CanExecute()

  • 文本框绑定到视图模型中的属性

  • UpdateSourceTrigger
  • code>设置为 PropertyChanged 和视图模型中的属性在每个关键用户按下后更新。


问题是,当用户输入数据时, CanExecute()文本框。



如何使这项工作成功?



strong> Edit>

Re Yanko的注释:

委托命令在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}>添加< / Button>
...

查看模型:


$ b b

  //属性绑定到文本框
public string ObjectName
{
get {return objectName; }
set {
objectName = value;
OnPropertyChanged(ObjectName);
}
}


//命令绑定到按钮
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;
}

正如我在问题的第一部分写道, p>


  • 对象名称的属性设置在文本框中的每个按键上触发

  • 如果我在 CanAddObject()中放置返回true; ,则命令处于活动状态/ li>


看起来我的绑定是正确的。



't知道是如何使 CanExecute()在上面的代码 c>属性

Re Ben和Abe的答案:




  • CanExecuteChanged )是事件处理程序和编译器抱怨:


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



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




你有一些例子说明如何让命令调用 CanExecute()



我在 DelegateCommand.cs 我会调查它,也许有一些机制,可以帮助。



无论如何,想为了激活命令基于用户输入,到微移命令对象在属性设置器代码看起来笨拙。它会引入依赖关系,而MVVM的一个重点是减少它们。



编辑2:



我试图通过调用 addObjectCommand.RaiseCanExecuteChanged()激活 CanExecute ObjectName 属性设置器。这也没有帮助。 CanExecute()在窗体初始化时被触发了几次,但之后它不会再次执行。这是代码:

  //属性绑定到文本框
public string ObjectName
{
get {return objectName; }
set {
objectName = value;
addObjectCommand.RaiseCanExecuteChanged();
OnPropertyChanged(ObjectName);
}
}

编辑3:解决方案



由于 Yanko Yankov JerKimball 写道,问题是静态资源。当我更改按钮绑定像Yanko建议:

 < Button Command ={Binding AddObjectCommand}>添加< / Button> ; 

事情立即开始工作。我甚至不需要 RaiseCanExecuteChanged()。现在 CanExecute 会自动启动。



为什么我第一次使用静态资源?

原始代码来自 WPF MVVM工具包手册。该手册中的示例将命令定义为静态资源,然后将其绑定到菜单项。区别在于,在我的示例中,MVVM手动使用 ObservableCollection 而不是string属性。



编辑4:最终解释



所有我需要做的是阅读 CommandReference 类中的注释。它说:

  ///< summary> 
///这个类通过暴露一个Command依赖关系属性,使得XAML标记中的一个键绑定与一个View模型中定义的命令
///相关联。
///当来自XAML的
///数据绑定时,该类派生自Freezable解决WPF中的限制。
///< / summary>

因此, CommandReference 用于 KeyBinding ,它不是用于在视觉元素中绑定。在上面的代码中,资源中定义的命令引用适用于KeyBinding,我对此用户控件没有。

当然,WPF MVVM工具包附带的示例代码是正确的,但我误读并且在可视元素绑定中使用 CommandReference

这个WPF MVVM有时很棘手。

解决方案

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

 < Button Command ={Binding AddObjectCommand}>添加< / Button> 


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

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.

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

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

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?

Edit:
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).

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

View model:

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

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

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

Re Ben's and Abe's answers:

  • CanExecuteChanged() is event handler and compiler complains:

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

  • there are only two more members of ICommand: Execute() and CanExecute()

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

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

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.

Edit 2:

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");
        }
    }

Edit 3: Solution

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

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

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

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.

Edit 4: Final explanation

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>

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天全站免登陆