1. 程式人生 > >WPF-MVVM模式學習筆記3——MVVM概念再次挖掘

WPF-MVVM模式學習筆記3——MVVM概念再次挖掘

     通過上篇文章<WPF-MVVM模式學習筆記2——MVVM簡單樣例>中舉了一個例子,我對MVVM大概有了一個比較淺顯的意思。同時,看過前兩篇文章的人,也知道我的這個系列的文章大多數來源於其他的部落格,我其實只是起了一個彙總的作用,畢竟我也是在學習,肯定是要去網路上學習別人的筆記嘍。本篇文章將以溫故而知新的方式再次去理解MVVM,力求對MVVM的認識再深一個層次。

1.再看"M-V-VM"

    M:即Model,由現實世界抽象出來的模型。

    V:即View,檢視,介面,該介面與使用者輸入裝置進行互動。

2.View與Model如何進行互動?

    此時,Binding便可以發揮作用了,比如檢視上的某一個文字框中的文字和Model中的"使用者名稱"關聯起來, 使用者便可以通過操作該文字框來訪問和修改Model的"使用者名稱"了。但是在實際程式設計時,我們發現,Model中的屬性(或者方法)往往不那麼容易與View中的介面控制元件關聯起來。比如定義了一個時間的類Time,該時間類Time具有年、月、日三個屬性,如下

    public class Time
    {
        private string year;
        public string Year
        {
            get
            {
                return this.year;
            }
            set
            {
                this.year = value;
            }
        }


        private string month;
        public string Month
        {
            get
            {
                return this.month;
            }
            set
            {
                this.month = value;
            }
        }


        private string day;
        public string Day
        {
            get
            {
                return this.day;
            }
            set
            {
                this.day = value;
            }
        }

        public Time(string year, string month, string day)
        {
            this.year = year;
            this.month = month;
            this.day = day;
        }
    }

   同時還有一個介面TimeView,如下

   

   我想實現按下按鈕1,時間以年-月-日的形式展示;按下按鈕2,時間以月-日-年的形式展示。此時就需要進行一些“額外的操作”,即模型Time中的資料經過一些額外的處理才能傳給檢視,反之亦然。現在,我們意識到這個View似乎需要一個"Helper"類來處理一些額外工作。這個Helper所包含的程式碼可以放在Model(例如這裡的Time)外的很多地方,比如對應的View.cs中。而且我之前確實是這麼做的,將絕大數處理邏輯放在所謂的CodeBehind中。

3.後來...

   後來,在各種設計模式書籍中所看到的一樣,為了將View和Model剝離開來,實現View可替換,便有了MVC。有了MVC以後,就開始有了MVP、MVVM等等M-V-XX。但是幾乎(我還是加個幾乎吧,因為其他設計模式我也沒有接觸過)所有這些設計模式都主要圍繞兩個問題:

   一是Model與View之間的關係,完全隔離的?單向的還是雙向的?

   二是這個"XX"需要完成哪些功能,簡單流程排程?複雜規則處理?

   這些問題都沒有關係, 是否採用某種模式取決於你的開發所處的環境(比如語言特性,框架特性)以及你的業務特性以及所面臨的主要變化點等等。

4.但是...

   但與MVC,MVP所不同的是,MVVM的引入不僅僅是技術上的原因(解除耦合應對變化等老生常談),另外一個很大原因是:軟體團隊開發方式的改變。我們需要一種方式將View層的程式碼邏輯抽取出來,並View層很純粹以便完全讓美工去打造它。相應地,,需要將View層的相應邏輯抽取到一個程式碼層上,以便讓程式設計師專注在這裡。這就需要:

   ① 你擁有能夠熟練運用Blend等工具能為程式設計師輸出XAML的美工,他專注於純粹的UI/UE,另外他還必須具有一定的"程式設計師"思維,以便輸出的東西能很好地作為程式的一部分而運轉起來,而不是僅僅"看上去"是那樣的;

   ② 你需要能夠脫離View層但仍能編寫出高質量程式碼的程式設計師。

5. Binding、Command、AttachBehavior

   回想一下, 我們之所以要在View(Xaml)背後寫一些程式碼(C#),無非是想傳遞一些資料以及傳遞資料時的資料的處理或在使用者與介面控制元件進行互動時執行一些操作。最簡單的例子是在MVC中當介面發生互動時View去呼叫Controler中的某個方法,以便將該操作的相應"指示"傳遞到"後臺"去。在以前的技術中, 這樣的"銜接性"的程式碼是必須的。而在WPF中, 則可以通過另外的技術來進行層與層之間的"銜接", 這就是"Binding" 和"Command", 以及"AttachBehavior"。

   通過Binding,我們可以實現資料的傳遞;通過Command,我們可以實現操作的呼叫。Binding和Command是可以寫在XAML中的, 這樣看來XAML後面對於的CS檔案可以被完全拋棄或不予理會了,這樣的XAML檔案正是美工所需要的。而這些對於Binding以及Command的定義描述以及其他相關資訊的程式碼應該放在那裡呢,當然不是View, 更不是Model,是“ViewModel”。ViewModel是為這個View所量身定製的,它包含了Binding所需的相關資訊,比如Converter以及為View的Binding提供DataContext,它包含了Command的定義以便View層可以直接使用, 另外,它還是一個變種的Controler, 它得負責業務流程的排程。

   

   上圖非常直觀的展示View\ViewModel\Model的互動圖,真的很佩服繪出這幅圖的作者,太直觀了。

那麼AttachBehavior又是什麼呢?一般情況下利用Command, Binding, AttachProperty等WPF特性, View和ViewModel之間能配合工作得很好。假設我們有一個Button,當該Button被點選的時候我們要完成一些操作,很簡單,將該操作封裝成一個Command並繫結到該Button上就可以了。但如果我們要在Button被Load的時候執行另外一些操作呢? 由於Button沒有直接被Load事件所觸發的Command, 所以不能使用Command了。不能直接將Load事件處理器寫在Button所在的Xaml所對應的CS檔案裡, 這和我們剛才對MVVM的設計是相矛盾的。 一個不太好的方案是繼承一下Button, 並撰寫一個由Load所觸發的Command,這可行, 但明顯不好, 正如一個控制元件沒有某個屬性並且在不繼承的情況下而採用AttachProperty一樣,我們可以採用AttachBehavior。

6.收尾

    到這裡,又瞭解了MVVM,同時也知道了ViewModel的作用,那麼久可以利用這個模式解決上面的時間顯示的問題了,


   新增類TimeViewModel,內容如下

    public class TimeViewModel : NotificationObject
    {
        private Time time;
        public Time Time
        {
            get
            {
                return this.time;
            }
            set
            {
                this.time = value;
                this.RaisePropertyChanged(() => this.time);
            }
        }

        public TimeViewModel()
        {
            time = new Time("1991","02","23");
            birthday = time.Year + "-" + time.Month + "-" + time.Day;
        }

        private string birthday;
        public string Birthday
        {
            get
            {
                return this.birthday;
            }
            set
            {
                this.birthday = value;
                this.RaisePropertyChanged("Birthday");
            }
        }


        public bool CanSubmit
        {
            get
            {
                return true;
            }
        }

        public void Submit1()
        {
            Birthday = time.Year + "-" + time.Month + "-" + time.Day;
        }

        public void Submit2()
        {
            Birthday = time.Month + "-" + time.Day + "-" + time.Year;
        }

    }
   在這個ViewModel裡,定義了一個用於顯示日期格式的字串Birthday,同時兩個方法Submit1()和Submit2()分別是兩個按鈕繫結的Click事件。

   此時View檢視內容為下

<UserControl x:Class="MVVMDemo.View.TimeView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
             xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
             xmlns:vm="clr-namespace:MVVMDemo.ViewModel"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="gridLayout">
        <Grid.DataContext>
            <vm:TimeViewModel />
        </Grid.DataContext>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="5*" />
            <ColumnDefinition Width="5*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="5*" />
            <RowDefinition Height="5*" />
            <RowDefinition Height="5*" />
            <RowDefinition Height="5*" />
        </Grid.RowDefinitions>

        <TextBlock Text="Time:" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        <TextBlock Text="{Binding Path=Birthday,Mode=Default}" Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left"/>

        <Button x:Name="Btn1" Content="按鈕1:年-月-日"  IsEnabled="{Binding CanSubmit}"  Grid.Row="2" Grid.Column="0" Width="150" Height="50" VerticalAlignment="Center" HorizontalAlignment="Right">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:CallMethodAction TargetObject="{Binding}" MethodName="Submit1"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>

        <Button x:Name="Btn2" Content="按鈕2:月-日-年"  IsEnabled="{Binding CanSubmit}"  Grid.Row="2" Grid.Column="1" Width="150" Height="50" VerticalAlignment="Center" HorizontalAlignment="Right">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <ei:CallMethodAction TargetObject="{Binding}" MethodName="Submit2"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</UserControl>

  編譯執行程式(該工程點此下載)

       

(2.23就快到我的生日了,不知道還有沒有人會記得呢,呵呵)

文章來源

感謝這位朋友!!你講的很易懂!!

相關推薦

WPF-MVVM模式學習筆記3——MVVM概念再次挖掘

     通過上篇文章<WPF-MVVM模式學習筆記2——MVVM簡單樣例>中舉了一個例子,我對MVVM大概有了一個比較淺顯的意思。同時,看過前兩篇文章的人,也知道我的這個系列的文章大多數來源於其他的部落格,我其實只是起了一個彙總的作用,畢竟我也是在學習,肯定是

WPF-MVVM模式學習筆記1——MVVM概念預覽

    畢業工作後的第一版軟體也漸漸接近尾聲,邊學邊做也算是能暫且滿足專案需求,但是還是不滿意,因為有之前的WINFORM換到WPF後,感覺根本沒有掌握WPF的核心,什麼繫結拉之類的用的不好。接下來的新專案的軟體準備採用MVVM模式設計,抓緊學一學,廢話不說,直接進入正題,

WPF-MVVM模式學習筆記2——MVVM簡單樣例

 一. MVVM理解     1. 先建立一個簡單的WPF樣例,並逐步將它重構成為MVVM模式。    這個Demo需求是:在介面上放置文字框用來顯示定義的類Student中的名字,放置Button來修改Student的名字。    剛建立好的樣例工程文件如下圖:    

NetApp DataONTAP 集群模式 學習筆記3

netapp dataontap 集群模式DATA SVMData SVM是安全多租戶的基本單元,它能將集群分區,以程現為多個不相關的SVM。每個SVM對客戶端程現為單個獨立的服務器。除非集群管理員開啟,否則在集群中流量不會SVM之間傳輸。如果不啟用多租戶,仍然需要至少一個DataSVM。SVM之前被稱之為v

設計模式學習筆記(3) --工廠方法

1.定義: 工廠方法模式(Factory Method Pattern)又稱為工廠模式,也叫虛擬構造器(Virtual Constructor)模式或者多型工廠(Polymorphic Factory)模式,它屬於類建立型模式。在工廠方法模式中,工廠父類負責定義建立產品物件的公共介面,而工廠子類

WPF學習筆記MVVM模式下,ViewModel如何關閉View?

矯枉過正,從一個極端走向另一個極端。MVVM模式,View只負責呈現,雖然也有後臺程式碼,但基本上就是擺設,VM接管了一切的邏輯處理。那麼,現在,大能的VM已經完成了所有的事情,這個視窗V如何才能自動關閉呢?據我目前少得可憐的WPF知識可知,有兩種方案:一、利用View裡的I

設計模式學習筆記(3)——命令者式

抽象 ring code 耦合度 引入 聲明 筆記 操作日誌 string Java設計模式之命令者式 引入命令模式 案列   比如我們要設計一個DOS命令模擬器,它可以接受輸入的命令並做出響應。   0.首先我們的DOS模擬器支持三個大類的功能:文件操作類(FileKit

redis 學習筆記3(哨兵模式下分布式鎖的實現以及全局唯一id的生成)

pin target 實現 sde 命令 記錄 興趣 mage incr redis實現分布式鎖和全局唯一id應該是較為常見的應用. 實現基於redis的setNX,以及incr命令.還是比較簡單的! 搭建環境以及配置好sping整合,做了下測試,有興趣的載下來看看,自己做

資料庫系統概念學習筆記3

  第三章 SQL 1.資料定義語言:提供定義關係模式、刪除關係以及修改關係模式的命令。 2.資料操縱語言:提供從資料庫中査詢資訊,以及在資料庫中插人元組、刪除元組、修改元組的能力。 3.完整性( integrity ): SQL DDL 包括定義完整性約束的命令,儲存在資料庫中的

數據庫系統概念學習筆記3

第三章 編程 完整 動態 sql mic 修改 auth mbed dynamic 第三章 SQL 1.數據定義語言:提供定義關系模式、刪除關系以及修改關系模式的命令。 2.數據操縱語言:提供從數據庫中査詢信息,以及在數據庫中插人元組、刪除元組、修改元組的能力。 3.完

【django3】Django學習筆記3:Model,Template,View 基本概念

轉載:http://www.cnblogs.com/weichsel/archive/2012/10/16/2725554.html,侵權必刪 總體結構         Django是MTV結構,即:Model, Template, View &nb

redis 學習筆記(3)-master/slave(主/從模式

類似mysql的master-slave模式一樣,redis的master-slave可以提升系統的可用性,master節點寫入cache後,會自動同步到slave上。 環境: master node: 10.6.144.155:7030 slave node:

ZooKeeper原始碼學習筆記(3)--Cluster模式下的ZooKeeper

Cluster叢集模式 前一篇文章 介紹了當配置檔案中只有一個server地址時,Standalone模式的啟動流程以及ZooKeeper的節點模型和執行邏輯。在本節中,我會針對Cluster的執行模式進行詳細講解。 啟動流程 public s

零基礎大資料HADOOP學習-筆記3-安全模式 safemode

【安全模式 safemode】 3種方式 方式一:Namenode的一種狀態,啟動時會自動進入安全模式,在安全模式,檔案系統不 允許有任何修改,“只讀不寫”。目的,是在系統啟動時檢查各個DataNod

計算廣告學習筆記3.1 受眾定向-受眾定向概念

來自於師徒網 劉鵬的講課,確實不錯,筆記記錄一下 彈窗廣告:有一個對於彈窗廣告的比喻很形象,某人去某家店鋪吃飯,經常會出現在去那家飯店吃飯的路上,很多沿途的小飯店的夥計跑出來拉客,誰先拉到客算誰的,這確實是對現在各種軟體的彈窗廣告的一個非常形象的比喻。(個人以為,這

設計模式學習筆記3):觀察者模式(2)

       上一篇的觀察者模式的筆記中提到的例子,只是Subject把自身狀態“推”給Observer的方式。 //通知觀察者資訊發生改變了 @Override public void notifyObservers() { for (

Android學習筆記MVVM----DataBinding(資料雙向繫結)

要把大象裝冰箱,總共三步! 第一步:在app.gradle中新增一下程式碼 第二步:建立一個普通bean類和XML檔案 注意:xml檔案的命名將影響生成的binding類名,如需要自定義b

設計模式學習筆記-適配器模式(對象適配器)

ring ons col class pat ima pub 不兼容 public 一、概述 將一個類的接口轉換為客戶希望的另外一個接口。Adapter模式使得原本由於接口不兼容而不能一起工作的那些類可以一起工作; 二、模式中的角色 Target:定

Redis學習筆記3-Redis5個可運行程序命令的使用

運行程序 檢查 mil 數據文件 img usr pre text mod 在redis安裝文章中,說到安裝好redis後,在/usr/local/bin下有5個關於redis的可運行程序。以下關於這5個可運行程序命令的具體說明。 redis-server Redi