zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Python for Infomatics 第14章 数据库和SQL应用四(译)
    展望2017
    bing的简单英文字典工具
    自我安慰
    Python for Infomatics 第14章 数据库和SQL应用三(译)
    Python for Infomatics 第14章 数据库和SQL应用二(译)
    Python for Infomatics 第14章 数据库和SQL应用一(译)
    希望父亲早日恢复
    Python for Infomatics 第13章 网页服务四(译)
    Python for Infomatics 第13章 网页服务三(译)
  • 原文地址:https://www.cnblogs.com/lizhiqiang0204/p/13645907.html
Copyright © 2011-2022 走看看