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

Demo 下載:
GridViewLiveTiles.zip
GridViewEx.zip
GridViewDemo.zip
開發UWP應用程序最好是從創建empty項目開始,重用已開發的一些模塊,這樣可以提高開發效率。
本文為了創建UWP 應用程序,首先創建一些通用類如下,詳細代碼見附件:
DataModel 和Sample 文件夾下的所有文件都可以重用。
VisibilityConverter 和 SuspensionsManager暫時不需要修改,可直接在UWP中使用。主要修改布局和導航邏輯文件。
由于微軟支持的設備種類越來越多,導致applicationViewState不再適用。UWP平臺提供了其他的解決方法如AdaptiveTriggers,內置了自適應布局。因此創建UWP應用程序,首先需要刪除所有ApplicationViewStates的代碼。可能會導致使用報錯。因此我們需要做一些兼容性的改變。LayoutAwarePage的部分會
無論是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" />
WinRT版的GridViewEx控件使用了簡單border作為新分組的占位符,在拖拽項過程中外觀是靜態的,無法改變。為了使界面對用戶更加友好,并且將拖放的位置高亮, 因此我們新建了新的“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控件,使得其可以適應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的開發。
示例圖片:

原文鏈接:http://www.codeproject.com/Articles/1037059/How-to-Upgrade-Extended-GridView-from-WinRT-to-Uni
新聞熱點
疑難解答