WPF MVVM 入門示例講解


M-V-VM是Model-View-ViewModel的簡寫,Model,ViewModel是個類文件(.cs文件),View是前台文件(,xaml文件)。假設我們的工程只有一個前台文件和一個后台文件,當設計要求越來越多的時候,前后台文件可能會高達上千行,甚至上萬行,此時要想找到對應的代碼,鼠標滾輪會滑的頭大。學習MVVM便於工程調試,修改,移植。用MVVM如果只是修改或者更好顯示界面,后台文件只需稍微的改動甚至不用改動。下面這個例子是V-VM模式就是view和viewmodel,先以簡單的入門,工程集如下:

 

<Window x:Class="Students.View"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Students"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>

        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid x:Name ="StudetGrid"  Grid.Row ="0">
            <Grid.DataContext>
                <!--聲明創建一個ViewModel的實例,這個聲明確定了ViewModel.cs是VM,這個聲明建立了View.xaml與ViemModel之間的橋梁,這個myGrid所有綁定的屬性(Name,Age,Sex)都值的是ViewModel.cs類中的成員-->
                <local:StudetViewModel/>
            </Grid.DataContext>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <TextBlock Text="姓名:" Grid.Column="0" HorizontalAlignment="Right"/>
            <TextBlock Text="{Binding Name}" Grid.Column="1"/>
            <TextBlock Text="年齡:" Grid.Column="2" HorizontalAlignment="Right"  />
            <TextBlock Text="{Binding Age}" Grid.Column="3" />
            <TextBlock Text="性別:" Grid.Column="4" HorizontalAlignment="Right" />
            <TextBlock Text="{Binding Sex}" Grid.Column="5"/>
            <Button Content="更新" Grid.Column="6" Click="BtnClick" />

        </Grid>
    </Grid>
</Window>
View.xaml
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 Students
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class View : Window
    {
        public static StudetViewModel viewModel;//聲明一個類,但是沒有實例化,把這個viewModel設為static方便其他頁面文件互相訪問綁定的屬性
        public View()
        {
            InitializeComponent();
            viewModel = StudetGrid.DataContext as StudetViewModel;//在構造方法中實例化viewModel,這個viewModel就是View.xaml中聲明的那個ViewModel實例,就是那個橋梁。
        }

        private void BtnClick(object sender, RoutedEventArgs e)
        {
            viewModel.Name = "小明";
            viewModel.Age = "15";
            viewModel.Sex = "";
        }
    }
}
View.xaml.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace Students
{
    public class StudetViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private string name;
        public String Name
        {
            get { return name; }
            set { name = value; OnPropertyChanged("Name"); }
        }

        private string age;
        public String Age
        {
            get { return age; }
            set { age = value; OnPropertyChanged("Age"); }
        }

        private string sex;
        public String Sex
        {
            get { return sex; }
            set { sex = value; OnPropertyChanged("Sex"); }
        }
    }
}
StudetViewModel.cs

View.xaml是View,那如何確定StudetViewModel.cs就是VM呢?在View.xaml文件中有如下聲明

 

 在前台文件中聲明數據上下文指定類,指定的那個類就是ViewModel。先看一下運行效果吧

 

 

 

 這個工程文件里的StudetViewModel.cs其實就是Model和ViewModel合在一起了

 

 增加完Model類后的程序集如下:

 

 如何確定PeronModel就Model呢?因為它在ViewModel中有實例化

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace Students
{
    public class StudetViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }


        private PersonModel _studentModel = new PersonModel();//實例化Model中的類
        public PersonModel StudentModel
        {
            get { return _studentModel; }
            set { _studentModel = value; OnPropertyChanged("StudentModel"); }
        }
    }
}
StudetViewModel
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace Students
{
    public class PersonModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private string name;
        public String Name
        {
            get { return name; }
            set { name = value; OnPropertyChanged("Name"); }
        }

        private string age;
        public String Age
        {
            get { return age; }
            set { age = value; OnPropertyChanged("Age"); }
        }

        private string sex;
        public String Sex
        {
            get { return sex; }
            set { sex = value; OnPropertyChanged("Sex"); }
        }
    }
}
Students
<Window x:Class="Students.View"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Students"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>

        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid x:Name ="StudetGrid"  Grid.Row ="0">
            <Grid.DataContext>
                <!--聲明創建一個ViewModel的實例,這個聲明確定了ViewModel.cs是VM,這個聲明建立了View.xaml與ViemModel之間的橋梁,這個myGrid所有綁定的屬性(Name,Age,Sex)都值的是ViewModel.cs類中的成員-->
                <local:StudetViewModel/>
            </Grid.DataContext>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <TextBlock Text="姓名:" Grid.Column="0" HorizontalAlignment="Right"/>
            <TextBlock Text="{Binding StudentModel.Name}" Grid.Column="1"/>
            <TextBlock Text="年齡:" Grid.Column="2" HorizontalAlignment="Right"  />
            <TextBlock Text="{Binding StudentModel.Age}" Grid.Column="3" />
            <TextBlock Text="性別:" Grid.Column="4" HorizontalAlignment="Right" />
            <TextBlock Text="{Binding StudentModel.Sex}" Grid.Column="5"/>
            <Button Content="更新" Grid.Column="6" Click="BtnClick" />

        </Grid>
    </Grid>
</Window>
View
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 Students
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class View : Window
    {
        public static StudetViewModel viewModel;//聲明一個類,但是沒有實例化,把這個viewModel設為static方便其他頁面文件互相訪問綁定的屬性
        public View()
        {
            InitializeComponent();
            viewModel = StudetGrid.DataContext as StudetViewModel;//在構造方法中實例化viewModel,這個viewModel就是View.xaml中聲明的那個ViewModel實例,就是那個橋梁。
        }

        private void BtnClick(object sender, RoutedEventArgs e)
        {
            viewModel.StudentModel.Name = "小明";
            viewModel.StudentModel.Age = "15";
            viewModel.StudentModel.Sex = "";
        }
    }
}
View.xaml.cs

View中實例化過ViewModel,而ViewModel中實例化過Model,所以說ViewModel建立起了View與Model之間溝通的橋梁。一個ViewModel類中可以有多個不同的Model類的實例,比如我們還可以創建一個成績類(Model),然后在ViewModel中去實例化,最后在View界面中去綁定各科成績,這個好理解。

View中也可以實例化多個ViewModel

程序集如下:

 

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace Students
{
    public class TeacherViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }


        private PersonModel _teacherModel = new PersonModel();//實例化Model中的類
        public PersonModel TeacherModel
        {
            get { return _teacherModel; }
            set { _teacherModel = value; OnPropertyChanged("TeacherModel"); }
        }
    }
}
TeacherViewModel
<Window x:Class="Students.View"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Students"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>

        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid x:Name ="StudetGrid"  Grid.Row ="0">
            <Grid.DataContext>
                <!--聲明創建一個ViewModel的實例,這個聲明確定了ViewModel.cs是VM,這個聲明建立了View.xaml與ViemModel之間的橋梁,這個myGrid所有綁定的屬性(Name,Age,Sex)都值的是ViewModel.cs類中的成員-->
                <local:StudetViewModel/>
            </Grid.DataContext>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <TextBlock Text="學生姓名:" Grid.Column="0" HorizontalAlignment="Right"/>
            <TextBlock Text="{Binding StudentModel.Name}" Grid.Column="1"/>
            <TextBlock Text="年齡:" Grid.Column="2" HorizontalAlignment="Right"  />
            <TextBlock Text="{Binding StudentModel.Age}" Grid.Column="3" />
            <TextBlock Text="性別:" Grid.Column="4" HorizontalAlignment="Right" />
            <TextBlock Text="{Binding StudentModel.Sex}" Grid.Column="5"/>
            <Button Content="更新" Grid.Column="6" Click="BtnClick" />

        </Grid>
        <Grid x:Name ="TeacherGrid"  Grid.Row ="1">
            <Grid.DataContext>
                <!--聲明創建一個ViewModel的實例,這個聲明確定了ViewModel.cs是VM,這個聲明建立了View.xaml與ViemModel之間的橋梁,這個myGrid所有綁定的屬性(Name,Age,Sex)都值的是ViewModel.cs類中的成員-->
                <local:TeacherViewModel/>
            </Grid.DataContext>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <TextBlock Text="老師姓名:" Grid.Column="0" HorizontalAlignment="Right"/>
            <TextBlock Text="{Binding TeacherModel.Name}" Grid.Column="1"/>
            <TextBlock Text="年齡:" Grid.Column="2" HorizontalAlignment="Right"  />
            <TextBlock Text="{Binding TeacherModel.Age}" Grid.Column="3" />
            <TextBlock Text="性別:" Grid.Column="4" HorizontalAlignment="Right" />
            <TextBlock Text="{Binding TeacherModel.Sex}" Grid.Column="5"/>
            <Button Content="更新" Grid.Column="6" Click="BtnClickTeacher" />

        </Grid>
    </Grid>
</Window>
View.xaml
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 Students
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class View : Window
    {
        public static StudetViewModel studentViewModel;//聲明一個類,但是沒有實例化,把這個viewModel設為static方便其他頁面文件互相訪問綁定的屬性
        public static TeacherViewModel teacherViewModel;
        public View()
        {
            InitializeComponent();
            studentViewModel = StudetGrid.DataContext as StudetViewModel;//在構造方法中實例化viewModel,這個viewModel就是View.xaml中聲明的那個ViewModel實例,就是那個橋梁。
            teacherViewModel = TeacherGrid.DataContext as TeacherViewModel;
        }

        private void BtnClick(object sender, RoutedEventArgs e)
        {
            studentViewModel.StudentModel.Name = "小明";
            studentViewModel.StudentModel.Age = "15";
            studentViewModel.StudentModel.Sex = "";
        }

        private void BtnClickTeacher(object sender, RoutedEventArgs e)
        {
            teacherViewModel.TeacherModel.Name = "王老師";
            teacherViewModel.TeacherModel.Age = "30";
            teacherViewModel.TeacherModel.Sex = "";
        }
    }
}
View.xaml.cs

效果如下:

 上面的示例中,控件的成員屬性和View分開了,但是按鍵的Click事件內容還是在后台文件實現的,那怎么把事件屬性也和View分開呢?

<Button Content="更新" Grid.Column="6" Command="{Binding CommadUpdata}" />
View Code

把Button 的Click用Commad代替,以TeacherViewModel例

using Prism.Commands;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace Students
{
    public class TeacherViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }


        private PersonModel _teacherModel = new PersonModel();//實例化Model中的類
        public PersonModel TeacherModel
        {
            get { return _teacherModel; }
            set { _teacherModel = value; OnPropertyChanged("TeacherModel"); }
        }

        public TeacherViewModel()
        {
            this.CommadUpdata = new DelegateCommand(new Action(Updata));//命令屬性與方法聯系起來
        }

        private void Updata()//方法
        {
            this.TeacherModel.Name = "王老師";
            this.TeacherModel.Age = "30";
            this.TeacherModel.Sex = "";
        }

        public DelegateCommand CommadUpdata { get; set; }//命令屬性
    }
}
TeacherViewModel

StudentViewModel也是類似,這樣改完后,后台文件View.xaml.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 Students
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class View : Window
    {
        public View()
        {
            InitializeComponent();
        }
    }
}
View.xaml.cs

這樣成員屬性和命令屬性都和前台文件去耦合了

 源碼下載地址:https://github.com/lizhiqiang0204/WPF_MVVM_Demo


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM