`
cloudtech
  • 浏览: 4607672 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

Silverlight之MVVM模式简单介绍项目(数据绑定)

 
阅读更多

很久没有更新博客了,今天向大家介绍一下Silverlight MVVM模式的使用。 MVVM即Model-View-ViewModel模式,它是一种轻量级的,灵活的方式分离数据实体与视图之间的关系,可以更好的提高代码的可重用性,便于项目的管理和测试。View层主要应用于页面展现,Model为数据的构造,ViewModel层用于逻辑的实现,并且使用数据绑定将三者之间很好的联系起来。

本项目中我们通过演示制作一个简单的数据绑定的例子, 来讲述MVVM模式程序的工作原理,使用过WPF和Silverlight的朋友可能都知道,在XAML中,一般的数据绑定有三种,

One-Time,One-Way,Two-way。

One-Time绑定模式的意思即为从Data object绑定至UI这一层只进行一次绑定,程序不会继续追踪数据的在两者中任何一方的变化,这种绑定方式很使用于报表数据,数据仅仅会加载一次。

One-Way绑定模式即为单向绑定,即object-UI的绑定,只有当object中数据发生了变化,UI中的数据也将会随之发生变化,反之不然。

Two-Way绑定模式为双向绑定,无论数据在Object或者是UI中发生变化,应用程序将会更新另一方,这是最为灵活的绑定方式,同时代价也是最大的。

在这个程序中,我们将针对Two-Way数据绑定模式进行实验。掌握了双向绑定模式,其他两种也很好理解了,希望大家能够在实际项目中灵活使用这三种绑定方式。

本项目使用Visual Studio 2010 Ultimate和Silverlight 4 制作。

[本示例完整源码下载(0分)] http://download.csdn.net/detail/aa466564931/3701792

首先创建一个名为CSSL4DataGridBindingInMVVM的Silverlight程序。我们将使用MainPage.xaml作为主界面,在Grid里面添加一些TextBlock,TextBox和Button作为简单的数据呈现及修改,下面的Xaml的内容,添加了4个TextBlock,4个TextBox和两个Button:

MainPage.xaml

    <Grid x:Name="LayoutRoot" Background="White"
          DataContext="{Binding Source={StaticResource viewModel}}" >
        <Grid Name="personGrid" DataContext="{Binding Path=person, Mode=TwoWay}"  >
            <Grid.RowDefinitions>
                <RowDefinition Height="30"></RowDefinition>
                <RowDefinition Height="30"></RowDefinition>
                <RowDefinition Height="30"></RowDefinition>
                <RowDefinition Height="30"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100"></ColumnDefinition>
                <ColumnDefinition Width="120"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <TextBlock VerticalAlignment="Center" Name="lbName" Grid.Row="0" Grid.Column="0" Text="Name:" />
            <TextBox Name="tbName" Text="{Binding Path=Name, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}"
                     BindingValidationError="tbValidate" Grid.Column="1" Height="30" VerticalAlignment="Top"></TextBox>
            <TextBlock VerticalAlignment="Center" Name="lbAge" Grid.Row="1" Grid.Column="0" Text="Age:" />
            <TextBox Name="tbAge" Text="{Binding Path=Age, Mode=TwoWay, NotifyOnValidationError=True,ValidatesOnExceptions=True}"
                     BindingValidationError="tbValidate"  Grid.Column="1" Grid.Row="1"></TextBox>
            <TextBlock VerticalAlignment="Center" Name="lbTelephone" Grid.Row="2" Grid.Column="0" Text="Telephone:" />
            <TextBox Name="tbTelephone" Text="{Binding Path=Telephone, Mode=TwoWay, NotifyOnValidationError=True,ValidatesOnExceptions=True}"
                     BindingValidationError="tbValidate" Grid.Column="1" Grid.Row="2"></TextBox>
            <TextBlock VerticalAlignment="Center" Name="lbComment" Grid.Row="3" Grid.Column="0" Text="Comment:" />
            <TextBox Name="tbComment" Text="{Binding Path=Comment, Mode=TwoWay,NotifyOnValidationError=True, ValidatesOnExceptions=True}" 
                     BindingValidationError="tbValidate" Grid.Column="1" Grid.Row="3"></TextBox>
            <Button Content="Change Model by code" Grid.Column="2" Grid.Row="4" Height="24" HorizontalAlignment="Left"
                    Name="btnChangeModel" VerticalAlignment="Top" Width="146" Margin="0,20,0,0" 
                    Command="{Binding Path=DataContext.SetInformation, ElementName=LayoutRoot}"
                    CommandParameter="{Binding Path=Name}" />
            <Button Content="Display" Grid.Column="1" Grid.Row="4" Height="23" HorizontalAlignment="Left"
                    Margin="0,21,0,0" Name="btnDisplay" VerticalAlignment="Top" Width="75" 
                    Command="{Binding Path=DataContext.GetInformation, ElementName=LayoutRoot}" 
                    CommandParameter="{Binding Path=Age}" />

            <Grid Name="DisplayGrid" DataContext="">
            </Grid>
        </Grid>
    </Grid>

MVVM模式中应尽量避免在code-behind文件中添加过多的代码,逻辑代码大多通过继承ICommand类实现,这里我们在Button的Command中添加Binding和BindingParameter,Button的单击代码实现写在PersonCommand类中,下面我们将会介绍如何创建这个类,同时大家可以注意到这里有一些Validation(验证)的东西,在TextBox中有两个比较特殊的属性,NotifyOnValidationError和ValidationOnExceptions,Notify事件一般用于在model类的读取和设置属性时发生的异常(通常是类型转换出现的异常)时会抛出错误,比方说你的TextBox中绑定了“年龄”这个属性,并且在Model类中将它设为Int类型,那么当你使用双向绑定时,给它输入字符串类型的数据或者为空值,那么此时在Model的Set中变回抛出异常,你可以说自己在Set里面进行类型检测处理,但是通过这种方式工作量会比较大,所以我们推荐使用NotifyOnValidationError这个属性,ValidationOnException这个属性意思为当数据字段在验证时抛出异常的情况下会触发BindValidationError这个事件,所以当数据发生异常时候我们可以定义自己的方法将错误呈现在页面上。这里我们将这两个属性均设置为true。BindValidationError事件后的“tbValidate”是我们设置在MainPage.xaml.cs文件中用于呈现错误一个方法。

由于我们需要在异常中为验证设定一个状态,保存在IsolatedStorageSettings中,这是系统为Silverlight应用程序开辟的一个存储空间,可以存放你需要的数据,我们这里存入验证的状态位,在Command类中将会检查此状态位,决定是否执行更新,下面是MainPage,xaml.cs的代码,比较简单,但是也比较重要

MainPage.xaml.cs

    public partial class MainPage : UserControl
    {
        private bool flag = true;
        private IsolatedStorageSettings appSetting;
        public MainPage()
        {
            InitializeComponent();
            appSetting = IsolatedStorageSettings.ApplicationSettings;
            if (!appSetting.Contains("validateFlag"))
            {
                appSetting.Add("validateFlag", this.flag);
            }
        }

        /// <summary>
        /// The method is used for catching binding exceptions.
        /// We can also store validate variable with IsolatedStorageSettings.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void tbValidate(object sender, ValidationErrorEventArgs e)
        {
            if (e.Action == ValidationErrorEventAction.Added)
            {
                (e.OriginalSource as Control).Background = new SolidColorBrush(Colors.Yellow);
                flag = false;
            }
            if (e.Action == ValidationErrorEventAction.Removed)
            {
                (e.OriginalSource as Control).Background = new SolidColorBrush(Colors.White);
                flag = true;
            }
            appSetting["validateFlag"] = flag;
        }

    }


下面我们创建Model类,为了演示方便,我们只创建四个属性。此类命名为PersonModel,注意由于是双向绑定模式,我们需要继承INotifyPropertyChanged接口,该接口的作用是当Model数据发生改变时候,将会通知客户端,我们这里需要实现名为PropertyChangedEventHandler的事件和Changed方法,当属性被重新设置时需要调用这个Changed方法来改变客户端的值。

PersonModel.cs

    /// <summary>
    /// Person Modal class, contains name, age, telephone and comment properties.
    /// The Model implement INotifyPropertyChanged interface for notifying clients
    /// that properties has been changed.
    /// </summary>
    public class PersonModel : INotifyPropertyChanged
    {
        private string name;
        private int age;
        private string telephone;
        private string comment;
        private Regex regexInt = new Regex(@"^-?\d*{1}quot;);
        public event PropertyChangedEventHandler PropertyChanged;
        public PersonModel(string name, int age, string telephone, string comment)
        {
            this.name = name;
            this.age = age;
            this.telephone = telephone;
            this.comment = comment;
        }

        public void Changed(string newValue)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(newValue));
            }
        }

        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                if (value == string.Empty)
                    throw new Exception("Name can not be empty.");
                name = value;
                Changed("Name");
            }
        }

        public int Age
        {
            get
            {
                return age;
            }
            set
            {
                int outPut;
                if (int.TryParse(value.ToString(), out outPut))
                {
                    if (outPut < 0)
                        throw new Exception("Age must be greater than zero.");
                    age = outPut;//outPut.ToString();
                    Changed("Age");
                }
                else
                {
                    throw new Exception("Age must be an integer number.");
                }
            }
        }

        public string Telephone
        {
            get
            {
                return telephone;
            }
            set
            {
                if (value == string.Empty)
                    throw new Exception("Telephone can not be empty.");
                if (!regexInt.IsMatch(value))
                    throw new Exception("Telephone number must be comprised of numbers.");
                telephone = value;
                Changed("Telephone");
            }
        }

        public string Comment
        {
            get
            {
                return comment;
            }
            set
            {
                if (value == string.Empty)
                    throw new Exception("Comment can not be empty.");
                comment = value;
                Changed("Comment");
            }
        }
    }


接下来,我们创建ViewModel类,此类用于连接View和Model,并且被Command类调用,是MVVM模式的核心。创建一个class文件,命名为PersonViewModel,此类含有PersonModel的实例,用于当实体类数据发生改变时通知客户端程序,这里我们创建两个ICommand类型的属性,分别用于获取model数据和设置model数据。

PersonViewModel.cs

    /// <summary>
    /// The MainPage.xaml page bind this class with Grid control, PersonViewModel
    /// class is the ViewModel layer in MVVM pattern design, this class contains 
    /// a model instances and invoke Command class.
    /// </summary>
    public class PersonViewModel
    {
        public PersonModel person
        {
            get; 
            set;
        }

        public PersonViewModel()
        {
            this.person = new PersonModel("John", 1, "13745654587", "Hello");
        }

        public PersonViewModel(string name, int age, string telephone, string comment)
        {
            this.person = new PersonModel(name, age, telephone, comment);
        }

        public ICommand GetInformation
        {
            get
            {
                return new PersonCommand(this);
            }
        }

        public ICommand SetInformation
        {
            get
            {
                return new ChangeModelCommand(this);
            }
        }

        public void UpdatePerson(PersonModel entity)
        {
            MessageBox.Show(String.Format("Name: {0} \r\n Age: {1} \r\n Telephone: {2} \r\n Comment: {3}",
                person.Name,person.Age,person.Telephone,person.Comment),"Display Message", MessageBoxButton.OK);
        }


下面我们创建这两个Command类PersonCommand类和ChangeModelCommand类,因为在本程序中,数据无论在后台代码或者是前台UI中发生改变另一方也会随之改变,PersonCommand类的作用是当用户在点击Display按钮时出现对话框显示当前model的值,由于用户可以在TextBox中改变model的值(UI改变),所以我们需要建立一个ChangeModelCommand来响应Change Model by Code按钮,意为从object方向改变model的值,这样来阐述用户从两方面来改变Model值都是可以成功的。Command类需要注意的几个要点是这样的:

1. 继承ICommand接口。

2.实现CanExecute属性,该属性判断Command类中的Execute方法能否被执行。

3.实现Execute方法,Command类的主要逻辑代码。

4.包含ViewModel的一个实例,可以在Execute方法中直接调用ViewModel的方法,或是改变ViewModel中Model实例的数据。

PersonCommand.cs

    /// <summary>
    /// The class implements ICommand interface and displays a dialog box
    /// to show data.
    /// </summary>
    public class PersonCommand : ICommand
    {
        public PersonViewModel viewModel;
        public event EventHandler CanExecuteChanged;
        private IsolatedStorageSettings appSetting; 
        public PersonCommand(PersonViewModel view)
        {
            this.viewModel = view;
            appSetting = IsolatedStorageSettings.ApplicationSettings;
        }

        public bool CanExecute(object parameter)
        {
            bool validateFlag = false;
            if (appSetting.Contains("validateFlag"))
            {
                validateFlag = (bool)appSetting["validateFlag"];
            }
            if (validateFlag)
            {
                return true;
            }
            else
            {
                return false;
            }
        }        

        public void Execute(object parameter)
        {
            viewModel.UpdatePerson(viewModel.person);        
        }
    }

ChangeModelCommand.cs

    public class ChangeModelCommand: ICommand
    {
        /// <summary>
        /// This class is used to change model instance via code, and view layer will update 
        /// when background data source has been changed.
        /// </summary>
        private PersonViewModel viewModel;
        public event EventHandler CanExecuteChanged;
        public ChangeModelCommand(PersonViewModel viewModel)
        {
            this.viewModel = viewModel;
        }

        public bool CanExecute(object parameter)
        {
            if (parameter.ToString() != string.Empty)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Change Model instance by Execute method.
        /// </summary>
        /// <param name="parameter"></param>
        public void Execute(object parameter)
        {
            PersonModel model;
            model = viewModel.person;
            model.Name = "Default Name";
            model.Age = 0;
            model.Telephone = "11111111111";
            model.Comment = "Default Comment";
        }
    }

至此,项目创建完毕,按Ctrl+F5看看结果吧。

分享到:
评论

相关推荐

    silverlight做的自定义日历(MVVM模式)

    用MVVM模式做的silverlight自定义日历,可以绑定其他数据,做成进度管理日历或者考勤表

    Silverlight MVVM例子(通过WebServer 查询数据)

    折腾了好久终于可以跟大家分享一下了,一开始的问题是不知道怎么页面加载的时候就自动调用Webservice绑定数据,弄了好久终于知道怎么写了,贴出...Silverlight MVVM例子(通过WebServer 查询数据) 页面加载时绑定数据

    MVVM模式模型-视图-视图模型(Model-View-ViewModel)

    结合WPF、Silverlight绑定机制,MVP演变出了MVVM,充分利用了WPF、Silverlight的优势,将大量代码逻辑、状态转到ViewModel, 可以说MVVM是专门为WPF、Silverlight打造的。 View绑定到ViewModel,然后执行一些命令在...

    Silverlight4 MVVM Combobox总结.docx

    以下资源转自互联网 1.MVVM格式下,DataGrid中ComboBox绑定 2.Silverlight ComboBox的SelectedValue不在ItemSource中的绑定失败问题。 如果,你有意见或更好的处理办法,请联系我QQ:13422640谢谢

    Silverlight开发MVVM框架(MVVM Light Toolkit) v4 beta1.rar

    MVVM Light Toolkit是Silverlight开发中用到的最多的MVVM框架。 GalaSoft.MvvmLight 类库 ViewModelBase 类是ViewModels的基础类,在开发中ViewModls类都要继承自它。 Messenger类 用于应用程序的通信。接收者仅接受...

    MvvmDemo:数据绑定

    MvvmDemo 模型视图ViewModel:数据绑定演示目标MVVM代表Model-View-ViewModel,这是Microsoft WPF和Silverlight中广泛采用的模式。 通过Android-Binding框架在Android中实现MVVM模式的演示项目。MVVM Android 模型:...

    Silverlight4新特性

    Silverlight 4 在商务应用、多媒体应用和跨浏览器应用的架构方面有很大提高,新的功能包括对打印的支持、显著提高数据的使用形式、对一些新语言的支持、对 Google Chrome 浏览器的完全支持、WCF RIA Services 的应用...

    Silverlight5_Tools

    silverlight 5.0测试版 1)改进的数据绑定支持和更好地支持MVVM 2)性能和速度的提高

    Microsoft.Practices.Prism.Mvvm.dll

    Prism.Mvvm用于WPF中MVVM前后端数据绑定框架,有需要的可以下载 Prism provides guidance to help you more easily design and build, flexible, and easy-to-maintain client business apps that run on Windows ...

    Silverlight企业应用框架(Richwork.framework 1.1.0.1)正式版本

    比较正式的版本,此版本可能不能运行,数据库做了修改了,贡献后期代码是子啊,Silverlight企业应用框架(Richwork.framework beta 1.0.6.9)在基础上提供完善框架之一。补充不足。 数据库太大了,在原来的基础上增加...

    Silverlight 4命令绑定分步指南

    在本文中,我将描述如何实现命令绑定以加载一些信息并将其显示到UI。

    Knockout API 中文版

    (developed BDD-style) means its correct functioning can easily be verified on new browsers and platforms 开发人员如果用过Silverlight或者WPF可能会知道KO是MVVM模式的一个例子。如果熟悉 Ruby on Rails 或...

    redux.NET:Redux.NET 是 .NET 应用程序的可预测状态容器。 灵感来自 https

    在开发了几个 MVVM 应用程序(Silverlight、WPF、WinRT)之后,当它们开始变大时,我总是感到不安: 双向绑定会导致级联更新,因此很难预测单个用户交互的结果会发生什么变化。 异步操作使得记住应用程序的流程...

Global site tag (gtag.js) - Google Analytics