WPF MVVM 示例






2.80/5 (8投票s)
WPF 中 MVVM 方法的示例
引言
在本文中,我将使用 MVVM 方法实现 WPF 解决方案,以满足下面提到的小需求
要求
我们需要使用 MV-VM 方法,根据用户输入的员工 ID 值显示员工详细信息。
解决方案
让我们创建包含以下项目/文件的示例 WPF 项目。
- 视图: MainWindow.Xaml
- MainWindow.Xaml.CS -->在 MV-VM 方法中,代码隐藏的作用非常小。
- 视图模型: SearchEmpVM.CS。
- 模型:Employee 类: EmpCls.cs – 创建的类文件用于保存搜索到的员工详细信息。
我将按照我创建的顺序逐步介绍每个实体的代码。
模型 (EmpCls.cs)
模型类应包含业务逻辑,为了便于理解,我将模型简化为 :-) 此类将包含 Employee 实体的结构。这是代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SampleWPFMVVM.Entity
{
class EmpCls
{
private int _empNo;
public int EmpNo
{
get { return _empNo; }
set
{
_empNo = value;
}
}
private string _name;
public string Name
{
get { return _name; }
set {
_name = value;
}
}
private string _designation;
public string Designation
{
get { return _designation; }
set
{
_designation = value;
}
}
private string _department;
public string Department
{
get { return _department; }
set
{
_department = value;
}
}
}
}
//
视图 (MainWindow.Xaml)
编写如下所示的 Xaml 代码
<window height="350" mc:ignorable="d" title="MainWindow" width="333" x:class="SampleWPFMVVM.MainWindow" x:name="Window" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:SampleWPFMVVM.ViewModel" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <window.datacontext> <vm:searchempvm> </vm:searchempvm></window.datacontext> <grid> <grid.rowdefinitions> <rowdefinition height="auto"></rowdefinition> <rowdefinition height="auto"></rowdefinition> <rowdefinition height="auto"></rowdefinition> <rowdefinition height="auto"></rowdefinition> </grid.rowdefinitions> <stackpanel> <grid grid.rowspan="4" margin="0,51,0,-48"> <grid.rowdefinitions> <rowdefinition height="auto"></rowdefinition> <rowdefinition height="auto"></rowdefinition> </grid.rowdefinitions> <grid.columndefinitions> <columndefinition width="auto"> <columndefinition width="auto"> </columndefinition></columndefinition></grid.columndefinitions> <label content="EmpId:" grid.column="0" grid.row="0"> <textbox grid.column="1" grid.row="0" text="{Binding ElementName=Window,Path=DataContext.EmpId,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" x:name="txtEmpId1"></textbox> <stackpanel datacontext="{Binding SearchCls}" grid.column="1" grid.row="1"> <groupbox> <groupbox.headertemplate> <datatemplate> <label content="Employee Information"> </label></datatemplate> </groupbox.headertemplate> <grid> <grid.rowdefinitions> <rowdefinition height="26*"> <rowdefinition height="26*"> <rowdefinition height="26*"> <rowdefinition height="26*"> <rowdefinition height="26*"> </rowdefinition></rowdefinition></rowdefinition></rowdefinition></rowdefinition></grid.rowdefinitions> <grid.columndefinitions> <columndefinition width="Auto"> <columndefinition width="Auto"> <columndefinition width="Auto"> <columndefinition width="Auto"> <columndefinition width="Auto"> </columndefinition></columndefinition></columndefinition></columndefinition></columndefinition></grid.columndefinitions> <label content="Name:" grid.column="0" grid.columnspan="3" grid.row="0"> <textbox grid.column="3" grid.row="0" text="{Binding Name}" width="174"> <label content="Designation:" grid.column="0" grid.columnspan="3" grid.row="1"> <textbox grid.column="3" grid.row="1" text="{Binding Designation}" width="174"> <label content="Department:" grid.column="0" grid.columnspan="3" grid.row="2"> <textbox grid.column="3" grid.row="2" text="{Binding Department}" width="174"> </textbox></label></textbox></label></textbox></label></grid> </groupbox> </stackpanel> </label></grid> </stackpanel> </grid> </window>
让我解释一下下面用斜体突出显示的重要代码行,
A. 下面的代码将导入我们的 ViewModel "SearchEmpVM.CS" 的命名空间
xmlns:vm="clr-namespace:SampleWPFMVVM.ViewModel"
B. 以下行会将 viewModel
类绑定为窗体的数据上下文
<window.datacontext> <vm:searchempvm> </vm:searchempvm></window.datacontext>
C. 以下代码将绑定 viewModel
类的 "EmpId
" 属性,并触发 "EmpId
" 属性的 set 过程/块中的逻辑
<textbox grid.column="1" grid.row="0" text=" {Binding ElementName=Window,Path=DataContext.EmpId,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" x:name="txtEmpId1">
</textbox>
D. 以下代码将绑定属性 "SearchCls
"。此属性将保存搜索到的员工的对象,即 "EmpCls
" 类
<stackpanel datacontext="{Binding SearchCls}" grid.column="1" grid.row="1">
</stackpanel>
E. 以下代码将绑定类 "searchCls
"("EmpCls
" 的内部属性)的属性 "Name
",因此,每当将值分配给 "Name
" 属性时,该值将显示在文本框中。类似地,我们将 "EmpCls
" 的属性绑定到所有控件,以显示所选员工的值
<textbox grid.column="3" grid.row="0" text="{Binding Name}" width="174">
</textbox>
视图模型 (SearchEmpVM.CS)
这将包含业务逻辑
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SampleWPFMVVM.Entity; //namespace of Employee class
namespace SampleWPFMVVM.ViewModel
{
class SearchEmpVM : INotifyPropertyChanged
{
List<empcls> EmpList = new List<empcls>();
public SearchEmpVM()
{
// Add sample employee details into employee list
EmpList.Clear();
EmpList.Add(new EmpCls { EmpNo = 1, Name = "John", Department = "IT", Designation = "Developer" });
EmpList.Add(new EmpCls { EmpNo = 2, Name = "Mark", Department = "IT", Designation = "Tester" });
EmpList.Add(new EmpCls { EmpNo = 3, Name = "Robert", Department = "IT", Designation = "DB Developer" });
}
#region properties
private EmpCls _searchcls = new EmpCls();
public EmpCls SearchCls
{
get { return _searchcls; }
set
{
_searchcls = value;
RaisePropertyChanged("SearchCls");
}
}
private int _empid;
public int EmpId
{
get {
return _empid;
}
set {
_empid = value;
RaisePropertyChanged("EmpId");
PopulteEmpDetails(_empid);
}
}
#endregion
private void PopulteEmpDetails(int _empid)
{
SearchCls= EmpList.Where(x => x.EmpNo == _empid).Single();
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
让我们理解上面的代码。
A. 我们的 viewModel
应该实现接口,以便在绑定的属性已更改时通知客户端。更多详情
请参考以下链接 INotifyPropertyChanged。
B. 实现接口 "INotifyPropertyChanged
" 的方法 "RaisePropertyChanged
",如上面的代码中突出显示的那样
C. 在所有绑定到控件的属性的 set 过程中调用方法 "RaisePropertyChanged
"。
例如
按如下所述调用
RaisePropertyChanged("EmpId"); //Pass the Property name as parameter
D. 在 "EmpId
" 的 set 属性过程中,将 "_empid
" 传递给用户定义的方法 "PopulteEmpDetails
"。由于我们已将此属性绑定到 xaml 文件中的文本框 "EmpId
",因此每当用户在文本框中输入值时,"EmpId
" 属性的 set 过程中的逻辑将被退出。因此,文本框值将传递给我们的方法 "PopulteEmpDetails
",如以下代码所示。
private int _empid; public int EmpId { get { return _empid; } set { _empid = value; RaisePropertyChanged("EmpId"); PopulteEmpDetails(_empid); } } E. The method "PopulteEmpDetails" will search the employee details from the list and set the List item to the property "SearchCls" as in the following code: private void PopulteEmpDetails(int _empid) { SearchCls= EmpList.Where(x => x.EmpNo == _empid).Single(); }
在 "SearchCls
" 属性的 Set 过程中,我们将值分配给对象 "_searchcls
"(即 EmpCls 类的对象),即我们将搜索到的员工详细信息存储在 "EmpCls" 类的对象中。
由于我们将 "SearchCls
" 属性的属性(即类 "EmpCls
" 的属性)绑定到文本框,因此每当将值设置为属性 "SearchCls" 时,"EmpCls" 的属性将被填充,然后文本框将填充与下图相同的值。
输出
查看上面的图片。
因此,我们实现了前面图像中显示的所需功能。希望本文能让您了解基本实现技术