MVFM框架----示例

来源:互联网 发布:微信头像 知乎 编辑:程序博客网 时间:2024/06/13 08:58

   本章介绍mvfm的详细使用方法,并提供win8下的demo以供参考。

   用VS2012建立工程,选择windows应用商店中的网格应用程序。本次的demo就是将这个vs2012自带的示例改造成mvfm方式运行。

  由于这个示例已经有了view和model层(SampleDataSource类),这两块就不需要重写了,我们直接开始构造fuction model。

  首先引入Windows.UI.Interactivity类库,这个库是微软提供的一个扩展库,需要从NuGet下载安装。

  然后再引入mvfm库,这是mvfm开发模式所依赖的动态库。

  构建function model,代码如下:

 public class SampleFunctionModel : FunctionModelBase    {        #region Property        IEnumerable<SampleDataGroup> _groups;        public IEnumerable<SampleDataGroup> Groups        {            get            {                if (_groups == null)                    _groups = SampleDataSource.GetGroups("AllGroups");                return _groups;            }        }        SampleDataGroup _currentGroup;        public SampleDataGroup CurrentGroup        {            get            {                return _currentGroup;            }            set            {                this.SetProperty(ref _currentGroup, value);            }        }        SampleDataItem _currentItem;        public SampleDataItem CurrentItem        {            get            {                return _currentItem;            }            set            {                this.SetProperty(ref _currentItem, value);            }        }        #endregion        #region Command        public ActionCommand<object> SetCurrentGroupCommand { get; private set; }        public ActionCommand<object> SetCurrentItemCommand { get; private set; }        #endregion        #region Command Function        void SetCurrentGroup(object parameter)        {            var Group = (parameter as ExCommandParameter).Parameter as SampleDataGroup;            if (Group != null)                CurrentGroup = Group;        }        void SetCurrentItem(object parameter)        {            var Item = (parameter as ExCommandParameter).Parameter as SampleDataItem;            if (Item != null)            {                CurrentItem = Item;            }        }        #endregion        #region Public Function        #endregion        #region Private Function        #endregion        #region protected Function        protected override void InitializeData()        {            SetCurrentGroupCommand = new ActionCommand<object>(SetCurrentGroup);            SetCurrentItemCommand = new ActionCommand<object>(SetCurrentItem);        }        #endregion    }
  其中Groups是整个工程的数据源,Groups从SampleDataSource中获取,并交由view曾显示。mvfm中function model并不存储数据,只负责业务逻辑处理,function model仅保存临时数据。例如CurrentGroup和CurrentItem,这两个属性分别代表当先选择或显示的SampleDataGroup和SampleDataItem。还需要说明一点的时,有些UI逻辑放在页面里处理,并不放在function model中。像页面跳转这样的常用ui逻辑都放在界面中处理。

  SetCurrentGroupCommand和SetCurrentItemCommand分别代表设置当前的SampleDataGroup命令和当前的SampleDataItem命令。将逻辑封装成命令进行交互称作命令模式,mvfm中view与function model的绝大部分交互都通过这种模式进行。

  在InitializeData函数中指定了具体执行命令的函数,SetCurrentGroupCommand由SetCurrentGroup函数执行。所有的命令都是ICommand类型,而ActionCommand<T>则是将ICommand封装了,方便使用。

  下面看看SetCurrentGroup中德代码。若界面上有参数传过来,都将是ExCommandParameter这种类型,下面是ExCommandParameter类的代码:

 public class ExCommandParameter    {        /// <summary>          /// 事件触发源          /// </summary>          public object Sender { get; set; }        /// <summary>          /// 事件参数          /// </summary>          public object EventArgs { get; set; }        /// <summary>          /// 额外参数          /// </summary>          public object Parameter { get; set; }        /// <summary>          /// 额外参数  2        /// </summary>         public object Parameter2 { get; set; }        /// <summary>          /// 额外参数  3        /// </summary>         public object Parameter3 { get; set; }    }  
  其中Sender为发送着,比如控件之类的,EventArgs则是某些代理中德事件参数,比如这个命令是button的click触发的,则EventArgs是对应的RoutedEventArgs事件。Parameter则是附带额外的参数,最多可以带三个。

  各位看到这里可能对function model还有些迷惑,等看完xaml中德处理在回头看就好理解了。

  function model写完后在APP中声明 function model的资源:

  

  <x:String x:Key="AppName">MvfmText</x:String>

  这样就可以在其他的页面中使用function model中Command了。

  首先看GroupedItemsPage页面,删光cs中德代码,仅保留构造函数

    public sealed partial class GroupedItemsPage : MvfmText.Common.LayoutAwarePage    {        public GroupedItemsPage()        {            this.InitializeComponent();        }    }
  在xaml页中声明数据源

<common:LayoutAwarePage    x:Name="pageRoot"    x:Class="MvfmText.GroupedItemsPage"    DataContext="{StaticResource SampleFunctionModel}"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:local="using:MvfmText"    xmlns:data="using:MvfmText.Data"    xmlns:common="using:MvfmText.Common"    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    xmlns:mvfm="using:Mvfm"    xmlns:i="using:Windows.UI.Interactivity"    mc:Ignorable="d">

  DataContext就是数据源,数据从SampleFunctionModel中获取。特别注意     xmlns:mvfm="using:Mvfm"和 xmlns:i="using:Windows.UI.Interactivity"这两条语句,xaml与function将同过这两个命名空间进行。

  然后声明网格所需要使用的数据资源

 <Page.Resources>        <!--            此页所显示的分组项的集合,绑定到完整            项列表的子集,因为无法虚拟化组中的项        -->        <CollectionViewSource            x:Name="groupedItemsViewSource"            Source="{Binding Groups}"            IsSourceGrouped="true"            ItemsPath="TopItems"            d:Source="{Binding AllGroups, Source={d:DesignInstance Type=data:SampleDataSource, IsDesignTimeCreatable=True}}"/>    </Page.Resources>
  其中Groups就是SampleFunctionModel中的Groups属性。

  然后再造GridView:

 <GridView            x:Name="itemGridView"            AutomationProperties.AutomationId="ItemGridView"            AutomationProperties.Name="Grouped Items"            Grid.RowSpan="2"            Padding="116,137,40,46"            ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"            ItemTemplate="{StaticResource Standard250x250ItemTemplate}"            SelectionMode="None"            IsSwipeEnabled="false"            IsItemClickEnabled="True">            <i:Interaction.Triggers>                <i:EventTrigger  EventName="ItemClick">                    <mvfm:EventArgNameCommandAction EventArgName="ClickedItem" Command="{Binding SetCurrentItemCommand}"/>                    <local:NavigateAction NavigateName="MvfmText.ItemDetailPage"/>                    <!--<mvfm:NavigateAction NavigateName="MvfmText.ItemDetailPage"/>-->                </i:EventTrigger>            </i:Interaction.Triggers> </GridView>
  GridView自带的属性设置就不说明了,重点介绍
            <i:Interaction.Triggers>                <i:EventTrigger  EventName="ItemClick">                    <mvfm:EventArgNameCommandAction EventArgName="ClickedItem" Command="{Binding SetCurrentItemCommand}"/>                    <local:NavigateAction NavigateName="MvfmText.ItemDetailPage"/>                </i:EventTrigger>            </i:Interaction.Triggers>

这几行语句。Triggers,Behavior,Action是mvfm所依赖的核心技术中德3个。Triggers为触发器,Behavior为行为附加,Action则负责执行某些命令。Triggers往往与Action相伴出现,通过控件中的某些行为或event触发执行Action。

这几行语句中EventTrigger指定由GridView中的ItemClick事件触发,触发的Action分别为NavigateAction和EventArgNameCommandAction。NavigateAction执行导航,NavigateName参数指定导航页,此Action触发后界面将直接跳转到ItemDetailPage页面。也就是说若点击了GridView中的某一项,界面就会跳转到ItemDetailPage页。EventArgNameCommandAction中的Command指定所要执行的命令,这里则指定了执行SampleFunctionModel中的SetCurrentItemCommand命令。EventArgName参数指定将EventArg中的哪个属性作为参数传递到Command中。

  然后看下HeaderTemplate中的代码:

<GroupStyle.HeaderTemplate>                        <DataTemplate>                            <Grid Margin="1,0,0,6">                                <Button                                    AutomationProperties.Name="Group Title"                                                                      Style="{StaticResource TextPrimaryButtonStyle}" >                                    <StackPanel Orientation="Horizontal">                                        <TextBlock Text="{Binding Title}" Margin="3,-7,10,10" Style="{StaticResource GroupHeaderTextStyle}" />                                        <TextBlock Text="{StaticResource ChevronGlyph}" FontFamily="Segoe UI Symbol" Margin="0,-7,0,10" Style="{StaticResource GroupHeaderTextStyle}"/>                                    </StackPanel>                                    <i:Interaction.Triggers>                                        <i:EventTrigger  EventName="Click">                                            <mvfm:ExInvokeCommandAction Command="{Binding SetCurrentGroupCommand, Source={StaticResource SampleFunctionModel}}" CommandParameter="{Binding}"/>                                            <local:NavigateAction NavigateName="MvfmText.GroupDetailPage"/>                                        </i:EventTrigger>                                    </i:Interaction.Triggers>                                </Button>                            </Grid>                        </DataTemplate></GroupStyle.HeaderTemplate>
  注意其中的这几行语句

 <i:Interaction.Triggers>     <i:EventTrigger  EventName="Click">        <mvfm:ExInvokeCommandAction Command="{Binding SetCurrentGroupCommand, Source={StaticResource SampleFunctionModel}}" CommandParameter="{Binding}"/>        <local:NavigateAction NavigateName="MvfmText.GroupDetailPage"/>     </i:EventTrigger> </i:Interaction.Triggers>
原理与前面是一样的,主要说明下ExInvokeCommandAction, ExInvokeCommandAction中Command指定的是完整的Command路径,这样的好处在于不管Action在何处声明,都可以执行到functiong model中的命令。 其中CommandParameter则是将自身的数据源作为参数传输到了执行对应命令的函数中,此命令对应的是如下函数
        void SetCurrentGroup(object parameter)        {            var Group = (parameter as ExCommandParameter).Parameter as SampleDataGroup;            if (Group != null)                CurrentGroup = Group;        }
  剩下两个页面就不额外说明了,原理差不多,运行后你会发现执行效果和原来没有任何差别。由于page对应的.cs中不需要写人和代码,这将大大减轻我们的工作量,并且这样的边写方式易于修改,当需求频繁变化是也能轻松应对。

并且我们还有两个原model中提供的两个函数没有用到,GetGroup和GetItem完全没用用武之地了,因为我们可以从页面中直接获取对应的数据,并在另一个页面中使用,这样省去了页面间的参数传递以及部分数据处理逻辑。这样轻松的编程方式

你还有什么理由拒绝呢?以后我会介绍mvfm的高级用法,熟练使用以后编写代码效率将会大大提高。

   示例代码在本人空间资源中

原创粉丝点击