MVVM単純な例 - 2つのノートを学習WPF-MVVMパターン

 A. MVVMを理解します  

  1.簡単なWPFのサンプルを作成し、徐々にそれがMVVMパターンの再構築になります。

   この要件はデモです:学生定義されたクラス名を表示するには、画面上の場所のテキストボックスには、学生の名前を変更するためにボタンを配置しました。

   以下のようにちょうど良いサンプルプロジェクトのドキュメントを作成します。

   

  その後、Studentクラスを追加

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MVVMDemo
{
    public class Student : INotifyPropertyChanged
    {
        string firstName;
        public string FirstName
        {
            get
            {
                return firstName;
            }
            set
            {
                firstName = value;
                OnPropertyChanged("FirstName");
            }
        }

        string lastName;
        public string LastName
        {
            get
            {
                return lastName;
            }
            set
            {
                lastName = value;
                OnPropertyChanged("LastName");
            }   
        }

        public Student(string firstName, string lastName)
        {
            this.firstName = firstName;
            this.lastName = lastName;
        }


        void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
    }
}

   このとき、図エンジニアリングの以下の構成図

  

   その後、次のようにMainWindow.xamlを変更

<Window x:Class="MVVMDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid x:Name="gridLayout">
        <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="FirstName:" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        <TextBlock Text="{Binding Path=FirstName,Mode=TwoWay}" Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left"/>
        <TextBlock Text="LastName:" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        <TextBox Text="{Binding Path=LastName,Mode=TwoWay}" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left"/>
        <Button x:Name="BtnView" Content="I am View" Grid.Row="2" Grid.Column="0" Width="150" Height="50" VerticalAlignment="Center" HorizontalAlignment="Right"/>
    </Grid>
</Window>

ショーメインウィンドウビュー下図


   その後、MainWindow.csに以下を追加します

        public MainWindow()
        {
            InitializeComponent();
            Student student = new Student("Wang", "WenSong");
            gridLayout.DataContext = student;
            BtnView.Click += new RoutedEventHandler(delegate(object sender, RoutedEventArgs e)
                {
                    student.FirstName = "BBK工作室";
                    student.LastName = "www.bigbearking.com";
                });
        }


   この場合、プログラムを実行すると、次の図


ボタンBtnView、この時間以下のインターフェイスをクリックします


    上記のコードの作品は、こちらからダウンロードしてください

   2.ここでの問題

      私たちは、ページの価値を聞かせする必要があり、学生のインスタンス値を使用すると、INotifyPropertyChangedインターフェイスからタイプの継承をしなければならない、一貫性を維持し、次のようにコーディングされている場合:

public class Student : INotifyPropertyChanged
    {
        string firstName;
        public string FirstName
        {
            get
            {
                return firstName;
            }
            set
            {
                firstName = value;
                OnPropertyChanged("FirstName");
            }
        }

        string lastName;
        public string LastName
        {
            get
            {
                return lastName;
            }
            set
            {
                lastName = value;
                OnPropertyChanged("LastName");
            }   
        }

        public Student(string firstName, string lastName)
        {
            this.firstName = firstName;
            this.lastName = lastName;
        }


        void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
    }

  そのような教師がクラスのようなタイプのアプリケーションが複数ある場合、各クラスは、その実現しなければならない明らかに無理であるOnPropertyChangedをする方法を、。そこで、我々はINotifyPropertyChangedのからのスーパークラスの継承、当然のことながら、この需要をラップするためにスーパークラスが必要です。

   3.次に、エンジニアリングのスーパークラスのNotificationObject、図の構造を追加します。


