如何將GridViewEX升級到UWP(Universal Windows Platform)平臺

引言

 

上一篇文章中,咱們主要講解了如何在保證GridView控件的用戶體驗基礎上,擴展GridView生成GridViewEx控件,增長動態添加新分組功能等,本文在上文的基礎上,介紹如何在Windows10中使用GridViewEx,開發UWP應用。windows

extended GridView with grouping, variable sized items and drag and drop support

 

Demo 下載:app

GridViewLiveTiles.zipide

 GridViewEx.zip工具

 GridViewDemo.zip佈局

開發UWP應用程序

開發UWP應用程序最好是從建立empty項目開始,重用已開發的一些模塊,這樣能夠提升開發效率。開發工具

本文爲了建立UWP 應用程序,首先建立一些通用類以下,詳細代碼見附件:ui

  • Common/VisibilityConverter.cs
  • Common/LayoutAwarePage.cs
  • Common/SuspensionManager.cs

DataModel 和Sample 文件夾下的全部文件均可以重用。this

修改佈局和導航

VisibilityConverter 和 SuspensionsManager暫時不須要修改,可直接在UWP中使用。主要修改佈局和導航邏輯文件。spa

因爲微軟支持的設備種類愈來愈多,致使ApplicationViewState再也不適用。UWP平臺提供了其餘的解決方法如AdaptiveTriggers,內置了自適應佈局。所以建立UWP應用程序,首先須要刪除全部ApplicationViewStates的代碼。可能會致使使用LayoutAwarePage的部分會報錯。所以咱們須要作一些兼容性的改變。code

不管是WinRT仍是UWP應用,都會使用返回鍵導航。桌面WinRTx應用會在Xaml文件添加返回按鈕。可是在UWP應用中,很是靈活,桌面應用能夠在標題欄中添加返回按鈕,在移動設備中不只能使用標題欄中的返回鍵,也可使用物理返回鍵實現導航功能。UWP的方法比較通用,且不須要編寫自定義的Xaml文件。所以只須要開發一個基類,應用到不一樣的Xaml 頁面中就能夠實現輕鬆實現導航功能,不須要重複編寫代碼。修改後的LayoutAwarePage 類:

 1: protected override void OnNavigatedTo(NavigationEventArgs e)
 2: {
 3:  // subscribe on Back button event
 4:  if (IsWindowsPhoneDevice())
 5:  {
 6:  // use hardware button
 7:  Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
 8:  }
 9:  else
 10:  {
 11:  // enable/disable window back button depending on navigation state
 12:  var currentView = SystemNavigationManager.GetForCurrentView();
 13:  currentView.AppViewBackButtonVisibility = this.Frame != null && this.Frame.CanGoBack ?
 14:  AppViewBackButtonVisibility.Visible : AppViewBackButtonVisibility.Collapsed;
 15:  currentView.BackRequested += backButton_Tapped;
 16:  }
 17:  ...
 18: protected override void OnNavigatedFrom(NavigationEventArgs e)
 19: {
 20:  // unsubscribe from Back button event
 21:  if (IsWindowsPhoneDevice())
 22:  {
 23:  Windows.Phone.UI.Input.HardwareButtons.BackPressed -= HardwareButtons_BackPressed;
 24:  }
 25:  else
 26:  {
 27:  // unsubscribe from window back button
 28:  var currentView = SystemNavigationManager.GetForCurrentView();
 29:  currentView.BackRequested -= backButton_Tapped;
 30:  }
 31:  ...
 32: // handle Back button events
 33: private void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)
 34: {
 35:  if (this.Frame != null && this.Frame.CanGoBack)
 36:  {
 37:  e.Handled = true;
 38:  this.Frame.GoBack();
 39:  }
 40: }
 41: private void backButton_Tapped(object sender, BackRequestedEventArgs e)
 42: {
 43:  this.GoBack(this, new RoutedEventArgs());
 44: }

 

由於須要使用物理返回鍵,咱們須要在程序中添加引用文件「Windows Mobile Extensions for the UWP」。

如今由LayoutAwarePage派生而來的全部頁面均可直接使用,無需在多個文件中添加引用。

LayoutAwarePage 類最後添加設備查詢的靜態方法,來檢測運行時設備。

 1: public static bool IsWindowsPhoneDevice()
 2: {
 3:  if (Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
 4:  {
 5:  return true;
 6:  }
 7:  return false;
 8: }

 

其餘平臺

1. 若是想保證應用程序在Windows10中具備與系統一致的界面風格和用戶體驗,可以使用Windows 10 ThemeResources (主題資源)。

2. 微軟也在Windows10 發佈中升級了GridView控件,相對於Windows 8 版原本說,最重要的改變是添加了用戶重定向檢測。

3. VariableSizedWrapGrid 面板也添加了重定向檢測功能。而且去掉了行和列自動展開的功能。下面是Windows8 版本的Xaml文件,在Windows10 中已經沒法使用。

 1: <GridView  Grid.Row="1" Grid.Column="1" Margin="10" AllowDrop="True" CanReorderItems="True" CanDragItems="True" IsSwipeEnabled="True">
 2:  <GridView.ItemsPanel>
 3:  <ItemsPanelTemplate>
 4:  <VariableSizedWrapGrid/>
 5:  </ItemsPanelTemplate>
 6:  </GridView.ItemsPanel>
 7:  <Rectangle Height="100" Width="200" Fill="Blue" />
 8:  <Rectangle Height="100" Width="100" Fill="Red" />
 9:  <Rectangle Height="100" Width="100" Fill="Yellow" />
 10:  <Rectangle Height="100" Width="100" Fill="Green" />

最好的解決方法就是將VariableSizedWrapGrid 與item的屬性綁定,並將值傳給自定義的GridView控件的ListViewItemPresenter 元素:

 1: /// <summary>
 2: /// This class sets VariableSizedWrapGrid.ColumnSpanProperty for GridViewItem controls,
 3: /// so that every item can have different size in the VariableSizedWrapGrid.
 4: /// Also it sets VerticalContentAlignment and HorizontalContentAlignment to Stretch.
 5: /// </summary>
 6: public class GridViewTiled : GridView
 7: {
 8:  // set ColumnSpan according to the business logic (maybe some GridViewSamples.Samples.Item or group properties)
 9:  protected override void PrepareContainerForItemOverride(Windows.UI.Xaml.DependencyObject element, object item)
 10:  {
 11:  element.SetValue(ContentControl.HorizontalContentAlignmentProperty, HorizontalAlignment.Stretch);
 12:  element.SetValue(ContentControl.VerticalContentAlignmentProperty, VerticalAlignment.Stretch);
 13:  UIElement el = item as UIElement;
 14:  if (el != null)
 15:  {
 16:  int colSpan = Windows.UI.Xaml.Controls.VariableSizedWrapGrid.GetColumnSpan(el);
 17:  int rowSpan = Windows.UI.Xaml.Controls.VariableSizedWrapGrid.GetRowSpan(el);
 18:  if (rowSpan > 1)
 19:  {
 20:  // only set it if it has non-defaul value
 21:  element.SetValue(Windows.UI.Xaml.Controls.VariableSizedWrapGrid.RowSpanProperty, rowSpan);
 22:  }
 23:  if (colSpan > 1)
 24:  {
 25:  // only set it if it has non-defaul value
 26:  element.SetValue(Windows.UI.Xaml.Controls.VariableSizedWrapGrid.ColumnSpanProperty, colSpan);
 27:  }
 28:  }
 29:  base.PrepareContainerForItemOverride(element, item);
 30:  }
 31: }

 

UWP中的XAML文件:

<controls:GridViewTiled Grid.Row="1" Grid.Column="1" Margin="10" AllowDrop="True" CanReorderItems="True" CanDragItems="True" > <controls:GridViewTiled.ItemsPanel> <ItemsPanelTemplate> <VariableSizedWrapGrid ItemHeight="100" ItemWidth="100" Orientation="Horizontal"/> </ItemsPanelTemplate> </controls:GridViewTiled.ItemsPanel> <Rectangle VariableSizedWrapGrid.ColumnSpan="2" VariableSizedWrapGrid.RowSpan="2" Fill="Blue" /> <Rectangle Fill="Red" /> <Rectangle Fill="Yellow" /> <Rectangle Fill="Green" />

新佔位符(NewGroupPlaceholder)控件

WinRT版的GridViewEx控件使用了簡單border做爲新分組的佔位符,在拖拽項過程當中外觀是靜態的,沒法改變。爲了使界面對用戶更加友好,而且將拖放的位置高亮, 所以咱們新建了新的「NewGroupPlaceholder」控件,在拖拽過程當中有簡單的狀態切換邏輯。

GridViewEx - NewGroupPlaceholder

代碼很簡單,見附件,系統提供的控件模板代碼以下:

 1: <Style TargetType="local:NewGroupPlaceholder">
 2:  <Setter Property="Background" Value="Transparent" />
 3:  <Setter Property="Margin" Value="8" />
 4:  <Setter Property="Height" Value="32" />
 5:  <Setter Property="Template">
 6:  <Setter.Value>
 7:  <ControlTemplate TargetType="local:NewGroupPlaceholder">
 8:  <Border x:Name="root" Background="{TemplateBinding Background}">
 9:  <VisualStateManager.VisualStateGroups>
 10:  <VisualStateGroup x:Name="DragStates">
 11:  <VisualState x:Name="Normal"/>
 12:  <VisualState x:Name="DragOver">
 13:  <Storyboard>
 14:  <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="dragOverElement"/>
 15:  </Storyboard>
 16:  </VisualState>
 17:  </VisualStateGroup>
 18:  </VisualStateManager.VisualStateGroups>
 19:  <Border x:Name="dragOverElement" Background="{ThemeResource SystemControlHighlightListAccentLowBrush}" Opacity="0"/>
 20:  </Border>
 21:  </ControlTemplate>
 22:  </Setter.Value>
 23:  </Setter>
 24: </Style>

修改GridViewEx 控件

接下來,咱們將介紹如何修改GridViewEx控件,使得其能夠適應UWP。

UWP平臺下運行GridViewEx大部分的功能與WinRT保持一致。只有OnDragOver中的DragEventArgs.AcceptedOperation 屬性須要重寫。顯然UWP 中的GridView 將全部非空項的該屬性都設置爲None。所以,若是不重寫OnDragOver 方法,Drop 事件就不會被觸發。

代碼以下:

 1: protected override void OnDragOver(DragEventArgs e)
 2: {
 3:  int newIndex = GetDragOverIndex(e);
 4:  if (newIndex >= 0)
 5:  {
 6:  e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;

運行代碼時編譯器會發出不少關於ItemContainerGenerator 方法的警告,調用ItemsControl 響應方法就能夠處理Warning

VariableSizedWrapGrid存在不少限制,爲了解決這些限制,在上述代碼中添加 PrepareContainerForItemOverride 方法。最後須要升級GridViewEx 控件自帶的樣式,使其支持設備重定向。

更加適應手持設備

在GridViewEx控件中添加新的PreparingContainerForItem 事件,該事件的參數即包含數據對象,也包含UI 容器,所以可根據需求設置UI屬性,代碼以下:

 1: /// <summary>
 2: /// Set column spans depending on group id.
 3: /// </summary>
 4: /// <param name="sender"></param>
 5: /// <param name="e"></param>
 6: private void gve_PreparingContainerForItem(object sender, GridViewEx.PreparingContainerForItemEventArgs e)
 7: {
 8:  try
 9:  {
 10:  Item it = e.Item as Item;
 11:  if (it != null)
 12:  {
 13:  e.Element.SetValue(Windows.UI.Xaml.Controls.VariableSizedWrapGrid.ColumnSpanProperty, it.GroupId % 2 + 1);
 14:  }
 15:  }
 16:  catch
 17:  {
 18:  e.Element.SetValue(Windows.UI.Xaml.Controls.VariableSizedWrapGrid.ColumnSpanProperty, 1);
 19:  }
 20: }

在多設備中具備良好用戶體驗

 爲了適應多種設備,須要生成自適應佈局。本文中主要經過修改內容項的尺寸來實現該功能。建立了Bound ,Unbound以及Grouped 示例文件,Grouped 顯示單個GridView控件,所以在移動端可以修改Tile的尺寸及邊框。

Bound 和Unbound 示例是由2個GridView控件組成,小屏幕中顯的內容較多,沒法顯示更多的細節性的內容,所以使用Pivot控件保證同一時間只顯示一個GridView控件,並支持GridView之間切換。

代碼以下:

 1: public double TileSize
 2: {
 3:  get { return (double)GetValue(TileSizeProperty); }
 4:  set { SetValue(TileSizeProperty, value); }
 5: }
 6: public static readonly DependencyProperty TileSizeProperty =
 7:  DependencyProperty.Register(nameof(TileSize), typeof(double), typeof(Customized), new PropertyMetadata(100));
 8: public Customized()
 9: {
 10:  if (IsWindowsPhoneDevice())
 11:  {
 12:  TileSize = 72;
 13:  }
 14:  this.InitializeComponent();
 15: }

GridViewEx 和GridView 中綁定代碼以下:

 1: <GroupStyle.Panel>
 2:  <ItemsPanelTemplate>
 3:  <VariableSizedWrapGrid ItemHeight="{Binding TileSize, ElementName=pageRoot}"
 4:  ItemWidth="{Binding TileSize, ElementName=pageRoot}"
 5:  Orientation="Horizontal" MaximumRowsOrColumns="10"/>
 6:  </ItemsPanelTemplate>
 7: </GroupStyle.Panel>

 

總結

自定義GridViewEx控件擴展了GridView控件,豐富了功能,並新增適應UWP平臺App的開發。

示例圖片:

live tiles

UWP平臺開發工具

ComponentOne Studio for UWP,是一套能夠編寫全部 UWP 平臺應用的控件集,包括表格、報表、圖表、儀表盤、組織圖、地圖、PDF、Excel、Word、日程安排、輸入、導航等多個控件,有效幫助開發過程。

原文連接:http://www.codeproject.com/Articles/1037059/How-to-Upgrade-Extended-GridView-from-WinRT-to-Uni

相關文章
相關標籤/搜索