猿问

WPF 的 MVVM 模式:模型与视图模型

我无法真正解决以下问题:


我在应用程序中只有一个textbox用于用户输入,一个button用于对该输入执行后台计算和一个textblock. 想象一下,我必须使用 MVVM,所以我有我的view,viewmodel和model类。


我将视图中的控件(textbox、button和textblock)绑定到viewmodel相应的属性和命令。但是,我不确定该viewmodel功能应该在哪里结束。例如,以下是构建应用程序的一种方式吗?


模型:


public class Model

{


    public string Input { get; set; }

    public string Output { get; set; }


    public void FancyMethod ()

    {

       // Use input to calculate output

    }


}

视图模型:


public class ViewModel

{


    public string Input {get; set;}

    public string Output {get; set;}

    public ICommand command {get; set;}

    public Model model {get; set;}


    public ViewModel() 

    {

      model = new Model();

    }


    // When the button is pressed, model.input = Input and then execute model.FancyMethod()


}


泛舟湖上清波郎朗
浏览 143回答 3
3回答

MM们

如果你想保持一个干净的层模型,你不应该public Model model {get; set;}在你的ViewModel.因此,例如,如果您有一个命令,针对某个业务模型,您的结构应该是这样的://you don't have this one... but well, maybe other cases havepublic class SomeService : ISomeService{    //member of ISomeService    public void SomeFancyMethod(Model model)    {        //do stuff..    }}public class Model //might be database, or domain model.{   public string Input { get; set; }   public string Output { get; set; }}至于你的视图模型,它会变成这样:public class ViewModel{    private ISomeService _someService;    //note: someService is passed through a IoC service like ninject, unity, autofac etc.    public ViewModel(ISomeService someService)    {        _someService = someService;        //initialize the command:        command = new RelayCommand(() =>        {                _someService .SomeFancyMethod(new Model()            {                //properties could be mapped with an automapper.            });        });    }    public ICommand command {get; private set;}    public string Input {get; set;}    public string Output {get; set;} }注意:还涉及一些其他技术:使用控制容器的反转,并通过构造函数传递服务。通过接口(ISomeService)抽象服务可能是一些自动映射器来隔离你的映射与模型/视图模型“那为什么要把它弄得这么‘复杂’?你只是在复制。” ,一个普遍听到的反对这种模式的论点:好:这并不复杂这样做会将您的图层分开。这意味着您的数据层中的更改不会破坏您的视图。从长远来看,您将受益,因为变化将会到来,您将需要维护代码。

隔江千里

我猜FancyMethod()包含您的业务逻辑并产生您想要在视图中显示的值。在这种情况下,FancyMethod()属于您的模型,因为它包含一些相同的业务逻辑,无论它是在客户端应用程序还是其他组件的上下文中执行。所以你的模型看起来像这样,即它接受一个输入并产生一个输出,但它不公开视图可能绑定到的任何属性:public class Model{    public string FancyMethod(string input)    {        // Use input to calculate output    }}然后,您可以将模型注入您的视图模型,并FancyMethod在用户通过单击Button视图中的执行命令时调用:public class ViewModel{    private readonly Model _model;    public ViewModel(Model model)    {        _model = model;        command = new RelayCommand(Execute, CanExecute);    }    public string Input { get; set; }    public string Output { get; set; }    public ICommand command { get; private set; }    private bool CanExecute(object _)    {        return !string.IsNullOrEmpty(Input);    }    private void Execute(object _)    {        Output = _model.FancyMethod(Input);    }}显然,视图模型类也应该实现INotifyPropertyChanged接口并向视图发出更改通知。简而言之,业务逻辑属于模型,而应用逻辑,例如当用户点击 a 时发生的事情Button,属于视图模型。

炎炎设计

我认为没有必要在另一个类中外包Input和Output属性。这样做的原因是属性反映了视图的输入和输出。所以他们必须在视图模型中。您可以SomeFancyMethod在服务类中外包 ,以将逻辑与类似于 mvc 的视图模型分开。
随时随地看视频慕课网APP
我要回答