スーパークラスのコード

    public abstract class NotificationObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected void RaisePropertyChanged(params string[] propertyNames)
        {
            if (propertyNames == null) throw new ArgumentNullException("propertyNames");

            foreach (var name in propertyNames)
            {
                this.RaisePropertyChanged(name);
            }
        }

        protected void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
        {
            var propertyName = ExtractPropertyName(propertyExpression);
            this.RaisePropertyChanged(propertyName);
        }

        public static string ExtractPropertyName<T>(Expression<Func<T>> propertyExpression)
        {
            if (propertyExpression == null)
            {
                throw new ArgumentNullException("propertyExpression");
            }

            var memberExpression = propertyExpression.Body as MemberExpression;
            if (memberExpression == null)
            {
                throw new ArgumentException("PropertySupport_NotMemberAccessExpression_Exception", "propertyExpression");
            }

            var property = memberExpression.Member as PropertyInfo;
            if (property == null)
            {
                throw new ArgumentException("PropertySupport_ExpressionNotProperty_Exception", "propertyExpression");
            }

            var getMethod = property.GetGetMethod(true);
            if (getMethod.IsStatic)
            {
                throw new ArgumentException("PropertySupport_StaticExpression_Exception", "propertyExpression");
            }

            return memberExpression.Member.Name;
        }

    }

  したがって、学生のタイプを次のように変更されます。

  

    public class Student : NotificationObject
    {
        string firstName;
        public string FirstName
        {
            get
            {
                return firstName;
            }
            set
            {
                firstName = value;
                //OnPropertyChanged("FirstName");
                this.RaisePropertyChanged("FirstName");
            }
        }

        string lastName;
        public string LastName
        {
            get
            {
                return lastName;
            }
            set
            {
                lastName = value;
                //OnPropertyChanged("LastName");
                this.RaisePropertyChanged("LastName");
            }   
        }

        public Student(string firstName, string lastName)
        {
            this.firstName = firstName;
            this.lastName = lastName;
        }


        void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
    }

     コードのこの部分は、ダウンロードするにはここをクリック

    4.問題があるどのようなタイプの学生を介して変更、再び起こりますか?

      エンティティモデル、フィールドモデル、または何か他のものですか?実際には、任意のモード・アーキテクチャを使用していないため、現在の学生の種類は何も、その他の機能の多くをこします。これは、プロパティを提供する責任があり、また制御する責任があります。

      MVVMアーキテクチャモードでは、異なる場所にタイトルとMVC、すなわち、VM(ビューモデル)セクション。ビューは要求を受け入れ、要求を処理するためにどのモデルコンポーネントの呼び出しを決定するが、それはまた、ディスプレイのためのビューへのデータバックに責任がある:VMは責任があります。それは、VMの役割はMVC制御が完了すると理解することができるされています。(またなお、MVCモデルのパフォーマンスと呼ばれる概念があり、モデルの性能は、フラットフィールド投影モデルと呼ばれ、MVVMは、ビューモデルに混乱しません)。

    そこで、我々は今、これらの概念をクリアしたいです。まず、機能的なセグメンテーション、VMセクションの学生の種類は、我々はそれがMainViewModel呼ばれるべきページの名前に対応しています。ページが機能する実際のプロジェクトでは、それに応じて、対応するVM名はStudentViewModel.cs呼ばれる、StudentView.xaml命名します。私たちは、上記のコードを再構築し続けています。

II。MVVMのさまざまな部分を確立

    構造変化は今のコードをリファクタリング、プロジェクトが比較的大きいですが、私はこのコードの一部も渡される入れます。

    まず、以下に示すように、元のプロジェクトに3つのフォルダのモデル、ビュー、ビューモデルを作成すること

    

   モデル部ドメインモデルの分野

   その後Student.csは、モデルフォルダを移動し、Student.csにコードを修正し、次のようにStudent.cs内容は(ノートの変更の名前空間)に変更します

  

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MVVMDemo.Model
{
    public class Student
    {
        string firstName;
        public string FirstName
        {
            get
            {
                return firstName;
            }
            set
            {
                firstName = value;
            }
        }

        string lastName;
        public string LastName
        {
            get
            {
                return lastName;
            }
            set
            {
                lastName = value;
            }   
        }

        public Student()
        {
            //模拟获取数据
            //这里为什么会有模拟数据一说呢?我是这样认为的,有时候类的属性会存在数据库或者本地文件系统等上面,
            //我们需要读取操作将这些数据加载到咱们定义的类里。
            Mock();
        }

        public void Mock()
        {
            FirstName = "firstName:" + DateTime.Now.ToString();
            LastName = "lastName:" + DateTime.Now.ToString();
        }


    }
}
   この時点で、プロジェクトのファイル構造は下図になり

   

   2.ViewModelパーツ

   以下のように、クラスStudentViewModel ViewModelにフォルダを追加するために、右クリックして次に、

   

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MVVMDemo.Model;

