MVFM框架----示例

   本章介紹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的高級用法,熟練使用以後編寫代碼效率將會大大提高。

   示例代碼在本人空間資源中

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章