简体   繁体   English

WPF MVVM按钮命令获取文本框值

[英]WPF MVVM button command that gets textbox value

I'm having a great trouble with understanding how button command works. 我在了解按钮命令的工作方式时遇到了很大的麻烦。 I have something like this 我有这样的东西

{Binding TxtBox} gets value from model, let's say it's "aaa". {Binding TxtBox}从模型中获取价值,假设它是“ aaa”。 I would like click the button and the value should appear in the second textbox (the one with {Binding TxtBox2} ). 我想单击按钮,值应该出现在第二个文本框中(带有{Binding TxtBox2}文本框中)。

This is my xaml: 这是我的xaml:

<TextBox Text="{Binding TxtBox, Source={StaticResource viewModel}}" />
<TextBox Text="{Binding TxtBox2, Source={StaticResource viewModel}}" />
<Button Command="{Binding ClickCommand}"/>

This is my ViewModel: 这是我的ViewModel:

public class CommandHandler : ICommand
{
    private Action _action;
    private bool _canExecute;
    public CommandHandler(Action action, bool canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        _action();
    }
}

Do I really need this CommandHandler class? 我真的需要这个CommandHandler类吗? I copied the code from the net. 我从网上复制了代码。

public string TxtBox
{
    get { return Model.TxtBoxValue; }
    set { Model.TxtBoxValue = value; }
}
public string TxtBox2 { get; set; }

private ICommand _clickCommand;
public ICommand ClickCommand
{
    get
    {
        return _clickCommand ?? (_clickCommand = new CommandHandler(() => MyAction(), _canExecute)); // I believe that when the button is clicked MyAction() is triggered, right?

    }

}
private bool _canExecute = true;
public void MyAction()
{
    this.TxtBox2 = this.TxtBox; // should something like this work? Because right now it doesn't
}

The second textbox's binding never gets notified that it's bound property is changed. 第二个文本框的绑定永远不会收到有关其绑定属性已更改的通知。 When you set this.TxtBox2 you should fire the propertychanged event for that property so the binding will be updated. 设置this.TxtBox2时,应触发该属性的propertychanged事件,以便更新绑定。 See think link for everything on bindings 有关绑定的所有信息,请参见思考链接

I don't know if you are using prism as mvvm framework but that comes with the DelegateCommand class. 我不知道您是否使用棱镜作为mvvm框架,但这是DelegateCommand类附带的。 I don't think there is a simple/lightweight implementation in the .net framework. 我认为.net框架中没有简单/轻量级的实现。 See this link for the mvvm framework and the delegate command 有关mvvm框架和委托命令,请参见此链接。

The View reacts to binding changes through PropertyChanged events, of which you have none. 视图通过PropertyChanged事件对绑定更改作出反应,而您没有事件。 Have anything that binds to the View implement INotifyPropertyChanged and then fire events when props change, and you're all set for your bindings to work (one way or two way). 绑定到View实现INotifyPropertyChanged的任何东西,然后在props更改时触发事件,并且都准备好绑定起作用(一种或两种方式)。

Change your model to look like this and it should work for you. 更改模型使其看起来像这样,它应该对您有用。


public class MyViewModel : INotifyPropertyChanged
{
    #region INotifyPropertyChanged Members

    [field: NonSerialized]
    public event PropertyChangedEventHandler PropertyChanged = null;

    protected virtual void RaisePropertyChanged(string propName)
    {
        if(PropertyChanged != null)
        {
            Task.Run(() => PropertyChanged(this, new PropertyChangedEventArgs(propName)));
        }
    }

    #endregion

    public string TxtBox
    {
        get { return Model.TxtBoxValue; }
        set
        {
            Model.TxtBoxValue = value;
            RaisePropertyChanged("TxtBox");
        }
    }

    // presuming TxtBox2Value is in Model...else use a field
    public string TxtBox2
    {
        get { return Model.TxtBox2Value; }
        set
        {
            Model.TxtBox2Value = value;
            RaisePropertyChanged("TxtBox2");
        }
    }

    private ICommand _clickCommand;
    public ICommand ClickCommand
    {
        get
        {
            return _clickCommand ?? (_clickCommand = new CommandHandler(() => MyAction(), _canExecute)); // I believe that when the button is clicked MyAction() is triggered, right?

        }

    }
    private bool _canExecute = true;
    public void MyAction()
    {
        this.TxtBox2 = this.TxtBox; // should something like this work? Because right now it doesn't
    }
}

IMO - it is better to have your Model implement INotifyPropertyChanged and then bind directly to it rather than wrap it in your ViewModel. IMO-最好让模型实现INotifyPropertyChanged,然后直接绑定到它,而不是将其包装在ViewModel中。 If Model : INotifyPropertyChanged, then your ViewModel now looks like this: 如果Model:INotifyPropertyChanged,则您的ViewModel现在看起来像这样:


public class MyViewModel
{

    // fire prop changed event here if this model will be swapped out after the ctor...otherwise don't worry about it
    public Model Model { get; set; }

    private ICommand _clickCommand;
    public ICommand ClickCommand
    {
        get
        {
            return _clickCommand ?? (_clickCommand = new CommandHandler(() => MyAction(), _canExecute)); 

        }

    }
    private bool _canExecute = true;
    public void MyAction()
    {
        Model = new Model();

        Model.TxtBox2 = "Some new value"; 
    }
}

...and your xaml changes to this: ...而您的xaml更改为:

<TextBox Text="{Binding Model.TxtBox, Source={StaticResource viewModel}}" />
<TextBox Text="{Binding Model.TxtBox2, Source={StaticResource viewModel}}" />
<Button Command="{Binding ClickCommand}"/>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM