简体   繁体   English

从视图模型更新模型

[英]Update the model from the view model

Update the model from the view model 从视图模型更新模型

I have read some post about the MVVM but I not sure if understand the way that the view model is updating the model 我已经阅读了一些关于MVVM的帖子,但我不确定是否理解视图模型更新模型的方式

Currently I have two text boxes in the UI which is bound to the XAML view and call to the view model when the event was raised . 目前,我在UI中有两个文本框,它们绑定到XAML视图,并在引发事件时调用视图模型。 when should be the place in the view model when I updating the model? 当我更新模型时应该在视图模型中的哪个位置?

This is the view model 这是视图模型

class ViewModel:INotifyPropertyChanged
    {

 private String _url;
 private String _TemplateType;

    public string URL
    {
    get { return _url;  }
        set
        {
            if (value != _url)
            {
                _url= value;
                OnPropertyChanged("URL");
            }
        }
    }

    public string TemplateType
    {
    get { return _TemplateType;  }
        set
        {
            if (value != _TemplateType)
            {
                _TemplateType= value;
                OnPropertyChanged("URL");
            }
        }
    }

The model 该模型

internal class DefineAddinModel
{
    public string TemplateType { get; set; }
    public String URL { get; set; }
}

The ViewModel usually acts as a wrapper around the Model and contains a reference to the Model which is can update either in response to commands or automatically in property setters. ViewModel通常充当模型的包装器,并包含对模型的引用,该模型可以响应命令或在属性设置器中自动更新。

UPDATE: Here's an example of having the VM act as a wrapper around the Model. 更新:这是一个让VM充当模型包装器的例子。 This may seem useless in your example but you will find in many cases the VM's getters/setters need to do some sort of transformation on the values rather than simply passing them through. 在您的示例中,这似乎没用,但在很多情况下,您会发现VM的getter / setter需要对值进行某种转换,而不是简单地传递它们。

class ViewModel:INotifyPropertyChanged
{
 private DefineAddinModel model;

    public string URL
    {
        get { return model.URL;  }
        set
        {
            if (value != model.URL)
            {
                model.url = value;
                OnPropertyChanged("URL");
            }
        }
    }

    public string TemplateType
    {
        get { return model.TemplateType;  }
        set
        {
            if (value != model.TemplateType)
            {
                model.TemplateType = value;
                OnPropertyChanged("TemplateType");
            }
        }
    }

The better way to update your Model Is by using an event, its safer, so choose weather using a button click or lost focus, or whatever you want 更新模型的更好方法是使用事件,它更安全,所以选择天气使用按钮点击或失去焦点,或任何你想要的

void button_click(object sender,eventsarg e)
{
    MyObj.URL = App.Locator.MyVM.MyDefineAddinModel.URL;// App.Locator because MVVMLight is tagged
    MyObj.TemplateType = App.Locator.MyVM.MyDefineAddinModel.TemplateType ;

}

but personnaly i Use the following steps : 但是personnaly我使用以下步骤:

1- In your ViewModel create a CurrentItem object of type DefineAddinModel and without OnPropertyChanged then bind it to the View(UI) DataContext of the RootElement on the View ) 1-在ViewModel中创建一个类型为DefineAddinModelCurrentItem对象,而不使用DefineAddinModel ,然后将其绑定到View上RootElement的View(UI)DataContext)

2- for the model I use the INotifyPropertyChanged for each propery 2-为模型我为每个属性使用INotifyPropertyChanged

3- after binding the datacontext of your root element to the CurrentItem of your ViewModel then bind just URL and TemplateType properties to your Controls, so any thing changes on the textbox will update CurrentItem properties 3-根元素的datacontext绑定到您的视图模型的CURRENTITEM后,然后绑定只是URLTemplateType属性的控制,所以在文本框的任何事情的变化将更新currentItem属性

you can also chose the type of the binding (On LostFocus, or OnPropertyChanged) 你也可以选择绑定的类型(On LostFocus,或OnPropertyChanged)

You need to bind your TextBoxes to the two properties URL and TemplateType . 您需要将TextBox绑定到两个属性URLTemplateType Try to use Commands (in the ViewModel )instead of events (in The CodeBehind) since you are in MVVM . 尝试使用Commands (在ViewModel )而不是events (在CodeBehind中),因为您在MVVM For updating the model : use a button with it's Command property bound to OnSave just like this example: 要更新模型:使用一个按钮,它的Command属性绑定到OnSave,就像这个例子:

    private String _url;
    private String _TemplateType;
    private DefineAddinModel _defineAddin;

    public DefineAddinModel DefineAddin
    {
        get {return _defineAddin;}
        set
        { 
            _defineAddin = value;
            OnPropertyChanged("DefineAddin");
        }
    }

    public string URL
    {
        get { return _url;  }
        set
            {
                if (value != _url)
                {
                    _url= value;
                    OnPropertyChanged("URL");
                }
            }
    }

    public string TemplateType
    {
        get { return _TemplateType;  }
        set
        {
            if (value != _TemplateType)
            {
                _TemplateType= value;
                OnPropertyChanged("URL");
            }
        }
    }

    public RelayCommand OnSaved
    {
            get;
            set;
    }


    public ViewModel()
    {
        DefineAddin = new DefineAddinModel();
            OnSaved = new RelayCommand(()=>
                              {
                                    DefineAddin.URL  = URL  ;
                                    DefineAddin.TemplateType = TemplateType;
                              });

Think about using third parties like MVVMLight it helps you a lot with MVVM and the helpers around it (Commands, Messenger, ViewModelLocator ...) 考虑使用像MVVMLight这样的第三方它可以帮助你很多MVVM及其周围的助手(Commands,Messenger,ViewModelLocator ......)

I think that the correct answer here is 'it depends'. 我认为这里的正确答案是'它取决于'。

In most general cases, the advantage of actually using a ViewModel is also to track 'transient state', ie the state of an 'edit in progress' operation. 在大多数一般情况下,实际使用ViewModel的优点还在于跟踪“瞬态”,即“正在编辑”操作的状态。

In this particular case, you would not push your changes directly to the Model every time a value is updated, instead you would do this via an 'Update' ICommand implementation that will collect all the data from the ViewModel and push it down to the Model. 在这种特殊情况下,每次更新值时都不会将更改直接推送到模型,而是通过“更新”ICommand实现来执行此操作,该实现将从ViewModel收集所有数据并将其推送到模型。

This approach gives you many advantages: 这种方法为您提供了许多优势:

  1. The user of the view can change their mind as many times as they want, and only when they are happy will the Model actually get updated with their definitive choices 视图的用户可以根据需要多次改变他们的想法,并且只有当他们感到满意时,模型才能真正获得他们明确选择的更新
  2. It greatly reduces the load on your persistence service, since only final changes are pushed through. 它极大地减少了持久性服务的负载,因为只推送了最终的更改。
  3. It allows you to do final validation on a complete set of values, rather than transient states, and hence reduces programming complexity and overhead. 它允许您对一组完整的值进行最终验证,而不是瞬态,从而降低编程复杂性和开销。
  4. It also makes your UI far more fluid since all the examples above are pushing updates on the UI Dispatcher, and avoids you having to cater for this via Tasks or other async approaches. 它还使您的UI更加流畅,因为上面的所有示例都在推送UI Dispatcher上的更新,并避免您必须通过任务或其他异步方法来满足这一要求。
  5. The backing model is never in an inconsistent state, since I would imagine that all values on one View/ViewModel are related, and only make sense when updated together using an ACID approach. 支持模型永远不会处于不一致状态,因为我会想象一个View / ViewModel上的所有值都是相关的,并且只有在使用ACID方法一起更新时才有意义。

Here's an example of how I'd do it. 这是我如何做的一个例子。

public class ViewModel:INotifyPropertyChanged {

    private String _url;
    private String _TemplateType;

    public ViewModel(){
        UpdateCommand = new DelegateCommand(OnExecuteUpdate, OnCanExecuteUpdate);
    }

    public bool OnCanExecuteUpdate(object param){
        // insert logic here to return true when one can update
        // or false when data is incomplete
    }

    public void OnExecuteUpdate(object param){
        // insert logic here to update your model using data from the view model
    }

    public ICommand UpdateCommand { get; set;}

    public string URL{
        get { return _url;  }
        set {
            if (value != _url) {
                _url= value;
                OnPropertyChanged("URL");
            }
        }
    }

    public string TemplateType {
        get { return _TemplateType;  }
        set {
            if (value != _TemplateType) {
                _TemplateType= value;
                OnPropertyChanged("TemplateType");
            }
        }
    }

    ... etc.
}

public class DelegateCommand : ICommand {
    Func<object, bool> canExecute;
    Action<object> executeAction;

    public DelegateCommand(Action<object> executeAction)
        : this(executeAction, null) {}

    public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute) {
        if (executeAction == null) {
            throw new ArgumentNullException("executeAction");
        }
        this.executeAction = executeAction;
        this.canExecute = canExecute;
    }

    public bool CanExecute(object parameter) {
        bool result = true;
        Func<object, bool> canExecuteHandler = this.canExecute;
        if (canExecuteHandler != null) {
            result = canExecuteHandler(parameter);
        }

        return result;
    }

    public event EventHandler CanExecuteChanged;

    public void RaiseCanExecuteChanged() {
        EventHandler handler = this.CanExecuteChanged;
        if (handler != null) {
            handler(this, new EventArgs());
        }
    }

    public void Execute(object parameter) {
        this.executeAction(parameter);
    }
}

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

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