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

引言

相信你們對GridView都不陌生,是很是有用的控件,用於平鋪有序的顯示多個內容項。打開任何WinRT應用或者是微軟合做商的網站,都會在APP中發現GridView的使用。「Tiles」提供了一個簡單易用,平鋪方式來組織內容顯示。Windows8的開始菜單是最典型的GridView 示例。「開始菜單」顯示了系統中安裝的全部應用程序,並且支持從新排列。服務器

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

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

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

背景

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

1. 設置AllowDrop屬性爲true;佈局

2. 設置CanReorderItems 屬性值爲True;網站

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

<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使用拖拽操做將會很是方便快捷。this

GridViewEx 控件

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

  • 實現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應用

除了 GirdView之外,具有觸摸和鍵盤導航操做的自動或手動平鋪佈局的控件還有ComponentOne的TileControl爲WinForms ,它不但提供自適應Windows8的樣式佈局,還具備相似Windows8風格的交互體驗和靈活便捷的定製能力。

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

相關文章
相關標籤/搜索