程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 擴展GridView控件——為內容項添加拖放及分組功能,gridview拖放

擴展GridView控件——為內容項添加拖放及分組功能,gridview拖放

編輯:C#入門知識

擴展GridView控件——為內容項添加拖放及分組功能,gridview拖放


引言

相信大家對GridView都不陌生,是非常有用的控件,用於平鋪有序的顯示多個內容項。打開任何WinRT應用或者是微軟合作商的網站,都會在APP中發現GridView的使用。“Tiles”提供了一個簡單易用,平鋪方式來組織內容顯示。Windows8的開始菜單是最典型的GridView 示例。“開始菜單”顯示了系統中安裝的所有應用程序,而且支持重新排列。

本文源於我們項目的開發人員,他們想在項目中提供與GridView相同的用戶體驗,想要創建類GridView控件。

GridView 可以顯示大小不定的內容項,並且以有序的方式顯示。如果各個內容項無序,並且內容尺寸大小相同,GirdView還支持拖拽操作。然而,這些功能並不是默認提供的,需要編寫一定的代碼才能實現。

本文主要介紹了擴展GridView控件——稱為GridViewEx, GridViewEx主要實現GridView在不同大小的內容項中的拖拽功能。

背景

首先了解GridView的基本屬性和功能,GridView包含一些屬性集和 ItemTemplate。為了實現通過拖拽操作執行重排列功能,必須完成以下三件事:

1. 設置AllowDrop屬性為true;

2. 設置CanReorderItems 屬性值為True;

3. 綁定數據源,該數據源必須支持數據修改或支持重排序。例如,使用ObservableCollection或IList數據源。

<GridView ItemsSource="{Binding}" AllowDrop="True" CanReorderItems="True">
    <GridView.ItemTemplate>
        <DataTemplate>
            <Border BorderBrush="Aqua" BorderThickness="1" Background="Peru">
                <Grid Margin="12">
                    <Grid.RowDefinitions>
                        <RowDefinition />
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <TextBlock Text="{Binding}"/>
                    <TextBlock Grid.Row="1">item</TextBlock>
                </Grid>
            </Border>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

擴展後的GridView使用拖拽操作將會非常方便快捷。

GridViewEx 控件

GridViewEx控件彌補了GridView,功能如下:

  • 實現Item Panel 拖拽操作,而不是WrapGrid,StackPanel、VirtualizingStackPanel等
  • 分組時,實現拖拽功能;

我們也為GridViewEx增加了新建分組的功能,如果用戶將內容項拖到控件左邊或右邊時會觸發新建分組操作。

實現拖拽代碼:

   1:  public class GridViewEx : GridView
   2:  {
   3:      /// <summary>
   4:      /// Initializes a new instance of the <see cref="GridViewEx"/> control.
   5:      /// </summary>
   6:      public GridViewEx()
   7:      {
   8:          // see attached sample
   9:      }
  10:   
  11:      private void GridViewEx_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
  12:      {
  13:          // see attached sample
  14:      }
  15:   
  16:      /// <summary>
  17:      /// Stores dragged items into DragEventArgs.Data.Properties["Items"] value.
  18:      /// Override this method to set custom drag data if you need to.
  19:      /// </summary>
  20:      protected virtual void OnDragStarting(DragItemsStartingEventArgs e)
  21:      {
  22:          // see attached sample
  23:      }

該控件包含幾個變量,用來存儲拖放內容的索引。OnDragStarting 事件在DragEventArgs.Data.Properties[“Items”] 中存儲拖拽的內容。OnDragStarting 需要根據自己的需求重寫。

當用戶拖拽某一項內容時,需要給用戶提示來引導用戶將內容放在合適的位置上。標准的GriView對象是通過滑動相鄰的內實項來實現的。本文將在GridViewEx中完善此操作。

   1:  /// <summary>
   2:  /// Shows reoder hints while custom dragging.
   3:  /// </summary>
   4:  protected override void OnDragOver(DragEventArgs e)
   5:  {
   6:      // see attached sample }
   7:   
   8:  private int GetDragOverIndex(DragEventArgs e)
   9:  {
  10:      // see attached sample 
  11:  }

實現拖放代碼

首先需要重寫GridView.OnDrop方法,該方法會當用戶釋放某一項內容時觸發。重寫Ondrop方法,代碼如下:

   1:  /// <summary>
   2:  /// Handles drag and drop for cases when it is not supported by the Windows.UI.Xaml.Controls.GridView control
   3:  /// </summary>
   4:  protected override async void OnDrop(DragEventArgs e)
   5:  {
   6:      // see attached sample
   7:  }

 

OnDrop方法主要實現了內容項從源分組移到目標分組的邏輯代碼,以及創建新分組的功能。

添加新分組

如果GrideView通過IsSourceGrouped值為True來綁定CollectionViewSource情況下,GridView提供分組功能,這就意味著分組必須對數據源進行分組,但GridView沒有訪問數據的權限。因此本文在執行拖放操作時,實現添加新分組功能。GridViewEx.BeforeDrop事件處理此需求,並且提供更多的數據信息,如DragEventArgs數據。

當用戶執行拖放操作時,觸發BeforeDrop 事件。

   1:  /// <summary>
   2:  /// Occurs before performing drop operation,
   3:  /// </summary>
   4:  public event EventHandler<BeforeDropItemsEventArgs> BeforeDrop;
   5:  /// <summary>
   6:  /// Rises the <see cref="BeforeDrop"/> event.
   7:  /// </summary>
   8:  /// <param name="e">Event data for the event.</param>
   9:  protected virtual void OnBeforeDrop(BeforeDropItemsEventArgs e)
  10:  {
  11:      // see attached sample 
  12:  }

BeforeDropItemEventArgs包含關於被拖拽的內容項的重要信息,該信息在OnDrop事件中可使用的。

   1:  /// <summary>
   2:  /// Provides data for the <see cref="GridViewEx.BeforeDrop"/> event.
   3:  /// </summary>
   4:  public sealed class BeforeDropItemsEventArgs : System.ComponentModel.CancelEventArgs
   5:  {
   6:      /// <summary>
   7:      /// Gets the item which is being dragged.
   8:      /// </summary>
   9:      public object Item
  10:      {
  11:          get;
  12:      }
  13:      /// <summary>
  14:      /// Gets the current item index in the underlying data source.
  15:      /// </summary>
  16:      public int OldIndex
  17:      {
  18:          get;
  19:      }
  20:      /// <summary>
  21:      /// Gets the index in the underlying data source where
  22:      /// the item will be inserted by the drop operation.
  23:      /// </summary>
  24:      public int NewIndex
  25:      {
  26:          get;
  27:      }
  28:      /// <summary>
  29:      /// Gets the bool value determining whether end-user actions requested
  30:      /// creation of the new group in the underlying data source.
  31:      /// This property only makes sense if GridViewEx.IsGrouping property is true.
  32:      /// </summary>
  33:      /// <remarks>
  34:      /// If this property is true, create the new data group and insert it into
  35:      /// the groups collection at the positions, specified by the 
  36:      /// <see cref="BeforeDropItemsEventArgs.NewGroupIndex"/> property value.
  37:      /// Then the <see cref="GridViewEx"/> will insert dragged item
  38:      /// into the newly added group.
  39:      /// </remarks>
  40:      public bool RequestCreateNewGroup
  41:      {
  42:          get;
  43:      }
  44:      /// <summary>
  45:      /// Gets the current item data group index in the underlying data source.
  46:      /// This property only makes sense if GridViewEx.IsGrouping property is true.
  47:      /// </summary>
  48:      public int OldGroupIndex
  49:      {
  50:          get;
  51:      }
  52:      /// <summary>
  53:      /// Gets the data group index in the underlying data source
  54:      /// where the item will be inserted by the drop operation.
  55:      /// This property only makes sense if GridViewEx.IsGrouping property is true.
  56:      /// </summary>
  57:      public int NewGroupIndex
  58:      {
  59:          get;
  60:      }
  61:      /// <summary>
  62:      /// Gets the original <see cref="DragEventArgs"/> data. 
  63:      /// </summary>
  64:      public DragEventArgs DragEventArgs
  65:      {
  66:          get;
  67:      }
  68:  }

AllowNewGroup屬性確定用戶拖拽某一內容項到控件邊界時,是否創建新組。GridView並沒有提供此功能,在GridViewEX添加此功能。

   1:  /// <summary>
   2:  /// Gets or sets the value determining whether new group should be created at 
   3:  /// dragging the item to the empty space.
   4:  /// </summary>
   5:  public bool AllowNewGroup
   6:  {
   7:      get { return (bool)GetValue(AllowNewGroupProperty); }
   8:      set { SetValue(AllowNewGroupProperty, value); }
   9:  }
  10:   
  11:  /// <summary>
  12:  /// Identifies the <see cref="AllowNewGroup"/> dependency property.
  13:  /// </summary>
  14:  public static readonly DependencyProperty AllowNewGroupProperty =
  15:          DependencyProperty.Register("AllowNewGroup", typeof(bool), 
  16:          typeof(GridViewEx), new PropertyMetadata(false));

為了在拖拽過程中添加分組,需要將AllowNewGroup屬性設置為True。處理GridViewEx.BeforeDrop事件,該事件的參數能夠幫助決定單項內容的起始位置和目的位置。在BeforeDrop事件的Handler中,使用 NewGroupIndex 創建新的數據組,並插入到已有組集合。最後,需要實現的擴展GridView控件模板。在用戶可拖拽的項目的位置創建新分組,並使用占位符來代替。一旦用戶拖某一內容放置到控件的邊界時,觸發創建新分組,ItemsPresenter的兩個邊界元素是新組的占位符。

GridViewEx控件模板generic.xaml,如下:

   1:  <Style TargetType="local:GridViewEx">
   2:      <Setter Property="Padding" Value="0,0,0,10" />
   3:      <Setter Property="IsTabStop" Value="False" />
   4:      <Setter Property="TabNavigation" Value="Once" />
   5:      <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
   6:      <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"/>
   7:      <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Enabled" />
   8:      <Setter Property="ScrollViewer.IsHorizontalRailEnabled" Value="False" />
   9:      <Setter Property="ScrollViewer.VerticalScrollMode" Value="Disabled" />
  10:      <Setter Property="ScrollViewer.IsVerticalRailEnabled" Value="False" />
  11:      <Setter Property="ScrollViewer.ZoomMode" Value="Disabled" />
  12:      <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
  13:      <Setter Property="ScrollViewer.BringIntoViewOnFocusChange" Value="True" />
  14:      <Setter Property="IsSwipeEnabled" Value="True" />
  15:      <Setter Property="Template">
  16:          <Setter.Value>
  17:              <ControlTemplate TargetType="local:GridViewEx">
  18:                  <Border BorderBrush="{TemplateBinding BorderBrush}"
  19:                          Background="{TemplateBinding Background}"
  20:                          BorderThickness="{TemplateBinding BorderThickness}">
  21:                      <ScrollViewer x:Name="ScrollViewer"
  22:                              TabNavigation="{TemplateBinding TabNavigation}"
  23:                              HorizontalScrollMode="
  24:                              {TemplateBinding ScrollViewer.HorizontalScrollMode}"
  25:                              HorizontalScrollBarVisibility=
  26:                                "{TemplateBinding 
  27:                                ScrollViewer.HorizontalScrollBarVisibility}"
  28:                              IsHorizontalScrollChainingEnabled=
  29:                                "{TemplateBinding 
  30:                                ScrollViewer.IsHorizontalScrollChainingEnabled}"
  31:                              VerticalScrollMode="
  32:                              {TemplateBinding ScrollViewer.VerticalScrollMode}"
  33:                              VerticalScrollBarVisibility=
  34:                                "{TemplateBinding 
  35:                                ScrollViewer.VerticalScrollBarVisibility}"
  36:                              IsVerticalScrollChainingEnabled=
  37:                                "{TemplateBinding 
  38:                                ScrollViewer.IsVerticalScrollChainingEnabled}"
  39:                              IsHorizontalRailEnabled="
  40:                              {TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
  41:                              IsVerticalRailEnabled="
  42:                              {TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
  43:                              ZoomMode="{TemplateBinding 
  44:                              ScrollViewer.ZoomMode}"
  45:                              IsDeferredScrollingEnabled="
  46:                              {TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
  47:                              BringIntoViewOnFocusChange="
  48:                              {TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}">
  49:                          <StackPanel Orientation="Horizontal">
  50:                              <Border Width="60" 
  51:                              x:Name="NewGroupPlaceHolderFirst" 
  52:                                      Background="Transparent" 
  53:                                      Padding="{TemplateBinding Padding}" 
  54:                                      Visibility="{Binding AllowNewGroup, 
  55:                                      Converter={StaticResource 
  56:                                        VisibilityConverter}, 
  57:                                        RelativeSource={RelativeSource TemplatedParent}}"/>
  58:                              <ItemsPresenter 
  59:                                  Header="{TemplateBinding Header}" 
  60:                                  HeaderTemplate="{TemplateBinding HeaderTemplate}"
  61:                                  HeaderTransitions="{TemplateBinding HeaderTransitions}"
  62:                                  Padding="{TemplateBinding Padding}"/>
  63:                              <Border Width="60" 
  64:                              x:Name="NewGroupPlaceHolderLast" 
  65:                                      Background="Transparent" 
  66:                                      Padding="{TemplateBinding Padding}" 
  67:                                      Visibility="{Binding AllowNewGroup, 
  68:                                      Converter={StaticResource 
  69:                                        VisibilityConverter}, 
  70:                                        RelativeSource={RelativeSource TemplatedParent}}"/>
  71:                          </StackPanel>
  72:                      </ScrollViewer>
  73:                  </Border>
  74:              </ControlTemplate>
  75:          </Setter.Value>
  76:      </Setter>
  77:  </Style>

 

