# Chapter1: MVVM

## This section contain the following items:

* 1.MVVM (Model-View-ViewModel)
* 2.MVVM Example: META (MOXA Engineer Test Application
* 3.Two-Way Binding

## 1.MVVM (Model-View-ViewModel)

1.MVVM的優點是?

* 將與資料有關,及與UI有關的關注點分離
  * 把"狀態"跟使用者"介面"分開
  * 當對一個類別的改變需要牽動其他兩個類別, 而又會引起更多改變時, 這種現象稱為"shotgum surgery", 關注點分離可以防止這種問題的發生
* code能被重複使用
  * 例如我有很多個頁面, 但他們所binding的model並不全都100%相同, 如果有ViewModel
    * this.DataContext = this.plan\_ChidWindow\_NewTestPlan\_ListBoxViewModel;
  * Model, View可被重新使用

2.MVC跟MVVM的差別是?

* 角色 (Role):
  * Model (模型)
    * 用來表示與實作出應用程式內的各種資料物件，並且包含了商業處理邏輯。
  * View (檢視)
    * 表示應用程式中的使用者介面(UI)所要顯示的各個元件。
  * Controller or ViewModel
* MVC
  * 以 Model-View-Controller 來表示
  * Controller: 實踐了策略模式
    * 使用者接觸的對象用來處理使用者的互動與處理資料模型物件, 負責改變Model的狀態或是改變View的顯示
  * View:實踐了合成模式
    * 將內容顯示給使用者,要顯示的內容則是由Model取得
  * Model:實踐了觀察者模式
    * 當Model更新時,相關物件也會持續更新![](/files/-M4M0Lmv6WIuKphiGcaJ)
* MVVM
  * 以 Model-View-ViewModel 來表示
  * View: 通常會需要使用到 XAML 標記宣告語言來定義,而 XAML 僅僅提供了使用者介面的宣告,並無法提供任何處理邏輯
  * ViewModel:扮演這存取資料模型的責任,並且透過了資料繫結技術將資料提供給檢視。
  * 檢視僅知道檢視模型的存在,檢視模型僅知道模型的存在,而檢視模型並不知道檢視的存在,檢視也不知道模型的存在,因此充分做到的關注點分離的目的。

    ![](/files/-M4M0Lmx7J47GH_J6iDs)

3.Model, View, ViewModel: ![](/files/-M4M0Lmzu47MrVU2k2zz)

1\) Model :

* 儲存/產生資料, 通常來自服務或是資料庫
* 宣告軟體的核心函式(自己需要使用到的函式/其他物件所要用到的函式), 至於使用這些函數的時機,也可以透過宣告或是import Model到ViewModel中再使用
* Model記錄app目前的狀態,經常利用事件告訴app的其他部份狀態發生改變

  2\) View :
* 使用者直接與之互動的任何物件
* View可分為以下兩種: 1.User Control: (1)製作Template: 訂出將來所會綁定的Property, 觸發事件(需宣告在code behind中) (2)加入資料來源: 一般來說會將專案中所有的ViewModel用StaticResource放入

  ```
       xmlns:viewmodel="clr-namespace:WatchEample.ViewModel">
      <UserControl.Resources>
        <viewmodel:StopWatchViewModel x:Key="viewModel" x:Name="viewModel" />
      </UserControl.Resources>
      <Grid DataContext="{StaticResource ResourceKey=viewModel}">
    2.Page/Window:
      引用User Control, 以達到將視圖模組化的目的
      xmlns:view="clr-namespace:WatchEample.View">
      <view:BasicStopWatch Grid.Row="1" />
  ```

  3\) ViewModel :
* 具有能夠被繫結到View裡頭之控制項的特性&#x20;
* User Control不可放進ViewModel
* 與Model溝通 (1)建立Model與View間的溝通介面:包裝/使用Model所Release的函式 (2)建立所有與視圖有關的Class: 例如converter (3)Model內先定義好OnEventTrigger, 並寫好發動OnEventTrigger的時機; ViewModel則定義EventHandler, 並向Model註冊
* 與View溝通 雙向綁定: ViewModel本身implement INotifyPropertyChanged: (1)宣告: public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler propertyChanged = PropertyChanged; if(propertyChanged != null){ propertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } (2)觸發: 將會讓View中所綁定的欄位發生改變 OnPropertyChanged("LapSeconds"); ![](/files/-M4M0Ln0wRZg_Gx2wJfg)

  **2.MVVM Example**
* 1.需求
  * 要能達到以下的需求:
    * 1.可以做多台機器, 多種Model的測試
    * 2.可以得到realtime的測試情形
    * 3.使用者可以修改/編輯test plan
    * 4.使用者可以擴充test case
    * 5.測試完後可以自動產出test report
      * ![](/files/-M4M0Ln2zVUX3cW3T0rk)
* 2.WireFrame
  * Stage 2 - META的開發, 開發流程如下:

    ![](/files/-M4M0Ln4dfPi9PyTYArw)
  * 以繪圖軟體描繪出外觀作為後續開發的基礎

![](/files/-M4M0Ln6blx4LEy4H-X5)

![](/files/-M4M0Ln8C-rdRl9HL_oY)

* 3.Markdown & 設計軟體架構
  * 檢視wireframe的設計,在wpf實作上的可行性, 並進行修改及優化
  * MVVM: 1. 視圖模組化, 切換頁面要重新組合時十分便利(策略模式) 2. 無論是單一Window或是User Control會連結到的model數量跟種類都不同, 但是ViewModel可以重複利用 3. 在User Control中再嵌入User Control (合成模式)
  * business logic要放在M, V,還是VM? 個人認為: 1. 與按鈕等與視圖有關的功能:
    * 可放到View
    * 如果還可能被利用到其他視圖中, 則可放到ViewModel
      1. 與資料有關的功能,如產生資料則可放在Model

![](/files/-M4M0LnA7Vv2i9Fnb-a6)

![](/files/-M4M0LnCCXWpuuIFBTSX)

![](/files/-M4M0LnET9SHzg9rvFNp)

* 架構
  * META涵蓋了四個部分: Test Reporter, Test Launcher, Test Editor, Test Scripts Tranfer

![](/files/-M4M0LnGGIFRRY7JThGP)

![](/files/-M4M0LnIMtP_vbSLgwii)

* 4.操作 & 測試
  * 操作流程基本如下:

    ![](/files/-M4M0LnKPg34fREeiZCe)

## 3.Two-Way Binding

1\)何謂雙向綁定?

* WPF透過原生的XAML檔和CodeBehind的cs, 提供了開發者分層的開發環境

  可將程式的運算邏輯與設計分層.一旦View的值被調整, 後方的資料也會被調整; 反之後方設定了值,  &#x20;

  View所顯示的內容也會更著改變,這稱為雙向綁定.

2\)Example:

* 建立一個View, 裡面有Listbox, 裡面放了一個TextBlock, 一個Textbox

  TextBlock及Textbox將連結到同一個資料, 因此若使用者修改Textbox中的數值,

  TextBlock的數值也將跟著改變

3\)Cs:

1. 新增一個class: public class testObj : INotifyPropertyChanged { private string test2 = null; public testObj() { test1 = "1"; test2 = "2"; } public string Test2 { set { test2 = value; OnPropertyChanged(new PropertyChangedEventArgs("Test2")); } get { return test2; } } protected void OnPropertyChanged(PropertyChangedEventArgs e) { if (PropertyChanged != null) { PropertyChanged(this, e); } }

   ```
         #region INotifyPropertyChanged 成員
         public event PropertyChangedEventHandler PropertyChanged;
         #endregion
       }
   ```

   2.編輯MainWindows.cs: public partial class MainWindow : Window { public ObservableCollection moduleInfoList = new ObservableCollection(); public MainWindow() { InitializeComponent(); testObj module = new testObj(); this.moduleInfoList.Add(module); this.listBox.ItemsSource = this.moduleInfoList; } } 4)View (MainWindows.xaml):

   * 目的是將TextBlock及Textbox連結到testObj中的Test2, 因此在tag中加入Mode=TwoWay:

     &#x20;   \</Grid.ColumnDefinitions> \</Grid.RowDefinitions> \</DataTemplate > \</ListBox.ItemTemplate> \</ListBox >

Reference:

1\)<http://stackoverflow.com/questions/17967052/wpf-simple-binding-to-inotifypropertychanged-object>

2\)<http://www.codeproject.com/Articles/41817/Implementing-INotifyPropertyChanged>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jen-hsuan-hsieh.gitbook.io/design-pattern/chapter1.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
