65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF MVVM 示例

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.80/5 (8投票s)

2015年11月20日

CPOL

3分钟阅读

viewsIcon

25674

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" 的属性将被填充,然后文本框将填充与下图相同的值。

输出

查看上面的图片。

因此,我们实现了前面图像中显示的所需功能。希望本文能让您了解基本实现技术

© . All rights reserved.