第5篇 WPF C# 数据绑定Model-View-ViewModel模式

第5篇  WPF C# 数据绑定Model-View-ViewModel模式

参考资料:

John Sharp:《Microsoft Visual C# 2013 Step by Step》

周 靖 译:John Sharp《Visual C# 2012从入门到精通》

前言

Model-View-ViewModel模式即MVVM模式编程涉及五个文件:

1、MainWindow.xaml文件      UI界面文件

2、MainWindow.xaml.cs文件      UI架构文件

3、ViewModel.cs文件             视图模型文件

4、DataLib.cs数据类库文件        数据元素类库文件

5、Command.cs文件          UI命令文件

上面的文件名斜体为自由定义。正体为参考资料资料定义。

1界面文件

MainWindow.xaml

<Window x:Class="StudyDisplay.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 Background="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}">
        <!-- Grid定义 -->
        <Grid.ColumnDefinitions>
            ……
        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0" Grid.Column="0" Grid.RowSpan="5" Background="{DynamicResource {x:Static SystemColors.ActiveCaptionBrushKey}}" />
        <StackPanel Grid.Row="0" Grid.Column="1" Grid.RowSpan="5" Background="{DynamicResource {x:Static SystemColors.GradientInactiveCaptionBrushKey}}" />

        <!--1-->
        <StackPanel Grid.Row="0" Grid.Column="2" Style="{StaticResource TheStackPanelStyle}" >    ……    </StackPanel>

        <!--2-->
        <StackPanel Grid.Row="1" Grid.Column="2"  Style="{StaticResource TheStackPanelStyle}" >
            <StackPanel>
                <Label Style="{StaticResource TheLabeltyle}">采样周期</Label>
                <TextBox Style="{StaticResource TheTextBoxStyle}"
                         Name="inputSC"
                         Text="{Binding Current.SampleCircle,Mode=TwoWay}"
                         GotFocus="inputSC_GotFocus"
                         PreviewMouseLeftButtonDown="inputSC_PreviewMouseLeftButtonDown"
                         />
            </StackPanel>
            <StackPanel>
                <Label Style="{StaticResource TheLabeltyle}">公制/英制</Label>
                <ComboBox Style="{StaticResource TheComboBoxStyle}" Background="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}">
                    <ComboBoxItem Style="{StaticResource ThComboBoxItemStyle}">公制</ComboBoxItem>
                    <ComboBoxItem Style="{StaticResource ThComboBoxItemStyle}">英制</ComboBoxItem>
                    <ComboBoxItem Style="{StaticResource ThComboBoxItemStyle}">华制</ComboBoxItem>
                </ComboBox>
            </StackPanel>
            <StackPanel>
                <Label Style="{StaticResource TheLabeltyle}">采样周期1</Label>
                <TextBox Style="{StaticResource TheTextBoxStyle}"
                         Name="outputSC"
                         Text="{Binding Current.SampleCircle,Mode=TwoWay}"                GotFocus="outputSC_GotFocus"
                         />
            </StackPanel>
            <StackPanel>
                <Label Style="{StaticResource TheLabeltyle}">公制/英制1</Label>
                <ComboBox Style="{StaticResource TheComboBoxStyle}" Background="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}">
                    <ComboBoxItem Style="{StaticResource ThComboBoxItemStyle}">公制</ComboBoxItem>
                    <ComboBoxItem Style="{StaticResource ThComboBoxItemStyle}">英制</ComboBoxItem>
                    <ComboBoxItem Style="{StaticResource ThComboBoxItemStyle}">华制</ComboBoxItem>
                </ComboBox>
            </StackPanel>
        </StackPanel>
        <!--3-->
        <StackPanel Grid.Row="2" Grid.Column="2" Style="{StaticResource TheStackPanelStyle}">
            <CheckBox Content="CheckBox" Checked="CheckBox_Checked_1" />
            <CheckBox Content="CheckBox" Checked="CheckBox_Checked" />
            <CheckBox Content="CheckBox" />
            <CheckBox Content="CheckBox" Checked="CheckBox_Checked" />
            <CheckBox Content="CheckBox" />
            <CheckBox Content="CheckBox" />
            <CheckBox Content="CheckBox" />
        </StackPanel>
        <!--4-->
        <StackPanel Grid.Row="3" Grid.Column="2" Style="{StaticResource TheStackPanelStyle}">……    </StackPanel>
        <!--5-->
        <StackPanel Grid.Row="4" Grid.Column="2" Style="{StaticResource TheStackPanelStyle}">……    </StackPanel>

    </Grid>
    <!--
    <Page.TopAppBar >
        <AppBar IsSticky="True">
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                <AppBarButton x:Name="previousCustomer" Icon="Back" Command="{Binding Path=PreviousCustomer}"/>
                <AppBarButton x:Name="nextCustomer" Icon="Forward" Command="{Binding Path=NextCustomer}"/>
            </StackPanel>
        </AppBar>
    </Page.TopAppBar>
    -->
</Window>

如上列代码中粗体所示。绑定语句为:

Text="{Binding Current.SampleCircle,Mode=TwoWay}"

与简单的数据绑定相比,增加了 Current. 

代码末尾一段(<Page.TopAppBar ></Page.TopAppBar>)在Win7下无法运行,是Win8的AppBar控件。用"Back"和"Forward"按钮分别绑定命令上一个、下一个命令。该命令实现:数据引导ID的增减1,从而使上列绑定数据在视图模型中列出的各个数据表绑定。

2、架构文件

MainWindow.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.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace StudyDisplay
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        //架构绑定
        public MainWindow()
        {
            InitializeComponent();
            DataLib dataLib = new DataLib
            {
                SampleCircle = "John"
            };        //在MainPage构造器中删除创建Customer对象的代码,替换成创建ViewModel类实例 的一个语句。            ViewModel viewModel = new ViewModel();            //修改设置MainPage对象的DataContext属性的语句,来引用新的ViewModel对象。            this.DataContext = viewModel;     }
     //交互逻辑
        private void inputSC_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
           // var control = sender as System.Windows.Controls.TextBox;
            //if (control == null)
               // return;
           // Keyboard.Focus(control);
           // e.Handled = true;
        }
        private void inputSC_GotFocus(object sender, RoutedEventArgs e)
        {
           // inputSC_GotFocus.SelectAll();
        }
        private void outputSC_GotFocus(object sender, RoutedEventArgs e)
        {
            //outputSC_GotFocus.SelectAll();
        }
    }
}

在MainPage构造器中删除创建Customer对象的代码,替换成创建ViewModel类实例 的一个语句。修改设置MainPage对象的DataContext属性的语句,来引用新的ViewModel对象。如加粗的语句所示。

3、视图模型文件

项目资源管理器—>项目—>右键|添加—>类—>文件名:ViewModel.cs 新建ViewModel.cs文件。

ViewModel.cs

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

using System.ComponentModel;

namespace StudyDisplay
{
    public class ViewModel : INotifyPropertyChanged
    {
        private List<DataLib> dataLib;
        private int currentDataLib;
        //添加NextCustomer和PreviousCustomer自动属性。
        //视图将绑定到这些Command对象,允许在客户之间导航。
        public Command NextDataLib { get; private set; }
        public Command PreviousDataLib { get; private set; }
        //
        public ViewModel()                      //ViewModel构造器
        {
            this.currentDataLib = 0;
            this.IsAtStart = true;              //设置IsAtStart和IsAtEnd属性
            this.IsAtEnd = false;               //设置IsAtStart和IsAtEnd属性
            //设置NextCustomer和PreviousCustomer属性来引用新的Command对象,
            this.NextDataLib = new Command(this.Next, () =>
                { return this.dataLib.Count > 0 && !this.IsAtEnd; });   //Lambda表达式
            this.PreviousDataLib = new Command(this.Previous, () =>
                { return this.dataLib.Count > 0 && !this.IsAtStart; }); //Lambda表达式
            //1、ViewModel类将一个List<Customer>对象作为它的模型,构造器用示例数据填充该列表。
            this.dataLib = new List<DataLib>
            {
                new DataLib
                {
                    CustomerID = 1,
                    SampleCircle = "John",
                },
                new DataLib
                {
                    CustomerID = 2,
                    SampleCircle = "Diana",
                },
                new DataLib
                {
                    CustomerID = 3,
                    SampleCircle = "Francesca",
                }
            };
            //
        }         //添加以下字段和属性。将用这两个属性跟踪ViewModel的状态。
        //如果ViewModel的currentCustomer字段定位在customers集合起始处,IsAtStart属性将设为true,
        //如果定位在customers集合末尾, IsAtEnd属性将设为true。
        private bool _isAtStart;
     public bool IsAtStart
        {
            get { return this._isAtStart; }
            set
            {
                this._isAtStart = value;
                this.OnPropertyChanged("IsAtStart");
            }
        }
        private bool _isAtEnd;
        public bool IsAtEnd
        {
            get { return this._isAtEnd; }
            set
            {
                this._isAtEnd = value;
                this.OnPropertyChanged("IsAtEnd");
            }
        }
        /*                                            */
        public DataLib Current
        {
            get { return this.dataLib[currentDataLib]; }
        }
        //将加粗的私有方法Next和Previous添加到ViewModel类,放到Current属性之后。
        //注意 Count属性返回集合中的数据项的数量,但记住集合项的编号是从0到Count – 1。
        //这些方法更新currentCustomer变量来引用客户列表中的下一个(或上一个)客户。
        //注意,方法负责维护IsAtStart和IsAtEnd属性的值,并通过为Current属性引发
        //PropertyChanged事件来指出当前客户已发生改变。两个方法都是私有方法,它
        //们不应从ViewModel类的外部访问。外部类通过命令来运行这些方法。命令将在下面的步骤中添加。
        //!+++!此处涉及自定义的变量
        private void Next()
        {
            if (this.dataLib.Count - 1 > this.currentDataLib)
            {
                this.currentDataLib++;
                this.OnPropertyChanged("Current");
                this.IsAtStart = false;
                this.IsAtEnd =
                (this.dataLib.Count - 1 == this.currentDataLib);
            }
        }
        private void Previous()
        {
            if (this.currentDataLib > 0)
            {
                this.currentDataLib--;
                this.OnPropertyChanged("Current");
                this.IsAtEnd = false;
                this.IsAtStart = (this.currentDataLib == 0);
            }
        }
        //记住,视图在控件的数据绑定表达式中通过Current属性来引用数据。ViewModel类移动至不同的客户时,
        //必须引发PropertyChanged事件通知视图所显示的数据发生改变。
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this,
                new PropertyChangedEventArgs(propertyName));
            }

        }
    }
}

    

时间: 2024-08-08 09:56:42

第5篇 WPF C# 数据绑定Model-View-ViewModel模式的相关文章

Qt表格之Model/View实现

很多开发中都用到了表格,如何使用Qt做表格?比较简单的,我们可以使用QTableWidget,但是它有个问题,就是数据量不能太大,一旦数据量比较大的话就会带来内存问题.Qt还给我们提供了一样利器--Model/View.模型视图,接触Qt的都不会陌生,对新手来说可能不太好理解,没关系,Qt提供了强大的Assist文档和更加直观的Demo,相信看过之后使用来说就没有问题了.本篇文章来列出一个简单的例子,使用的就是表格的模型视图,在代码中给出了简单的注释说明.为什么要采用这种方式?试过的人都可以看到

Qt的Model/View Framework解析(数据是从真正的“肉(raw)”里取得,Model提供肉,所以读写文件、操作数据库、网络通讯等一系列与数据打交道的工作就在model中做了)

最近在看Qt的Model/View Framework,在网上搜了搜,好像中文的除了几篇翻译没有什么有价值的文章.E文的除了Qt的官方介绍,其它文章也很少.看到一个老外在blog中写道Model/View是他认为Qt中最不好的一部分了.真的是这样吗?为了回馈开源社区,我写了这篇blog,写的是我认为比较有价值的东东.题目起得是解析,但也没有特别细节的介绍,点到为止,有兴趣的Tx可以继续讨论.我所看的资料有<C++ GUI Programming with Qt 4, Second Edition

转几篇WPF文章

How to view word document in WPF application (CSVSTOViewWordInWPF) WPF 浏览PDF 文件 如何保存RichTextBox的文本到数据库?以及如何对RichTextBox的Document做绑定? 使用ViewModel模式来简化WPF的TreeView 转几篇WPF文章

WPF 之 数据绑定

数据绑定需要: 后台必须要有与控件对应的类和相关的属性 在后台new 一个类的对象 在后台把控件的数据上下文设置为该对象. 在XAML中把要绑定的控件中Text =      "{Binding 属性 }" 现象:在界面中修改控件中的参数可以同时反映到后台的实例中去,但是直接修改后台的实例,对界面中的参数没有影响 原因:由于普通对象没有"通知我的属性变了"这么一种机制,所以改变对象的属性,界面不会变,但是界面改变是有TextChanged之类的事件的,所以改变界面可

qt model/view 架构自定义模型之QStringListModel

# -*- coding: utf-8 -*- # python:2.x #QStringListModel #QStringListModel 是最简单的模型类,具备向视图提供字符串数据的能力. #QStringListModel 是一个可编辑的模型,可以为组件提供一系列字符串作为数据. #看作是封装了 QStringList 的模型.QStringList 是一种很常用的数据类型,实际上 #是一个字符串列表(也就是 QList<QString>).既然是列表,它也就是线性的数据结构, #因

Qt Model/View(转)

介绍 Qt 4推出了一组新的item view类,它们使用model/view结构来管理数据与表示层的关系.这种结构带来的功能上的分离给了开发人员更大的弹性来定制数据项的表示,它也提 供一个标准的model接口,使得更多的数据源可以被这些item view使用.这里对model/view的结构进行了描述,结构中的每个组件都进行了解释,给出了一些例子说明了提供的这些类如何使用. Model/View 结构 Model-View-Controller(MVC), 是从Smalltalk发展而来的一种

5.Qt model view设计模式

Introduction to Model/View Programming QT4 介绍了一系列新的 Item View 类,这些类使用Model/View结构来管理数据和数据如何呈现给用户.这种结构使程序员更加灵活的开发和定制呈现数据界面,Model/View结构提供标准的Model接口让各种数据资源都能够被存在的Item View使用. The model/view architecture MVC是一种源于 smalltalk的设计模式,经常用来构建应用程序界面. MVC有3个对象构成.

QT开发(三十八)——Model/View框架编程

QT开发(三十八)--Model/View框架编程 一.自定义模型 1.自定义只读模型 QAbstractItemModel为自定义模型提供了一个足够灵活的接口,能够支持数据源的层次结构,能够对数据进行增删改操作,还能够支持拖放.QT提供了 QAbstarctListModel和QAbstractTableModel两个类来简化非层次数据模型的开发,适合于结合列表和表格使用. 自定义模型需要考虑模型管理的的数据结构适合的视图的显示方式.如果模型的数据仅仅用于列表或表格的显示,那么可以使用QAbs

qt model/view 架构基础介绍之QTreeWidget

# -*- coding: utf-8 -*- # python:2.x #说明:QTreeWidget用于展示树型结构,也就是层次结构同前面说的 QListWidget 类似,这个类需要同另外一个辅助类 # QTreeWidgetItem 一起使用.不过,既然是提供方面的封装类,即便是看上去很复杂的树, # 在使用这个类的时候也是显得比较简单的 __author__ = 'Administrator' from PyQt4.QtGui import  * from PyQt4.Qt impor