在Windows Phone 7.1 应用程序中实现MVVM设计模式以及使用Prism

381 views 7 comments posted at about 7 years ago Raymond Tang

MVVM设计模式是Model-View-ViewModel的简写,它从MVP(Model-View-Presenter)演变而来;使用MVVM模式可以很容易的将程序中的数据与用户界面分离,这样程序员可以更好的编写数据模型,而美工则可以创建用户界面。从程序维护、更新等方面考虑,MVVM模式也许使得我们的工作变得更加的容易。在Windows Phone应用程序中,Model即为我们的数据模型,即为一个类,View则是XAML用户控件,ViewModel也为一个类,它将View和Model联系起来。

本文将演示如何在Windows Phone应用程序中实现MVVM模式,更多参考资料请查看:

1)Implementing the Model-View-ViewModel Pattern in a Windows Phone Application

2)WPF Apps With The Model-View-ViewModel Design Pattern

3)MVVM Light Toolkit

1.创建Windows Phone Application MvvmSample

2.添加View、Model、ViewModel文件夹

3.创建数据模型Article

Article类实现了INotifyPropertyChanged接口,当其属性值发生变化时可以通知视图这些变化,以便其作相应的更改;在本程序中,用户仅能更改IsRead属性:

namespace MvvmSample.Model
{
    public class Article : INotifyPropertyChanged
    {
        /// <summary>
        /// Article ID
        /// </summary>
        public int ID { get; set; }

        /// <summary>
        /// Article Title
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// Whether this article is read
        /// </summary>
        private bool m_IsRead;
        public bool IsRead
        {
            get { return m_IsRead; }
            set
            {
                m_IsRead = value;
                RaisePropertyChanged("IsRead");
            }
        }

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}

4.创建ViewModel ArticleViewModel

ArticleViewModel包含了Model即Article的集合,保存在一个ObservableCollection集合中,这样便于当数据发生更改,View可以做相应的变化;而Article数据则通过LINQ to XML从我们上一个例子中的XML文件中读取。

XML文件内容如下:

<?xml version="1.0" encoding="utf-8" ?>
<Articles>
  <Article ID="1" IsRead="True">
    <Title>Article Title 1</Title>
  </Article>
  <Article ID="2" IsRead="True">
    <Title>Article Title 2</Title>
  </Article>
  <Article ID="3" IsRead="False">
    <Title>Article Title 3</Title>
  </Article>
  <Article ID="4" IsRead="False">
    <Title>Article Title 4</Title>
  </Article>
  <Article ID="5" IsRead="False">
    <Title>Article Title 5</Title>
  </Article>
</Articles>

ArticleViewModel代码如下:

namespace MvvmSample.ViewModel
{
    public class ArticleViewModel
    {
        /// <summary>
        /// All the articles
        /// </summary>
        public ObservableCollection<Article> AllArticles { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        public ArticleViewModel()
        {
            Initialize();
        }

        /// <summary>
        /// Initialize the list
        /// </summary>
        private void Initialize()
        {

            //load all xml via LINQ to XML
            XDocument doc = XDocument.Load("Data\\Articles.xml");
            var articles = from article in doc.Root.Elements("Article")
                           select new Article
                           {
                               ID = Convert.ToInt32(article.Attribute("ID").Value),
                               Title = article.Element("Title").Value,
                               IsRead = Convert.ToBoolean(article.Attribute("IsRead").Value)
                           };
            this.AllArticles = new ObservableCollection<Article>(articles.ToList<Article>());
        }
    }
}

5.创建View ArticleView.xaml

在View文件夹下创建Windows Phone User Control ArticleView.xaml。在<Grid x:Name="LayoutRoot">元素中添加以下代码:

<ListBox ItemsSource="{Binding}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="50"/>
                            <ColumnDefinition Width="250"/>
                            <ColumnDefinition Width="50"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock x:Name="ID" Text="{Binding Path=ID, Mode=OneWay}" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" />
                        <TextBox x:Name="Title" Text="{Binding Path=Title, Mode=OneWay}" Grid.Column="1" TextAlignment="Center" InputScope="Number"/>
                        <CheckBox x:Name="IsRead" IsChecked="{Binding Path=IsRead, Mode=TwoWay}"Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center" />
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

6.在MainPage中添加ArticleView

生成项目,添加命名空间my,xmlns:view="clr-namespace:MvvmSample.View",在Grid中添加ArticleView元素:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <view:ArticleView HorizontalAlignment="Left" Margin="0,0,0,0" x:Name="articleView1" VerticalAlignment="Top" DataContext="{Binding}" />
        </Grid>

添加命名空间xmlns:vm="clr-namespace:MvvmSample.ViewModel",在资源中添加ViewModel: 

<phone:PhoneApplicationPage.Resources>
        <vm:ArticleViewModel x:Key="viewModel"/>
    </phone:PhoneApplicationPage.Resources>

设置articleView1的DataContext为viewModel:

<view:ArticleView HorizontalAlignment="Left" Margin="0,0,0,0" x:Name="articleView1" VerticalAlignment="Top" DataContext="{Binding Source={StaticResource viewModel}}" />

最终整个项目结构如下:

在Windows Phone Emulator中运行效果如下:


7.测试INotifyPropertyChanged

为了测试INotifyPropertyChanged是否发生作用,接下来我们再ArticleView.xaml中添加一个按钮Add,其作用为,当鼠标点击此按钮后,向View
Model的集合中添加一条新的Article数据。

XAML改动如下:

<StackPanel Orientation="Vertical">
            <ListBox ItemsSource="{Binding Path=AllArticles}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="50"/>
                                <ColumnDefinition Width="250"/>
                                <ColumnDefinition Width="50"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock x:Name="ID" Text="{Binding Path=ID, Mode=OneWay}" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" />
                            <TextBox x:Name="Title" Text="{Binding Path=Title, Mode=OneWay}" Grid.Column="1" TextAlignment="Center" InputScope="Number"/>
                            <CheckBox x:Name="IsRead" IsChecked="{Binding Path=IsRead, Mode=TwoWay}" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center" />
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
            <Button Content="Add" Height="72" HorizontalAlignment="Left" Margin="0,0,0,0" Name="buttonAdd" VerticalAlignment="Top" Width="160" Command="{Binding  Path=AddCommand}" />
        </StackPanel>

为了实现命令的绑定,我们通过Prism来实现,下面将参数如何安装Prism。

8.安装Prism

右击Reference,选择Add Library Package Reference:

在弹出对话框中,搜索prism,点击安装按钮:

安装完成后,可以看到项目中,增加了对Prism相应组件的引用:

9.修改ArticleViewModel

在ArticleViewModel中增加一个属性AddCommand,类型为ICommand,用于Add按钮的绑定,增加以及变化的代码如下:

/// <summary>
        /// Add command
        /// </summary>
        public ICommand AddCommand { get; private set; }
        /// <summary>
        /// Constructor
        /// </summary>
        public ArticleViewModel()
        {
            Initialize();
            this.AddCommand = new DelegateCommand<Object>((obj) =>
            {
                this.AllArticles.Add(new Article()
                {
                    ID = AllArticles.Last<Article>().ID + 1,
                    Title = string.Format("Article Title {0}", AllArticles.Last<Article>().ID + 1),
                    IsRead = false
                });
            },
            (arg) => true);
        }

在Emulator中运行效果:

点击Add按钮,ListBox会自动的刷新并且增加新的纪录:

以上结果表明ObservableCollection生效;按照同样的方式,我们添加一个Change按钮,更改列表数据中最后一项的CheckBox的状态。

改动的代码如下:

/// Change command
        /// </summary>
        public ICommand ChangeCommand { get; private set; }
构造函数增加:

this.ChangeCommand = new DelegateCommand<Object>((obj) =>
            {
                if (this.AllArticles.Count > 0)
                {
                    var article = this.AllArticles.Last<Article>();
                    article.IsRead = article.IsRead ? false : true;
                }
            },
            (arg) => true);

运行效果如下,点击Change按钮,最后一项的IsChecked即会发生相应的变化:

由此可见,IsRead属性也已经生效。

 

本文为原创文章,若需转载,请注明来源http://hi.baidu.com/1987raymond, 若需要本文源码,请回复你的邮箱,或者发邮件到我的邮箱china.raymond[at]hotmail.com。

Add comment

Comments (7)

Raymond about 5 years ago Re:在Windows Phone 7.1 应用程序中实现MVVM设计模式以及使用Prism

@ifree 谢谢捧场 现在实现了邮件功能,回复可以直接发送到你的邮箱

ifree about 7 years ago

你看你博客连个留言的地方都不留一个,到这里来给你捧场了. 哈哈
ps. 配一个openid插件嘛

Raymond Tang about 5 years ago Re:在Windows Phone 7.1 应用程序中实现MVVM设计模式以及使用Prism

@wingyiu ICommand class可以参看此MSDN帮助文档http://msdn.microsoft.com/zh-cn/library/vstudio/system.windows.input.icommand(v=vs.95).aspx

wingyiu about 5 years ago

SL4已经提供ICommand了,不用Prism了

Raymond about 5 years ago Re:在Windows Phone 7.1 应用程序中实现MVVM设计模式以及使用Prism

@wingyiu SL4里面的东西没去了解

wingyiu about 5 years ago Re:在Windows Phone 7.1 应用程序中实现MVVM设计模式以及使用Prism

SL4已经提供ICommand了,不用Prism了

Raymond about 7 years ago re: 在Windows Phone 7.1 应用程序中实现MVVM设计模式以及使用Prism

This is just test for emailing

Raymond about 7 years ago re: 在Windows Phone 7.1 应用程序中实现MVVM设计模式以及使用Prism

与我联系那里就可以留言呢
谢谢捧场 :)
OpenID 插件之前没整过 虽然这个是支持的

ifree about 7 years ago re: 在Windows Phone 7.1 应用程序中实现MVVM设计模式以及使用Prism

你看你博客连个留言的地方都不留一个,到这里来给你捧场了. 哈哈
ps. 配一个openid插件嘛
In this Page