<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      之乎者也,阿彌陀佛

      軟件設計的原則就是,化繁為簡,化難為易,把人的思維集中在簡單的領域,然后通過有序的組合實現復雜的邏輯。

        博客園  :: 首頁  :: 新隨筆  :: 聯系 :: 訂閱 訂閱  :: 管理

      賦值VS綁定

      要理解MVVM模式,最重要的是理解綁定的概念.做B/S或者對C/S理解不夠的程序員可能不了解"綁定",它與賦值類似,但又"高級"一點.

      一個簡單的類:

      public class MyClass
      {           
          public MyClass() {
              this._Time = DateTime.Now.ToString();
          }     
      
          private string _Time;
          public string Time {
              get {
                  return this._Time;
              }
              set {
                  this._Time = value;
              }
          }
      }

      賦值

      private void UpdateTime_Click(object sender, RoutedEventArgs e) {
          _MyClass.Time = DateTime.Now.ToString();
          this.lable1.Content = _MyClass.Time;
      }
      
      private void Grid_Loaded(object sender, RoutedEventArgs e) {
          this.lable1.Content = _MyClass.Time;
      }

      很簡單的對lable1的Content屬性的賦值.總結一下這種模式的流程圖:

      image

      這種模式很簡單,很容易理解.缺點也是很明顯,View跟CodeBehind緊緊耦合在一起了(事件方法里面需要知道lable1),還有到處都是this.lable1.Content = _MyClass.Time; 這樣的賦值代碼,這樣可維護性是很低的.于是就有了綁定.

      屬性綁定

      綁定就是把把東西關聯在一起,例如人的手腳是和整個身體綁定在一起的,手指受傷了,人會感到疼痛.屬性綁定通常是把一個Model屬性綁定給一個控件的屬性,于是它們就有了聯系,Model的屬性變化了,控件的屬性也會變化.

      wpf的綁定.

      首先把View的DataContext設為MyClass.

      <Window.DataContext>
          <local:MyClass />
      </Window.DataContext>
      

      這樣我們就可以把MyClass的屬性綁定給lable1的Content.

      <Label Grid.Column="1" Grid.Row="1" Content="{Binding Time}" />
      

      WinForm也能綁定:

      public Form1() {
          InitializeComponent();
          this.label2.DataBindings.Add("Text", _MyClass, "Time", true);
      }

      運行程序:

      image

      點擊Update Time按鈕,比較遺憾,綁定那一行的時間并沒有更新.看來需要做更多的工作.(見源碼Example1)

      INotifyPropertyChanged接口

      原來對于上面的那個poco類,它的屬性Time發生變化時,緊緊靠<Label Grid.Column="1" Grid.Row="1" Content="{Binding Time}" />或者this.label2.DataBindings.Add("Text", _MyClass, "Time", true); 是不夠的,lable不能"智能"地知道MyClass的Time變化了,需要MyClass主動去通知lable:我的Time屬性變化 了.INotifyPropertyChanged接口就是這樣的功能.

      INotifyPropertyChanged的源碼:

      // 摘要:向客戶端發出某一屬性值已更改的通知。
      public interface INotifyPropertyChanged
      {
          // 摘要:在更改屬性值時發生。
          event PropertyChangedEventHandler PropertyChanged;
      }

      PropertyChangedEventHandler里的事件參數源碼:

      // 摘要:為 System.ComponentModel.INotifyPropertyChanged.PropertyChanged 事件提供數據。
       public class PropertyChangedEventArgs : EventArgs
       {
           // 摘要:初始化 System.ComponentModel.PropertyChangedEventArgs 類的新實例。
           // 參數:propertyName:已更改的屬性名
           [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
           public PropertyChangedEventArgs(string propertyName);
      
           // 摘要:獲取已更改的屬性名。
           // 返回結果:已更改的屬性名。
           public virtual string PropertyName { get; }
       }

      接口非常簡單,就一個PropertyChanged事件,而事件委托的參數也很簡單,一個字符串屬性名.Model繼承 INotifyPropertyChanged后,在這個事件中是通知者的角色(執行事件),而<Label Grid.Column="1" Grid.Row="1" Content="{Binding Time}" />和this.label2.DataBindings.Add("Text", _MyClass, "Time", true); 這里可以理解為事件的訂閱.

      繼承INotifyPropertyChanged后的MyClass:

      public class MyClass : INotifyPropertyChanged
      {
          public MyClass() {
              this._Time = DateTime.Now.ToString();
          }
      
          private string _Time;
          public string Time {
              get {
                  return this._Time;
              }
              set {
                  if (this._Time != value) {
                      this._Time = value;
                      if (PropertyChanged != null) {
                          PropertyChanged(this, new PropertyChangedEventArgs("Time"));
                      }
                  }
              }
          }
      
          public event PropertyChangedEventHandler PropertyChanged;
      }

      重點是Set值時執行事件,運行程序發現,lable終于知道MyClass的屬性變化了,它們綁定了.而且可以發現綁定是雙向的,即控件的值更新,model的屬性值也會更新,添加一個按鈕顯示model的屬性值:

      private void Show_Click(object sender, RoutedEventArgs e) {
          MessageBox.Show(_MyClass.Time);
      }

      image

      這里做到了把Model的屬性綁定給View的控件的屬性中,下面看看集合的綁定.

      集合綁定

      跟上面一樣,普通的集合控件們是不認的,要用特殊的集合,它就是ObservableCollection<T>,它繼承了INotifyCollectionChanged和INotifyPropertyChanged.部分源碼:

       [Serializable]
       public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged
      一個簡單的類:
      public class Employe
      {
          public ObservableCollection<string> Employees { get; set; }
      
          public Employe() {
              Employees = new ObservableCollection<string>() 
              {
                  "肥貓", "大牛", "豬頭"
              };
          }
      }

      把它綁定到一個ComboBox中:

      <ComboBox Grid.Column="2" Grid.Row="0"  ItemsSource="{Binding Employees}" Width="50px"/>
      

      另外做一個按鈕添加來Employees

      private void AddDepartment_Click(object sender, RoutedEventArgs e) {
          _MyClass.Employees.Add(this.textBox1.Text);
      }

      運行程序,添加一個Employee,發現ComboBox也更新了(見源碼Example3).

      image

      命令綁定

      還有一個綁定就是命令綁定.實際解決的是要把View完全解耦,不用再寫控件事件,因為AddDepartment_Click這樣的寫法就會把View和CodeBehind的耦合在一起,跟上面屬性賦值類似.

      ICommand

      // 摘要:定義一個命令
      [TypeConverter("System.Windows.Input.CommandConverter, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, Custom=null")]
      [ValueSerializer("System.Windows.Input.CommandValueSerializer, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, Custom=null")]
      public interface ICommand
      {
          // 摘要: 當出現影響是否應執行該命令的更改時發生。
          event EventHandler CanExecuteChanged;
      
          // 摘要:定義用于確定此命令是否可以在其當前狀態下執行的方法。    
          // 參數:parameter:此命令使用的數據。如果此命令不需要傳遞數據,則該對象可以設置為null。
          // 返回結果:如果可以執行此命令,則為true;否則為false。
          bool CanExecute(object parameter);
          //
          // 摘要:定義在調用此命令時調用的方法。
          // 參數:parameter:此命令使用的數據。如果此命令不需要傳遞數據,則該對象可以設置為 null。
          void Execute(object parameter);
      }

      最主要需要實現的是Execute方法.即事件發生時要執行的方法.下面把Add Department的按鈕事件去掉,改為綁定一個命令.實現這個命令首先要得到的是textbox上的值.要在命令里得到View控件的值,可以在 model里新建一個屬性值與這個控件綁定,因為綁定是雙向的,所以屬性值就是控件的值.根據上面的Employe類添加如下代碼:

      private string _NewEmployee;
      public string NewEmployee {
          get {
              return this._NewEmployee;
          }
          set {
              if (this._NewEmployee != value) {
                  this._NewEmployee = value;
                  if (PropertyChanged != null)
                      PropertyChanged(this, new PropertyChangedEventArgs("NewEmployee"));
              }
          }
      }

      每個命令要實現為一個單獨的類,繼承ICommand,這里用一個委托把添加部門的邏輯轉移到Employe中:

      public class AddEmployeeCommand : ICommand
      {
          Action<object> _Execute;
          public AddEmployeeCommand(Action<object> execute) {
              _Execute = execute;
          }
      
          public bool CanExecute(object parameter) {
              return true;
          }
      
          public event EventHandler CanExecuteChanged {
              add { CommandManager.RequerySuggested += value; }
              remove { CommandManager.RequerySuggested -= value; }
          }
      
          public void Execute(object parameter) {
              _Execute(parameter);
          }
      }

      Employe類再添加一個ICommand用作綁定:

      private ICommand _AddEmployee;
      public ICommand AddEmployee {
          get {
              if (_AddEmployee == null) {
                  _AddEmployee = new AddEmployeeCommand((p) =>
                  {
                      Employees.Add(NewEmployee);
                  });
              }
              return _AddEmployee;
          }
      }
      有了AddEmployee 我們就可以綁定到按鈕中:
      <Button Grid.Column="0" Grid.Row="0" Content="Add Department" Command="{Binding AddEmployee}" />
      

      到這里,我們可以得到跟上面一樣的功能,但成功把按鈕事件改為了命令綁定.(見源碼Example4)

      完成上面所有工作,我們解決了一個問題,即View"后面"的模塊(Code Behind也好,Model也好)完全沒了view的影子,"后面"的模塊不用管textbox還是Label來顯示一個Name,只管把Name賦值 就好了,也不用關心一個button還是一個picturebutton來點擊,只管實現邏輯.但細心觀察,代碼還是有不少問題.

      其中最主要的是為了實現上面的功能,污染了Employe這個類.Employe應該是常見的Model層中的一個類,它應該是一個poco類,職 責是定義領域模型和模型的領域(業務)邏輯.為了實現綁定,添加了各種接口和與領域(業務)無關的屬性,這就是對Model的污染.所以,當想實現綁定, 而又不想污染model,就得引入新的一層--ViewModel,這樣就走向了MVVM模式.

      MVVM模式

      VM是MVVM的核心.主要作用有兩個.

      1.提供屬性和命令供View綁定

      2.還要承擔MVC模式中C(Controller)的職責,作為View和業務層的中間人.

      模式實踐.

      把上面的代碼稍為修改即可以改為MVVM模式.

      Model,Employee回歸Poco:

      public class Employee
      {
          public string Name { get; set; }
          public string Email { get; set; }
          public string Phone { get; set; }
      
          public void Add() {
              DataBase.AllEmployees.Add(this);
          }
      }

      ViewModel提供綁定的屬性和命令:

      public class EmployeeViewModel : INotifyPropertyChanged
         {
             public event PropertyChangedEventHandler PropertyChanged;
      
             /// <summary>
             /// 供ComboBox綁定
             /// </summary>
             public ObservableCollection<Employee> Employees { get; set; }
      
             public EmployeeViewModel() {
                 Employees = new ObservableCollection<Employee>(DataBase.AllEmployees);
             }
      
             #region 供textbox綁定      
             private string _NewEmployeeName;
             public string NewEmployeeName {
                 get {
                     return this._NewEmployeeName;
                 }
                 set {
                     if (this._NewEmployeeName != value) {
                         this._NewEmployeeName = value;
                         if (this.PropertyChanged != null) {
                             PropertyChanged(this, new PropertyChangedEventArgs("NewEmployeeName"));
                         }
                     }
                 }
             }
      
             private string _NewEmployeeEmail;
             public string NewEmployeeEmail {
                 get {
                     return this._NewEmployeeEmail;
                 }
                 set {
                     if (this._NewEmployeeEmail != value) {
                         this._NewEmployeeEmail = value;
                         if (this.PropertyChanged != null) {
                             PropertyChanged(this, new PropertyChangedEventArgs("NewEmployeeEmail"));
                         }
                     }
                 }
             }
      
             private string _NewEmployeePhone;
             public string NewEmployeePhone {
                 get {
                     return this._NewEmployeePhone;
                 }
                 set {
                     if (this._NewEmployeePhone != value) {
                         this._NewEmployeePhone = value;
                         if (this.PropertyChanged != null) {
                             PropertyChanged(this, new PropertyChangedEventArgs("NewEmployeePhone"));
                         }
                     }
                 }
             }
             #endregion
      
             public ICommand AddEmployee {
                 get {
                     return new RelayCommand(new Action(() =>
                                 {
                                     if (string.IsNullOrEmpty(NewEmployeeName)) {
                                         MessageBox.Show("姓名不能為空!");
                                         return;
                                     }
                                     var newEmployee = new Employee { Name = _NewEmployeeName, Email = _NewEmployeeEmail, Phone = _NewEmployeePhone };
                                     newEmployee.Add();
                                     Employees.Add(newEmployee);
                                 }));
                 }
             }
         }

      代碼的職責非常明確,提供5個屬性(1個命令,4個普通屬性)供View綁定.雖然簡單,但卻產生了一大堆代碼,可能這就是MVVM框架出現的原因.不管怎樣,一個簡單的MVVM模式的Simple就完成了(參考代碼Example5).

      MVVM:mvvm.png

       

       

      MVVM:mvvm.png

      參考:鏈接

      原文:http://www.rzrgm.cn/lemontea/archive/2011/11/26/2264168.html   示例源碼

      posted on 2012-05-16 18:02  搏擊的小船  閱讀(293)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲精品日韩精品久久| 蜜臀av久久国产午夜| 熟妇的味道hd中文字幕| 日韩av在线一卡二卡三卡| 蜜桃视频在线免费观看一区二区| 精品国产中文字幕av| 午夜免费视频国产在线| 正在播放的国产A一片| 一本无码av中文出轨人妻| 国产超碰人人做人人爱| 狠狠做五月深爱婷婷天天综合 | 国产精品天天看天天狠| 亚洲 校园 欧美 国产 另类| 读书| 成年午夜免费韩国做受视频| 精品亚洲国产成人av制服| 国产精品亚洲二区亚瑟| 亚洲国产成人久久精品不卡| 国产成人片无码视频在线观看| 久久国产精品99久久蜜臀| 天堂V亚洲国产V第一次| 强奷漂亮人妻系列老师| 亚洲av日韩av永久无码电影| 中文字幕在线日韩| 尤物国产精品福利在线网| 九九在线精品国产| 久久久久香蕉国产线看观看伊| 国产亚洲精品久久久久婷婷图片| 特级做a爰片毛片免费看无码| 囯产精品一区二区三区线| 大胆欧美熟妇xxbbwwbw高潮了 | 双乳奶水饱满少妇呻吟免费看| 国产精品自拍中文字幕| 91人妻熟妇在线视频| 蜜桃视频在线免费观看一区二区| 亚洲精品一区二区三区大桥未久| 日韩人妻一区中文字幕| 天天摸天天做天天爽水多| 99在线国内在线视频22| 色又黄又爽18禁免费网站现观看| 无码丰满人妻熟妇区|