当前位置:首页 > 操作系统 > Windows

如何将GridViewEX升级到UWP(Universal Windows Platform)平台

引言

上一篇文章中,我们主要讲解了如何在保证GridView控件的用户体验基础上,扩展GridView生成GridViewEx控件,增加动态添加新分组功能等,本文在上文的基础上,介绍如何在Windows10中使用GridViewEx,开发UWP应用。

Demo 下载:

GridViewLiveTiles.zip

?GridViewEx.zip

?GridViewDemo.zip

开发UWP应用程序

开发UWP应用程序最好是从创建empty项目开始,重用已开发的一些模块,这样可以提高开发效率。

本文为了创建UWP 应用程序,首先创建一些通用类如下,详细代码见附件:

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

DataModel 和Sample 文件夹下的所有文件都可以重用。

修改布局和导航

VisibilityConverter 和 SuspensionsManager暂时不需要修改,可直接在UWP中使用。主要修改布局和导航逻辑文件。

由于微软支持的设备种类越来越多,导致ApplicationViewState不再适用。UWP平台提供了其他的解决方法如AdaptiveTriggers,内置了自适应布局。因此创建UWP应用程序,首先需要删除所有ApplicationViewStates的代码。可能会导致使用LayoutAwarePage的部分会报错。因此我们需要做一些兼容性的改变。

无论是WinRT还是UWP应用,都会使用返回键导航。桌面WinRTx应用会在Xaml文件添加返回按钮。但是在UWP应用中,非常灵活,桌面应用可以在标题栏中添加返回按钮,在移动设备中不仅能使用标题栏中的返回键,也可以使用物理返回键实现导航功能。UWP的方法比较通用,且不需要编写自定义的Xaml文件。因此只需要开发一个基类,应用到不同的Xaml 页面中就可以实现轻松实现导航功能,不需要重复编写代码。修改后的LayoutAwarePage 类:

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

因为需要使用物理返回键,我们需要在程序中添加引用文件“Windows Mobile Extensions for the UWP”。

现在由LayoutAwarePage派生而来的所有页面都可直接使用,无需在多个文件中添加引用。

LayoutAwarePage 类最后添加设备查询的静态方法,来检测运行时设备。

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

其他平台

1. 如果想保证应用程序在Windows10中具有与系统一致的界面风格和用户体验,可使用Windows 10?ThemeResources?(主题资源)。

2. 微软也在Windows10 发布中升级了GridView控件,相对于Windows 8 版本来说,最重要的改变是添加了用户重定向检测。

3. VariableSizedWrapGrid 面板也添加了重定向检测功能。并且去掉了行和列自动展开的功能。下面是Windows8 版本的Xaml文件,在Windows10 中已经无法使用。

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

最好的解决方法就是将VariableSizedWrapGrid 与item的属性绑定,并将值传给自定义的GridView控件的ListViewItemPresenter 元素:

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

UWP中的XAML文件:

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

新占位符(NewGroupPlaceholder)控件

WinRT版的GridViewEx控件使用了简单border作为新分组的占位符,在拖拽项过程中外观是静态的,无法改变。为了使界面对用户更加友好,并且将拖放的位置高亮, 因此我们新建了新的“NewGroupPlaceholder”控件,在拖拽过程中有简单的状态切换逻辑。

代码很简单,见附件,系统提供的控件模板代码如下:

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

修改GridViewEx 控件

接下来,我们将介绍如何修改GridViewEx控件,使得其可以适应UWP。

UWP平台下运行GridViewEx大部分的功能与WinRT保持一致。只有OnDragOver中的DragEventArgs.AcceptedOperation 属性需要重写。显然UWP 中的GridView 将所有非空项的该属性都设置为None。因此,如果不重写OnDragOver 方法,Drop 事件就不会被触发。

代码如下:

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

运行代码时编译器会发出很多关于ItemContainerGenerator 方法的警告,调用ItemsControl 响应方法就可以处理Warning

VariableSizedWrapGrid存在很多限制,为了解决这些限制,在上述代码中添加 PrepareContainerForItemOverride 方法。最后需要升级GridViewEx 控件自带的样式,使其支持设备重定向。

更加适应手持设备

在GridViewEx控件中添加新的PreparingContainerForItem 事件,该事件的参数即包含数据对象,也包含UI 容器,因此可根据需求设置UI属性,代码如下:

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

在多设备中具有良好用户体验

?为了适应多种设备,需要生成自适应布局。本文中主要通过修改内容项的尺寸来实现该功能。创建了Bound ,Unbound以及Grouped 示例文件,Grouped 显示单个GridView控件,因此在移动端能够修改Tile的尺寸及边框。

Bound 和Unbound 示例是由2个GridView控件组成,小屏幕中显的内容较多,无法显示更多的细节性的内容,因此使用Pivot控件保证同一时间只显示一个GridView控件,并支持GridView之间切换。

代码如下:

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

GridViewEx 和GridView 中绑定代码如下:

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

总结

自定义GridViewEx控件扩展了GridView控件,丰富了功能,并新增适应UWP平台App的开发。

示例图片:

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

原文:http://powertoolsteam.iteye.com/blog/2252463


【说明】本文章由站长整理发布,文章内容不代表本站观点,如文中有侵权行为,请与本站客服联系(QQ:254677821)!

相关教程推荐

其他课程推荐