1. 程式人生 > >wpf之三:WPF的MVVM模式

wpf之三:WPF的MVVM模式

2.Model

Model就是一個class,是對現實中事物的抽象,開發過程中涉及到的事物都可以抽象為Model,例如客戶,客戶的姓名、編號、電話、住址等屬性也對應了class中的Property,客戶的下訂單、付款等行為對應了class中的方法。

3. View

View很好理解,就是介面。對應WPF中的xaml介面設計。

4. ViewModel

上面說過Model抽象,那麼ViewModel就是對View的抽象。顯示的資料對應著ViewMode中的Property,執行的命令對應著ViewModel中的Command。

5.WPF中MVVM的解耦方式

在WPF的MVVM模式中,View和ViewModel之間資料和命令的關聯都是通過繫結實現的,繫結後View和ViewModel並不產生直接的依賴。具體就是View中出現數據變化時會嘗試修改繫結的目標。同樣View執行命令時也會去尋找繫結的Command並執行。反過來,ViewModel在Property發生改變時會發個通知說“名字叫XXX的Property改變了,你們這些View中誰綁定了XXX也要跟著變啊!”,至於有沒有View收到是不是做出變化也不關心。ViewModel中的Command脫離View就更簡單了,因為Command在執行操作過程中操作資料時,根本不需要操作View中的資料,只需要操作ViewModel中的Property就可以了,Property的變化通過繫結就可以反映到View上。這樣在測試Command時也不需要View的參與。這也是我在接觸WPF初期時根本理解不了的所謂資料驅動。
這樣一來ViewMode可以在完全沒有View的情況下測試,View也可以在完全沒有ViewModel的情況下測試(當然只是測試介面佈局和動畫等業務無關的內容)。

二.資料繫結

首先定義NotificationObject類。目的是繫結資料屬性。這個類的作用是實現了INotifyPropertyChanged介面。WPF中類要實現這個介面,其屬性成員才具備通知UI的能力在Prism中有一個NotificationObject自動實現了這個介面,位於Microsoft.Practices.Prism.ViewModel名稱空間下。也就是說,Prism推薦ViewModel繼承這個NotificationObject類來自動實現INotifyPropertyChanged介面。

1.定義Model

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.ViewModel;

namespace WpfMsgReport.Model
{
    //航次號Model
    class BaseCommonModel:NotificationObject
    {
        private string code;

        public string Code
        {
            get { return code; }
            set
            {
                code = value;
                this.RaisePropertyChanged("Code");
            }
        }


        private string name;

        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                this.RaisePropertyChanged("Name");
            }
        }

        private string other;

        public string Other
        {
            get { return other; }
            set
            {
                other = value;
                this.RaisePropertyChanged("Other");
            }
        }
    }
}

2.定義ViewModel:ViewModel有屬性VoyNoList

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.ViewModel;
using System.Windows.Forms;
using WpfMsgReport.Model;

namespace WpfMsgReport.ViewModel
{
    //主頁面ViewModel
    class MainWindowViewModel : NotificationObject
    {
        /// <summary>
        /// 航次號列表
        /// </summary>
        private List<BaseCommonModel> voyNoList;
        public List<BaseCommonModel> VoyNoList
        {
            get { return voyNoList; }
            set
            {
                voyNoList = value;
                this.RaisePropertyChanged("VoyNoList");
            }
        }

        public MainWindowViewModel(HelpNavigator MyNavigator)
        {
            //載入主介面資料
            this.loadMainData();
        }
        /// <summary>
        /// 載入主介面資料
        /// </summary>
        private void loadMainData()
        {
            //載入航次號列表
            this.VoyNoList = new List<BaseCommonModel>();
            BaseCommonModel voyNoModel = new BaseCommonModel();
            voyNoModel.Code = "10000";
            voyNoModel.Name = "10000";
            VoyNoList.Add(voyNoModel);
            BaseCommonModel voyNoModel1 = new BaseCommonModel();
            voyNoModel1.Code = "10001";
            voyNoModel1.Name = "10001";
            VoyNoList.Add(voyNoModel1);
        }
    }
}