豐富GridViewEx功能

如上所示,我們已經實現了基本的拖拽操作,與Windows8 開始菜單類似的功能,接下來討論如何實現以下功能:

  • 尺寸大小不定的內容項
  • 分組
  • 添加新組
  • 節省跨會話布局空間

大小不定的內容項

Windows8展示了不同大小的Tiles,但是目前GridView或GridViewEx還不支持此功能。因為GridView使用WrapGrid作為默認的ItemsPanel,WrapPanel只能創建一種布局,即所有的條目尺寸相同的。因此微軟提供了VariableSizedWrapGrid,支持不同大小塊的布局創建。

GridViewEx控件的優勢在於能夠使用VariableSizedWrapGrid,並且很好的支持拖放操作。為了使用VariableSizedWrapGrid 並顯示不同大小的內容項,必須實現以下功能:

將GridViewEx.ItemsPanel 設置為VariableSizedWrapGrid

在GridView中重寫GridView 的PrepareContainerForItemOverride 方法。在該方法中,可以設置Item的RowSpan或ColumnSpan屬性來識別內容項的大小。

即生成繼承GridViewEx的新控件MyGridView。為什麼需要擴展GridViewEx控件而不是重寫GridViewEx的PrepareContainerForItemOverride方法?因為指定Item尺寸的邏輯必須放在數據模型中,而不是控件內部。

