为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
泛舟湖上清波郎朗 2021-10-09 16:47:51
我无法真正解决以下问题:我在应用程序中只有一个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()}
查看完整描述

3 回答

?
MM们

TA贡献1886条经验 获得超2个赞

如果你想保持一个干净的层模型,你不应该public Model model {get; set;}在你的ViewModel.


因此,例如,如果您有一个命令,针对某个业务模型,您的结构应该是这样的:


//you don't have this one... but well, maybe other cases have

public 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)抽象服务

可能是一些自动映射器来隔离你的映射与模型/视图模型

“那为什么要把它弄得这么‘复杂’?你只是在复制。” ,一个普遍听到的反对这种模式的论点:


好:


这并不复杂

这样做会将您的图层分开。这意味着您的数据层中的更改不会破坏您的视图。从长远来看,您将受益,因为变化将会到来,您将需要维护代码。


查看完整回答
反对 回复 2021-10-09
?
隔江千里

TA贡献1906条经验 获得超10个赞

我猜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,属于视图模型。


查看完整回答
反对 回复 2021-10-09
?
炎炎设计

TA贡献1808条经验 获得超4个赞

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


查看完整回答
反对 回复 2021-10-09
  • 3 回答
  • 0 关注
  • 142 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信