namespace MVVMDemo.ViewModel
{
    public class StudentViewModel:NotificationObject
    {
        private Student student;
        public Student Student
        {
            get
            {
                return this.student;
            }
            set
            {
                this.student = value;
                //下面这一句话的用法以后再拿出一章具体介绍
                this.RaisePropertyChanged(() => this.student);
            }
        }

        public StudentViewModel()
        {
            student = new Student();
        }

    }
}

   この時点で、次の描画のためのプロジェクトファイル構造

   

  3.View一部

  その後、再び次のために、StudentViewという名前のビューのフォルダにそのXAMLコードをユーザーコントロールを追加

  

<UserControl x:Class="MVVMDemo.View.StudentView"
             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:vm="clr-namespace:MVVMDemo.ViewModel"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="gridLayout">
        <Grid.DataContext>
            <vm:StudentViewModel />
        </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="FirstName:" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        <TextBlock Text="{Binding Path=Student.FirstName,Mode=Default}" Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left"/>
        <TextBlock Text="LastName:" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        <TextBox Text="{Binding Path=Student.LastName,Mode=TwoWay}" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left"/>
        <Button x:Name="BtnView" Content="I am View" Grid.Row="2" Grid.Column="0" Width="150" Height="50" VerticalAlignment="Center" HorizontalAlignment="Right"/>
    </Grid>
</UserControl>
  XAMLコードはいくつかの変更をバインドすることを通知は、代わりに、姓と名の、Student.FirstNameとStudent.LastNameをバインドされています。

  この時点で、プロジェクトファイルの画像は下図の構造を示しています

  

   次のように続いて、このコントロールを参照するために、メイン・ウィンドウが必要で、MainWindow.xamlコードを読み込み、変更

   

<Window x:Class="MVVMDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:view="clr-namespace:MVVMDemo.View"
        Title="MainWindow" Height="350" Width="525">
    <Grid >
        <view:StudentView />
    </Grid>
</Window>

   次いで、削除MainWindow.csを添加する前のコードで、修正されたコンテンツは、以下

   

using System;
using System.Collections.Generic;
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;

namespace MVVMDemo
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

        }
    }
}

   プロジェクトをコンパイルし、図で結果を実行します

   

  コードの部分は、ダウンロードするにはここをクリック

   4.いくつかの説明

   プロジェクトでは、データがから来ているデモは、ドメインモデル学生がデータを取得する責任があり、私たちの関心の焦点では​​ない(おそらくデータベース、それはコンフィギュレーション・ファイルである、などがあります)、私たちは、学生に直接アナログを得るように、プロセスデータ、すなわち模擬方法。これは、データのみUIの相互作用の完全な機能の一部とみなすことができる背景表示に前景にプッシュされ、一方向の処理の完了に相当します。UIの相互作用はまた、永続的なUI(例えば、データベースに保存された)からのデータを含める必要があります。背景を持つUIとの相互作用は、あなたがバインド順を達成するためのメカニズムを通過する必要があります。

   5. BINDコマンド

     次のプロジェクトでは、我々は一つのコマンドは、属性クラスを結合されたコマンドの2種類を、実証し、クラスがバインディングクラスのイベントコマンドです。

     まず第一に、私たちはその連絡先はUIとドメインモデルVMを担当して知っているので、結合方法は、VMでサポートされている必要があり、我々は、プロパティCanSubmitを定義し、送信中StudentViewModelのメソッドので、

     

        public bool CanSubmit
        {
            get
            {
                return true;
            }
        }

        public void Submit()
        {
            student.Mock();
        }

    次StudentViewModelのこの時点で、内容

    

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MVVMDemo.Model;

namespace MVVMDemo.ViewModel
{
    public class StudentViewModel:NotificationObject
    {
        private Student student;
        public Student Student
        {
            get
            {
                return this.student;
            }
            set
            {
                this.student = value;
                //下面这一句话的用法以后再拿出一章具体介绍
                this.RaisePropertyChanged(() => this.student);
            }
        }

        public StudentViewModel()
        {
            student = new Student();
        }

        public bool CanSubmit
        {
            get
            {
                return true;
            }
        }

        public void Submit()
        {
            student.Mock();
        }

    }
}

    上記の方法は、単純化のためのシミュレーション手法を提出することに注意してください。モックの方法は依然としてUIの変化に関連する可能性があるので(例えば、ある特定の変動値データベース上変化する)ので、技術も継承モデル学生NotificationObjectする必要があるかもしれません、本実施形態では、次のように学生を変更します

  

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MVVMDemo.Model
{
    public class Student : NotificationObject
    {
        string firstName;
        public string FirstName
        {
            get
            {
                return firstName;
            }
            set
            {
                firstName = value;
                this.RaisePropertyChanged("FirstName");
            }
        }

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

        public Student()
        {
            //模拟获取数据
            //这里为什么会有模拟数据一说呢?我是这样认为的,有时候类的属性会存在数据库或者本地文件系统等上面,
            //我们需要读取操作将这些数据加载到咱们定义的类里。
            Mock();
        }

        public void Mock()
        {
            FirstName = "firstName:" + DateTime.Now.ToString();
            LastName = "lastName:" + DateTime.Now.ToString();
        }
    }
}

    第二に、あなたはVIEWコマンドを使用すると、結合特性に起因するStudentViewを、変更する必要があり、我々は2つの参照を追加する必要があります

   

   あなたはこれらの2つの参照を追加した後、内容修正StudentView.xamlは、次のとおりです。

   

<UserControl x:Class="MVVMDemo.View.StudentView"
             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:StudentViewModel />
        </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="FirstName:" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        <TextBlock Text="{Binding Path=Student.FirstName,Mode=Default}" Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left"/>
        <TextBlock Text="LastName:" Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center"/>
        <TextBox Text="{Binding Path=Student.LastName,Mode=TwoWay}" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left"/>
        <Button x:Name="BtnView" Content="I am View"  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="Submit"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</UserControl>

   コンパイルして実行は、ボタンBtnViewをクリックして、あなたは本当のコンテンツの更新を確認することができます。

  上記のプロジェクトコードは、ダウンロードするにはここをクリック

   声明の後6

   この時間の再建の後、基本的にシンプルなMVVMモデルのニーズを満たすため、私はまた、MVVMについての知識を持っていますが、学習プロセスはまた、ラムダクラスNotificationObjectのように、私が探求し続ける必要があると問題のいくつかに設計されています表現だけでなく、コマンドバインディング。この研究は、ノートシリーズは終わっていない、ステップバイステップでは、来ます。

   フィルムは、この記事の大半から来ている:http://www.cnblogs.com/luminji/archive/2011/05/27/2060127.html、著者は彼の感謝を表明!!!ロゴを身に着けているため、元の理由は、線でノックアウトライン自分の言葉のために、そして自分のアイデアのいくつかをドープするだけでなく、それを所有するよう奨励されます。

公開された143元の記事 ウォンの賞賛161 ビュー121万+

おすすめ

転載: blog.csdn.net/mybelief321/article/details/44423845