3.View控制元件繫結ViewModel的屬性VoyNoList

<ComboBox x:Name="voyNoList" ItemsSource="{Binding VoyNoList}" DisplayMemberPath="Name" SelectedValuePath="Code" SelectionChanged="voyNoList_SelectionChanged"/>

xaml對應的.cs的DataContext設定為MainWindowViewModel

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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;
using WpfMsgReport.Model;
using WpfMsgReport.ViewModel;

namespace WpfMsgReport
{
    /// <summary>
    /// MainWindow.xaml 的互動邏輯
    /// </summary>
    public partial class MainWindow : Window
    {

        System.Windows.Forms.HelpNavigator MyNavigator = System.Windows.Forms.HelpNavigator.TableOfContents;
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new MainWindowViewModel(MyNavigator);
        }
    }
    
}
實現效果:


三.命令繫結

1.ViewModel定義命令並繫結實現方法




程式碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.ViewModel;
using System.Windows.Forms;
using WpfMsgReport.Model;
using System.Windows;


namespace WpfMsgReport.ViewModel
{
    //主頁面ViewModel
    class MainWindowViewModel : NotificationObject
    {
        /// <summary>
        /// 航次號列表
        /// </summary>
        private List<BaseCommonModel> voyNoList;
        public List<BaseCommonModel> VoyNoList
        {
            get { return voyNoList; }
            set
            {
                voyNoList = value;
                this.RaisePropertyChanged("VoyNoList");
            }
        }


        ///命令
        public DelegateCommand<object> SendMailCommand { get; set; }    //傳送報文按鈕


        public MainWindowViewModel(HelpNavigator MyNavigator)
        {
            this.SendMailCommand = new DelegateCommand<object>(SendMailCommandExecute);
            //載入主介面資料
            this.loadMainData();
        }
        /// <summary>
        /// 載入主介面資料
        /// </summary>
        private void loadMainData()
        {
            //載入航次號列表
            this.VoyNoList = new List<BaseCommonModel>();
            BaseCommonModel voyNoModel = new BaseCommonModel();
            voyNoModel.Code = "10000";
            voyNoModel.Name = "10000";
            VoyNoList.Add(voyNoModel);
            BaseCommonModel voyNoModel1 = new BaseCommonModel();
            voyNoModel1.Code = "10001";
            voyNoModel1.Name = "10001";
            VoyNoList.Add(voyNoModel1);
        }


        /// <summary>
        /// 選擇報文,傳送郵件
        /// </summary>
        /// <param name="obj"></param>
        private void SendMailCommandExecute(object obj)
        {
            UIElement ui = obj as UIElement;
            if (ui != null)
            {
                if (ui.GetType().Name == "DataGrid")
                {
                    System.Windows.Controls.DataGrid dg = ui as System.Windows.Controls.DataGrid;
                    var a = dg.SelectedItem;
                    System.Windows.Forms.MessageBox.Show("傳送郵件");
                }
            }
        }


    }
}

2.在xaml的控制元件繫結命令,並把介面控制元件作引數傳遞到ViewModel的方法中


程式碼如下:
                    <Button Width="100" Cursor="Hand" Background="White" BorderBrush="White" Command="{Binding Path=SendMailCommand}" CommandParameter="{Binding ElementName=reportListDataGrid}">
                        <StackPanel Orientation="Horizontal">
                            <Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="/WpfMsgReport;component/Images/email.gif" Height="16"/>
                            <TextBlock Text="傳送郵件" Width="70" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="2,0,0,0" />
                        </StackPanel>
                    </Button>

3.實現效果


四.事件繫結

WPF中不是所有的控制元件都有Command屬性的,如窗體,如果需要在ViewModel中處理Loaded事件命令,或者其他事件的命令時,很難通過繫結Command完成,必須要註冊依賴屬性或事件等,太麻煩了。我喜歡簡約、有效的方式,現在我和大家一起分享一下。

場景,我需要處理ComboBox的SelectionChanged事件,但又避免用後置程式碼,儘量要在ViewModel中獲取。這是需要一個System.Windows.Interactivity.dll,該dll是安裝Blend後才有的,在C:\Program Files\Microsoft SDKs\Expression\Blend\.NETFramework\v4.0\Libraries目錄中,然後我們仍需要Prism.dll。

1.在ViewModel定義命令ChangeVoyNoCommand


2.在ViewModel實現方法ChangeVoyNoCommandExecute


3.在xaml中匯入System.Windows.Interactivity.dll


4.在控制元件ComboBox上繫結事件SelectionChanged和命令ChangeVoyNoCommand

<ComboBox x:Name="voyNoList" ItemsSource="{Binding VoyNoList,UpdateSourceTrigger=PropertyChanged}" SelectedValue="{Binding Path=SelectVoyNo, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Name" SelectedValuePath="Code">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding ChangeVoyNoCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>

5.實現效果


相關推薦

wpfWPF的MVVM模式

2.Model Model就是一個class,是對現實中事物的抽象,開發過程中涉及到的事物都可以抽象為Model,例如客戶,客戶的姓名、編號、電話、住址等屬性也對應了class中的Property,客戶的下訂單、付款等行為對應了class中的方法。 3. View View很好理解,就是介面。對應WPF

設計模式介紹命令模式(command)

    命令(模式)的結構很簡單,但對於消除程式碼間的耦合卻有著重要的影響。     在 C 語言中我們經常使用回撥函式,而命令模式是回撥( callback )的面向物件的替代物。從最直觀的角度來看,命令模式就是一個函式物件:一個作為物件的函式。通過將函式封裝為物件,就能

設計模式系列工廠模式(Factory Pattern)

這是本系列的第三篇部落格,這次主要來說一下工廠模式。 基本工廠模式 簡單來說工廠模式是將工程中的相同型別物件的建立活動集中管理,一般通過反射來生成外界需要的實體類。比如Spring中的容器Bean概念,通過Spring BeanFactory來產生不同的Be

設計模式單例模式(餓漢式與懶漢式)

//保證類在記憶體中只有一個物件 package com.xjh.demo.designpattern.pattern3; public class Student { private Student(){ } //懶漢式 priva

設計模式工廠方法模式—多型工廠的實現

簡單工廠的嚴重問題: 當系統中需要引進新產品時,靜態工廠方法通過所傳入引數的不同來建立不同的產品,這必定要修改工廠類的原始碼,違背了開閉原則 引入工廠方法模式: 針對不同的產品提供不同的工廠 定義: 定義一個用於建立物件的介面,讓子類決定將 哪一個類例項化,工廠方法迷失

hadoop初識搭建hadoop環境(配置HDFS,Yarn及mapreduce 執行在yarn)上及種執行模式(本地模式,偽分散式和分散式介)

--===============安裝jdk(解壓版)================== --root 使用者登入 --建立檔案層級目錄    /opt下分別 建 modules/softwares/datas/tools 資料夾 --檢視是否安裝jdk    rpm -

設計模式系列抽象工廠模式

前言 在設計模式有三個模式是與工廠模式相關的,分別是:簡單工廠模式、工廠方法模式以及抽象工廠模式。在前面的文章中已經談到前面兩種,這裡就對抽象工廠模式介紹一下。抽象工廠模式就是提供一個建立一系列相關或者相互依賴的介面(也就是抽象類),而無需指定具體的類。簡單來

設計模式迭代器模式

1. 前言        迭代器模式(Iterator)提供了一種方法,它可以順序訪問一個物件當中的各個元素,但是又不暴露這個聚合物件的內部標示。聽起來和遍歷很像,個人感覺就是遍歷,即是,迭代器提供了一個方法,可以順序物件內部的某個容器,而不用知道容器中存放的是什麼型別.在

設計模式抽象工廠模式

     抽象工廠模式(Abstract Factory Pattern):      定義:Provide an interface for creating families of related or dependent objects without specify

CNCF CNI系列flannel vxlan模式工作原理淺析

一、前言flannel為container提供網路解決方案。flannel有一個基於etcd cluster的資料交換中心,每個節點上有flannel service,每個節點被分配不同的網段,每個節點上的container從該網段獲取IP。一個節點之間通過一個overlay

RabbitMQ指南發布/訂閱模式(Publish/Subscribe)

問題 除了 消息 模型 server fan 以及 color let   在上一章中,我們創建了一個工作隊列,工作隊列模式的設想是每一條消息只會被轉發給一個消費者。本章將會講解完全不一樣的場景: 我們會把一個消息轉發給多個消費者,這種模式稱之為發布-訂閱模式。   為了

RabbitMQ指南釋出/訂閱模式(Publish/Subscribe)

在上一章中,我們建立了一個工作佇列,工作佇列模式的設想是每一條訊息只會被轉發給一個消費者。本章將會講解完全不一樣的場景: 我們會把

VCSA 6.5 HA配置 準備工作

vmware vcenter ha 高可用 vcsa 接著上一篇文章部署完成VCSA 6.5後,還需要做一些準備工作才能開啟高可用功能,本篇文章主要就講述如何為vCenter 高可用進行準備工作配置vCenter HA網絡從vCenter HA的架構圖中可以看出對於vCenter HA的高

Linux學習文件夾系統的結構和相對(絕對)路徑

sharp 二進制 沒有 數據 csharp pan 用戶 ont 臨時 理解每個目錄的作用 bin   二進制文件 boot   系統的啟動文件、內核 dev   設備文件 etc   配置文件 home  用戶的家目錄 lib    鏈接庫文件  l

RabbitMQ系列教程發布/訂閱(Publish/Subscribe)

mqc 標題 整合 參數 cti 事情 return 控制臺 run (本教程是使用Net客戶端,也就是針對微軟技術平臺的) 在前一個教程中,我們創建了一個工作隊列。工作隊列背後的假設是每個任務會被交付給一個【工人】。在這一部分我們將做一些完全不同的事情--我們將向多個

OSPF詳解OSPF LSA詳解

ospf lsa詳解 forwarding address OSPF LSA詳解OSPF V2版本中常用的主要有6類LSA,分別是Router-LSA、Network-LSA、Network-summary-LSA、ASBR-summary-LSA、AS-External-LSA、NSSA-LSA,接

設計模式組合模式(Composite Pattern)

數據結構 log ide ase 統一 etc 方法 可能 模式 什麽是組合模式呢?簡單來說組合模式就是將對象合成樹形結構以表示“部分整體”的層次結構,組合模式使用戶對單個對象和組合對象使用具有一致性。 組合模式(Composite Pattern)有時

Django運維後臺的搭建用url去精細定制與反向解析

django 反向解析 參數傳遞 url指向 上一篇文章裏,我們做了一個alionlineecs(阿裏雲線上環境服務器)的添加界面,但是要知道我們的計劃裏是有六個分支的,而alionlineecs僅僅是其中之一,要是每一個都這麽寫的話,那麽views.py肯定又臭又長,充滿了大量的復制片段。對

camera攝像原理色溫和自動白平衡【轉】

mil gho 實現 技術分享 處理 目標 紅旗 適應 如果 轉自:http://blog.csdn.net/ghostyu/article/details/7912863 色溫的定義:將黑體從絕對零度開始加溫,溫度每升高一度稱為1開氏度(用字母K表示),當溫度升高到一定

Halcon學習有關圖像通道的函數

spa com detail too pan targe 個數 word pop 黑白攝像機會返回每個像素所對應的能量采用結果,這些結果組成了一幅單通道灰度值圖像,而對於RGB彩色攝像機,它將返回每個像素所對應的三個采樣結果,也就是一幅三通道圖像。下面這些是與圖像通道有關的