如想將某一項顯示較大一點,需要在數據項中創建一個屬性返回比1大的整型數值,來設置RowSpanhuoColumnSpan屬性。

   1:  public class Item
   2:  {
   3:      public int Id { get; set; }
   4:      public int ItemSize { get; set; }
   5:      /* */
   6:  }

因此,當創建新的內容項,我們要指定ItemSize屬性。如果值為1則表明常規尺寸,如果值為2則表明大尺寸,ColumnSpan屬性則設置為2。

   1:  /// <summary>
   2:  /// This class sets VariableSizedWrapGrid.ColumnSpanProperty for GridViewItem controls, 
   3:  /// so that every item can have different size in the VariableSizedWrapGrid.
   4:  /// </summary>
   5:  public class MyGridView : GridViewSamples.Controls.GridViewEx
   6:  {
   7:      // set ColumnSpan according to the business logic
   8:      // (maybe some GridViewSamples.Samples.Item or group properties)
   9:      protected override void PrepareContainerForItemOverride(
  10:                Windows.UI.Xaml.DependencyObject element, object item)
  11:      {
  12:          try
  13:          {
  14:              GridViewSamples.Samples.Item it = item as GridViewSamples.Samples.Item;
  15:              if (it != null)
  16:              {
  17:                  element.SetValue(
  18:                    Windows.UI.Xaml.Controls.VariableSizedWrapGrid.ColumnSpanProperty, it.ItemSize);
  19:              }
  20:          }
  21:          catch
  22:          {
  23:              element.SetValue(Windows.UI.Xaml.Controls.VariableSizedWrapGrid.ColumnSpanProperty, 1);
  24:          }
  25:          finally
  26:          {
  27:              base.PrepareContainerForItemOverride(element, item);
  28:          }
  29:      }
  30:  }

創建MyGridView實例,並綁定到數據集合。

   1:  <local:MyGridView AllowDrop="True" CanReorderItems="True" 
   2:            CanDragItems="True" IsSwipeEnabled="True"
   3:            ItemsSource="{Binding}" 
   4:            ItemTemplate="{StaticResource ItemTemplate}" >
   5:      <GridView.ItemsPanel>
   6:          <ItemsPanelTemplate>
   7:              <VariableSizedWrapGrid ItemHeight="160" 
   8:              ItemWidth="160" />
   9:          </ItemsPanelTemplate>
  10:      </GridView.ItemsPanel>
  11:      <GridView.ItemContainerStyle>
  12:          <Style TargetType="GridViewItem">
  13:              <Setter Property="HorizontalContentAlignment" 
  14:              Value="Stretch"/>
  15:              <Setter Property="VerticalContentAlignment" 
  16:              Value="Stretch"/>
  17:          </Style>
  18:      </GridView.ItemContainerStyle>
  19:  </local:MyGridView>

如上所示,我們將指定內容項的ItemSize屬性設置為2,效果如圖所示:

分組

使用GridViewEx控件,能夠實現添加新分組和拖拽等功能,也是在App中最為常見的功能,實現分組必須完成以下設置:

  • 為GridView綁定CollectionViewSource,必須使用支持分組的數據源。CollectionViewSource可視為代理服務器。
  • 使用GroupStyle確定分組結果如何顯示,GroupStyle包含Header Tempate及Panel,因此需要指定子項目的排序方式。

在GridViewEx中添加支持不同大小的內容項,邏輯代碼:

   1:  <local:MyGridView AllowDrop="True" CanReorderItems="True" 
   2:            CanDragItems="True" IsSwipeEnabled="True"
   3:            ItemsSource="{Binding}" 
   4:            ItemTemplate="{StaticResource ItemTemplate}" >
   5:      <GridView.ItemsPanel>
   6:          <ItemsPanelTemplate>
   7:              <VirtualizingStackPanel Orientation="Horizontal"/>
   8:          </ItemsPanelTemplate>
   9:      </GridView.ItemsPanel>
  10:      <GridView.GroupStyle>
  11:          <GroupStyle>
  12:              <GroupStyle.HeaderTemplate>
  13:                  <DataTemplate>
  14:                      <Grid Background="LightGray" 
  15:                      Margin="0">
  16:                          <TextBlock Foreground="Black" 
  17:                          Margin="10" 
  18:                                    Style="{StaticResource 
  19:                                    GroupHeaderTextStyle}">
  20:                              <Run Text="{Binding Id}"/>
  21:                              <Run Text=" group"/>
  22:                          </TextBlock>
  23:                      </Grid>
  24:                  </DataTemplate>
  25:              </GroupStyle.HeaderTemplate>
  26:   
  27:              <GroupStyle.ContainerStyle>
  28:                  <Style TargetType="GroupItem">
  29:                      <Setter Property="BorderBrush" 
  30:                      Value="DarkGray"/>
  31:                      <Setter Property="BorderThickness" 
  32:                      Value="2"/>
  33:                      <Setter Property="Margin" 
  34:                      Value="3,0"/>
  35:                  </Style>
  36:              </GroupStyle.ContainerStyle>
  37:   
  38:              <GroupStyle.Panel>
  39:                  <ItemsPanelTemplate>
  40:                      <VariableSizedWrapGrid ItemHeight="160" 
  41:                      ItemWidth="160" />
  42:                  </ItemsPanelTemplate>
  43:              </GroupStyle.Panel>
  44:          </GroupStyle>
  45:      </GridView.GroupStyle>
  46:   
  47:      <GridView.ItemContainerStyle>
  48:          <Style TargetType="GridViewItem">
  49:              <Setter Property="HorizontalContentAlignment" 
  50:              Value="Stretch"/>
  51:              <Setter Property="VerticalContentAlignment" 
  52:              Value="Stretch"/>
  53:          </Style>
  54:      </GridView.ItemContainerStyle>
  55:  </local:MyGridView>

運行演示:

添加新分組

自定義的GridViewEx控件支持新分組的創建,因此需要設置AllowNewGroup為True。其次處理添加新分組的數據層,處理GridViewEx.BeforeDrop 事件。

   1:  /// <summary>
   2:  /// Creates new CollectionViewSource and updates page DataContext.
   3:  /// </summary>
   4:  private void UpdateDataContext()
   5:  {
   6:      CollectionViewSource source = new CollectionViewSource();
   7:      source.Source = _groups;
   8:      source.ItemsPath = new PropertyPath("Items");
   9:      source.IsSourceGrouped = true;
  10:      this.DataContext = source;
  11:  }
  12:  // creates new group in the data source,
  13:  // if end-user drags item to the new group placeholder
  14:  private void MyGridView_BeforeDrop(object sender, Controls.BeforeDropItemsEventArgs e)
  15:  {
  16:      if (e.RequestCreateNewGroup)
  17:      {
  18:          // create new group and re-assign datasource 
  19:          Group group = Group.GetNewGroup();
  20:          if (e.NewGroupIndex == 0)
  21:          {
  22:              _groups.Insert(0, group);
  23:          }
  24:          else
  25:          {
  26:              _groups.Add(group);
  27:          }
  28:          UpdateDataContext();
  29:      }
  30:  }

也可以使用Drop事件刪除空分組

   1:  // removes empty groups (except the last one)
   2:  private void MyGridView_Drop(object sender, DragEventArgs e)
   3:  {
   4:      bool needReset = false;
   5:      for (int i = _groups.Count - 1; i >= 0; i--)
   6:      {
   7:          if (_groups[i].Items.Count == 0 && _groups.Count > 1)
   8:          {
   9:              _groups.RemoveAt(i);
  10:              needReset = true;
  11:          }
  12:      }
  13:      if (needReset)
  14:      {
  15:          UpdateDataContext();
  16:      }
  17:  }

節省布局空間

Windows8支持掛起或終止功能,為了提供更好的用戶體驗,我們繼續改善此前實現的功能,當用戶離開當前頁面,將當前的布局暫存。在本示例中,我們使用JSON 字符串簡化數據序列化。根據已有的數據、數據的大小及需求,以其他格式來保存數據。我們主要將“業務對象集合”保存。

