C# 在WPF中实现MVVM模式的正确方法
我刚开始学习来自JavaSwing和WinForms的WPF。我决定尝试一些新的东西来学习开发程序的其他概念和技术。上次,我介绍了MVC模式的概念。据我所知,这是一种分离UI逻辑、业务逻辑和数据的方法。我发现WPF的关键概念之一是绑定和MVVM模式 下面是我尝试实现MVVM的代码的一部分 MainWindowModel.csC# 在WPF中实现MVVM模式的正确方法,c#,.net,wpf,xaml,mvvm,C#,.net,Wpf,Xaml,Mvvm,我刚开始学习来自JavaSwing和WinForms的WPF。我决定尝试一些新的东西来学习开发程序的其他概念和技术。上次,我介绍了MVC模式的概念。据我所知,这是一种分离UI逻辑、业务逻辑和数据的方法。我发现WPF的关键概念之一是绑定和MVVM模式 下面是我尝试实现MVVM的代码的一部分 MainWindowModel.cs using System; using System.Collections.Generic; using System.ComponentModel; using Sys
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Controls;
namespace DocNanzDCMS.Model
{
public class MainWindowModel : INotifyPropertyChanged
{
private PropertyChangedEventArgs pce;
public MainWindowModel()
{
pce = new PropertyChangedEventArgs("");
}
private UserControl userControl;
#region ControlProperty
public UserControl ContentProperty {
get
{
return userControl;
}
set
{
userControl = value;
PropertyChanged(this, pce);
}
}
#endregion
private DateTime dateTime;
#region DateProperty
public String DateProperty
{
get
{
return dateTime.ToLongDateString();
}
set
{
dateTime = DateTime.Parse(value);
PropertyChanged(this, pce);
}
}
#endregion
public String TimeProperty
#region TimeProperty
{
get
{
return dateTime.ToLongTimeString();
}
set
{
dateTime = DateTime.Parse(value);
PropertyChanged(this, pce);
}
}
#endregion
private String title;
public String TitleProperty
#region TitleProperty
{
get
{
return title;
}
set
{
title = value;
PropertyChanged(this, pce);
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { };
}
}
MainWindowViewModel.cs
using DocNanzDCMS.Model;
using DocNanzDCMS.View;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace DocNanzDCMS.ViewModel
{
public class MainWindowViewModel
{
private MainWindow mainWindow;
private MainWindowModel mainWindowModel;
private Thread mainWindowThread;
private LoginModel loginModel;
private LoginViewModel loginViewModel;
private LoginView loginView;
private String title;
public MainWindowViewModel(MainWindowModel mainWindowModel, MainWindow mainWindow)
{
this.mainWindowModel = mainWindowModel;
this.mainWindow = mainWindow;
initialize();
}
private void initialize()
{
loginModel = new LoginModel();
loginView = new LoginView();
loginViewModel = new LoginViewModel(loginModel, loginView);
mainWindow.DataContext = mainWindowModel;
mainWindowThread = new Thread(BackgroundProcess);
mainWindowThread.IsBackground = true;
mainWindowThread.Start();
gotoLogin();
}
private void BackgroundProcess()
{
while(true)
{
updateTitle();
updateTime();
try
{
Thread.Sleep(100);
}
catch(ThreadInterruptedException e)
{
}
}
}
public void gotoLogin()
{
mainWindowModel.ContentProperty = loginView;
title = "Login";
}
private void updateTime()
{
mainWindowModel.DateProperty = DateTime.Now.ToString();
mainWindowModel.TimeProperty = DateTime.Now.ToString();
}
public void updateTitle()
{
mainWindowModel.TitleProperty = "Doc Nanz Dental | "+title;
}
}
}
MainWindow.cs
using DocNanzDCMS.Model;
using DocNanzDCMS.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace DocNanzDCMS
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private MainWindowModel mainWindowModel;
private MainWindowViewModel mainWindowViewModel;
public MainWindow()
{
InitializeComponent();
initializeApp();
}
private void initializeApp()
{
mainWindowModel = new MainWindowModel();
mainWindowViewModel = new MainWindowViewModel(mainWindowModel, this);
}
}
}
使用DocNanzDCMS.Model;
使用DocNanzDCMS.ViewModel;
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Data;
使用System.Windows.Documents;
使用System.Windows.Input;
使用System.Windows.Media;
使用System.Windows.Media.Imaging;
使用System.Windows.Navigation;
使用System.Windows.Shapes;
名称空间DocNanzDCMS
{
///
///MainWindow.xaml的交互逻辑
///
公共部分类主窗口:窗口
{
私有MainWindowModel MainWindowModel;
专用MainWindowViewModel MainWindowViewModel;
公共主窗口()
{
初始化组件();
初始化EAPP();
}
private void initializeApp()
{
mainWindowModel=新的mainWindowModel();
mainWindowViewModel=新的mainWindowViewModel(mainWindowModel,此);
}
}
}
MainWindow.xaml
<Window x:Class="DocNanzDCMS.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DocNanzDCMS"
mc:Ignorable="d"
Title="{Binding TitleProperty}" Height="600" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75"/>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<!--Banner-->
<Grid Grid.Row="0" Background="AliceBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="225"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<!--Date and Time Panel-->
<Grid Grid.Column="2" Background="Aquamarine">
<Grid.RowDefinitions>
<RowDefinition Height="1.5*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--Date Background-->
<StackPanel Grid.Row="0" Background="BurlyWood"/>
<!--Date-->
<Label Grid.Row="0" Content="{Binding DateProperty}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<!--Time Background-->
<StackPanel Grid.Row="1" Background="BlanchedAlmond"/>
<!--Time-->
<Label Grid.Row="1" Content="{Binding TimeProperty}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
<!--Content-->
<ScrollViewer Grid.Row="1" Content="{Binding ContentProperty}"/>
<!--Status Bar-->
<Grid Grid.Row="2">
</Grid>
</Grid>
</Window>
我创建了一个模型和视图,并在ViewModel中操纵了它们。我不确定这是否是实现MVVM的正确方法,或者它甚至是MVVM,因为我将其视为MVC模式
维基百科上说:
组件包括:模型、视图、视图模型和活页夹
这部分代码显示一个带有横幅的窗口,横幅最右侧是显示日期和时间的标签。这是可行的,但我担心的是,我的做法是否真的遵循了MVVM模式。你的问题非常广泛,但这里有一些想法 视图模型不应该知道关于视图的任何信息。您不应将
MainWindowViewModel
的引用注入MainWindow
,而应将MainWindow
的DataContext
设置为视图模型的实例:
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
然后,当视图绑定到视图模型时,主窗口视图模型可以初始化和/或与模型通信
此外,视图模型不应公开任何
ui元素
,例如UserControl
<代码>UIElements在视图中定义。为了MVVM的缘故,视图模型不应包含对视图的引用(这被认为是错误的做法)
是了解ViewModel的视图,而不是相反的视图。
视图知道ViewModel,而ViewModel又知道一个或多个模型
INotifyPropertyChanged接口应在ViewModel中实现,以允许视图通过绑定进行自我更新(在某些情况下,在模型上实现接口也是完全合法的)
请记住,可以将ViewModel视为一个适应视图需要的模型,因此,考虑到这一点,我更愿意将模型类作为简单对象,并在ViewModel上编写INotifyPropertyChanged实现
ViewModel成为视图的DataContext(您可以在代码隐藏或xaml中在视图的构造函数中分配DataContext)
要在视图中导航,可以使用(至少)2种方法
您应该决定是使用“视图优先”方法还是“视图模型优先”方法
在“视图优先”方法中,当您想要导航到新页面时,您将创建一个视图,并且一些机制(活页夹)将创建相应的ViewModel(后者反过来创建或获取模型)
在ViewModel first方法中,您将创建一个新的ViewModel(它将创建或获取模型),活页夹将创建相应的视图
根据我告诉你的,这里有一个例子:
视图(MainWindowView.cs),我们分配DataContext:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel()
}
}
ViewModel(MainWindowViewModel.cs):
模型(MainWindowModel.cs):
此外,我认为您应该研究一些类似或(我更喜欢第一个)的框架,以帮助您正确实现MVVM模式,而不是重新发明轮子(此外,您还将获得一个导航系统,用于在视图之间导航)。经过几夜的学习,我终于“吸收”了MVVM的概念及其与MVC的区别 模型-大多数时候它们只是具有属性的类。像
用户
,产品
等
查看-用户界面<代码>注册表服务视图,登录视图
,添加产品视图
ViewModel-这是操作发生的地方<代码>视图模型根据需求/规则操作模型,并将其公开给视图
。但是ViewModel
不知道View
的存在
绑定-这是视图
和视图模型
之间的粘合剂
与MVC相比(只是我的观点)
中的MVC
是被动的,而View
中的MVVM
是主动的。View
中的MVC
决定了什么是控制器
namespace DocNanzDCMS.ViewModel { public class MainWindowViewModel : INotifyPropertyChanged { private MainWindowModel mainWindowModel; public Model {get {return mainWindowModel;}} public MainWindowViewModel() { this.mainWindowModel = new mainWindowModel(); } } }
public class MainWindowModel { private PropertyChangedEventArgs pce; public MainWindowModel() { pce = new PropertyChangedEventArgs(""); } private UserControl userControl; #region ControlProperty public UserControl ContentProperty { get { return userControl; } set { userControl = value; PropertyChanged(this, pce); } } #endregion private DateTime dateTime; #region DateProperty public String DateProperty { get { return dateTime.ToLongDateString(); } set { dateTime = DateTime.Parse(value); PropertyChanged(this, pce); } } #endregion public String TimeProperty #region TimeProperty { get { return dateTime.ToLongTimeString(); } set { dateTime = DateTime.Parse(value); PropertyChanged(this, pce); } } #endregion private String title; public String TitleProperty #region TitleProperty { get { return title; } set { title = value; PropertyChanged(this, pce); } } #endregion public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { }; }