為了節省布局空間。重寫LayoutAwarePage方法:

   1:  /// <summary>
   2:  /// Populates the page with content passed during navigation.  Any saved state is also
   3:  /// provided when recreating a page from a prior session.
   4:  /// </summary>
   5:  /// <param name="navigationParameter">The parameter value passed to
   6:  /// <see cref="Frame.Navigate(Type, 
   7:  /// Object)"/> when this page was initially requested.
   8:  /// </param>
   9:  /// <param name="pageState"
  10:  /// >A dictionary of state preserved by this page during an earlier
  11:  /// session.  This will be null the first time a page is visited.</param>
  12:  protected override void LoadState(Object navigationParameter, 
  13:      Dictionary<String, Object> pageState)
  14:  {
  15:      base.LoadState(navigationParameter, pageState);
  16:      if (pageState != null && pageState.Count > 0 
  17:      && pageState.ContainsKey("Groups"))
  18:      {
  19:          // restore groups and items from the previously serialized state
  20:          System.Runtime.Serialization.Json.DataContractJsonSerializer rootSer = 
  21:          new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(List<Group>));
  22:          var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes
  23:              ((string)pageState["Groups"]));
  24:          _groups = (List<Group>)rootSer.ReadObject(stream);
  25:      }
  26:      else
  27:      {
  28:          // if we get here for the first time and don't have
  29:          // serialized content, fill groups and items from scratch
  30:          for (int j = 1; j <= 12; j++)
  31:          {
  32:              Group group = Group.GetNewGroup();
  33:              for (int i = 1; i <= 7 + j % 3; i++)
  34:              {
  35:                  group.Items.Add(new Item()
  36:                  {
  37:                      Id = i,
  38:                      GroupId = group.Id
  39:                  });
  40:              }
  41:              _groups.Add(group);
  42:          }
  43:      }
  44:      UpdateDataContext();
  45:  }
  46:   
  47:  /// <summary>
  48:  /// Preserves state associated with this page in case the application is suspended or the
  49:  /// page is discarded from the navigation cache.  Values must conform to the serialization
  50:  /// requirements of <see cref="SuspensionManager.SessionState"/>.
  51:  /// </summary>
  52:  /// <param name="pageState">
  53:  /// An empty dictionary to be populated with serializable state.</param>
  54:  protected override void SaveState(Dictionary<String, Object> pageState)
  55:  {
  56:      // save groups and items to JSON string so that 
  57:      // it's possible to restore page state later
  58:      base.SaveState(pageState);
  59:      System.Runtime.Serialization.Json.DataContractJsonSerializer rootSer = 
  60:          new System.Runtime.Serialization.Json.DataContractJsonSerializer
  61:          (typeof(List<Group>));
  62:      var stream = new MemoryStream();
  63:      rootSer.WriteObject(stream, _groups);
  64:      string str = System.Text.Encoding.UTF8.GetString(stream.ToArray(), 
  65:              0, (int)stream.Length);
  66:      pageState.Add("Groups", str);
  67:  }
  68:   
  69:  /// <summary>
  70:  /// Invoked when this page is about to be displayed in a Frame.
  71:  /// </summary>
  72:  /// <param name="e">Event data that describes 
  73:  /// how this page was reached.  The Parameter
  74:  /// property is typically used to configure the page.</param>
  75:  protected override void OnNavigatedTo(NavigationEventArgs e)
  76:  {
  77:      // restore page state
  78:      var frameState = 
  79:      GridViewSamples.Common.SuspensionManager.SessionStateForFrame(this.Frame);
  80:      if (frameState.ContainsKey("TilePageData"))
  81:      {
  82:          this.LoadState(e.Parameter, 
  83:          (Dictionary<String, Object>)frameState["TilePageData"]);
  84:      }
  85:      else
  86:      {
  87:          this.LoadState(e.Parameter, null);
  88:      }
  89:  }
  90:   
  91:  protected override void OnNavigatedFrom(NavigationEventArgs e)
  92:  {
  93:      // save page state with "TilePageData" key
  94:      var frameState = 
  95:      GridViewSamples.Common.SuspensionManager.SessionStateForFrame(this.Frame);
  96:      var pageState = new Dictionary<String, Object>();
  97:      this.SaveState(pageState);
  98:      frameState["TilePageData"] = pageState;
  99:  }

總結

GridViewEx控件豐富了GirdView控件功能,改進了基礎功能,提升用戶體驗。到此已經實現了GridView項與Windows8開始菜單具有的相同用戶體驗,如果你想了解如何在Windows10平台下開發UWP引用,請持續關注下篇文章:如何在Windows10中開發UWP應用

 

原文鏈接:http://www.codeproject.com/Articles/536519/Extending-GridView-with-Drag-and-Drop-for-Grouping

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved