• 重新想象 Windows 8 Store Apps (12) 控件之 GridView 特性: 拖动项, 项尺寸可变, 分组显示


    [源码下载]


    重新想象 Windows 8 Store Apps (12) - 控件之 GridView 特性: 拖动项, 项尺寸可变, 分组显示



    作者:webabcd


    介绍
    重新想象 Windows 8 Store Apps 之 GridView

    • 拖动项 - 在 GridView 内拖动 item 以对 item 排序, 拖动 item 到 GridView 外的指定位置以删除 item
    • 项尺寸可变 - 指定 GirdView 中每个 item 所占尺寸
    • 分组显示 - 分组显示集合数据



    示例
    1、演示如何在 GridView 内拖动 item 以对 item 排序,以及如何拖动 item 到 GridView 外的指定位置以删除 item
    GridView/DragItem.xaml

    <Page
        x:Class="XamlDemo.Controls.GridView.DragItem"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:XamlDemo.Controls.GridView"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Page.Resources>
            <DataTemplate x:Key="ItemTemplate">
                <StackPanel Orientation="Vertical">
                    <TextBlock TextWrapping="Wrap" FontSize="14.667" Text="{Binding Name}" HorizontalAlignment="Left" />
                    <TextBlock TextWrapping="Wrap" FontSize="14.667" Text="{Binding Age}" HorizontalAlignment="Left"/>
                </StackPanel>
            </DataTemplate>
            <Style x:Key="ItemContainerStyle"  TargetType="GridViewItem">
                <Setter Property="Width" Value="292" />
                <Setter Property="Height" Value="80" />
                <!--
                    即使将 Margin 设置为“0”,也无法去掉 item 之间的 margin
                    如果想要去掉 item 之间的 margin,请将此 Margin 属性设置为“-4”
                -->
                <Setter Property="Margin" Value="0" />
                <Setter Property="Background" Value="Blue" />
            </Style>
            <ItemsPanelTemplate x:Key="ItemsPanel">
                <!--
                    注:WrapGrid 继承了 VirtualizingPanel,而 VariableSizedWrapGrid 并未继承 VirtualizingPanel
                -->
                <WrapGrid MaximumRowsOrColumns="3" Orientation="Vertical" VerticalChildrenAlignment="Top" HorizontalChildrenAlignment="Left" />
            </ItemsPanelTemplate>
        </Page.Resources>
    
        <Grid Background="Transparent">
            <StackPanel Margin="120 0 0 0">
    
                <TextBlock Name="lblMsg" FontSize="14.667" Text="通过拖动 GirdView 中的 Item 进行排序" />
    
                <GridView x:Name="gridView" VerticalAlignment="Top" Margin="0 10 10 0" BorderThickness="1" BorderBrush="Red" Background="LightBlue"
                          ItemTemplate="{StaticResource ItemTemplate}"
                          ItemContainerStyle="{StaticResource ItemContainerStyle}"
                          ItemsPanel="{StaticResource ItemsPanel}"
                          IsSwipeEnabled="True" IsItemClickEnabled="True"
                          CanDragItems="True" CanReorderItems="True" AllowDrop="True" 
                          DragItemsStarting="gridView_DragItemsStarting_1" />
    
                <!--拖动 item 到此处以删除 item-->
                <Grid Name="gridDelete" Margin="0 10 0 0" AllowDrop="True" Drop="gridDelete_Drop_1" DragEnter="gridDelete_DragEnter_1" DragLeave="gridDelete_DragLeave_1" DragOver="gridDelete_DragOver_1">
                    <Rectangle Width="300" Height="100" StrokeThickness="1" StrokeDashArray="2" Stroke="Red" Fill="Blue" />
                    <TextBlock FontSize="26.667" Text="拖动到此处以删除" TextAlignment="Center" VerticalAlignment="Center" />
                </Grid>
                
            </StackPanel>
        </Grid>
    </Page>

    GridView/DragItem.xaml.cs

    /*
     * 演示如何在 GridView 内拖动 item 以对 item 排序,以及如何拖动 item 到 GridView 外的指定位置以删除 item
     * 
     * GridView - 网格控件
     *     CanDragItems - item 是否可被拖动
     *     CanReorderItems - 是否可通过拖动 item 来排序
     *     AllowDrop - 是否可在 GridView 中 drop
     *     DragItemsStarting - item 开始被拖动时所触发的事件(事件参数 DragItemsStartingEventArgs)
     *      
     * DragItemsStartingEventArgs
     *     Items - 被拖动的 items 集合
     *     Cancel - 是否取消拖动操作
     *     Data - 一个 DataPackage 类型的对象,用于传递数据(与 DataPackage 在剪切板和 Share Contract 中的作用一样)
     *     
     * 
     * 注:
     * drag-drop 间传递数据,clipboard 间传递数据,Share Contract 间传递数据,以及其他场景的数据传递均可通过 DataPackage 类型的对象来完成
     * 本例没有通过 DataPackage 来传递数据(太麻烦),而是通过一个私有字段来传递数据(比较简单)
     */
    
    using System.Collections.ObjectModel;
    using Windows.UI.Xaml.Controls;
    using System.Linq;
    using XamlDemo.Model;
    using Windows.UI.Xaml;
    using System.Diagnostics;
    
    namespace XamlDemo.Controls.GridView
    {
        public sealed partial class DragItem : Page
        {
            // 数据源
            private ObservableCollection<Employee> _dataSource;
            // 拖动中的 Employee 对象
            private Employee _draggingEmployee;
    
            public DragItem()
            {
                this.InitializeComponent();
                
                // 绑定数据
                _dataSource = new ObservableCollection<Employee>(TestData.GetEmployees());
                gridView.ItemsSource = _dataSource;
    
                // GridView 中的 items 发生变化时触发的事件
                gridView.ItemContainerGenerator.ItemsChanged += ItemContainerGenerator_ItemsChanged;
            }
    
            void ItemContainerGenerator_ItemsChanged(object sender, Windows.UI.Xaml.Controls.Primitives.ItemsChangedEventArgs e)
            {
                if (e.OldPosition.Index > -1)
                {
                    // 在 GridView 中 drop 了 item,且排序发生了变化
    
                    var oldIndex = _dataSource.IndexOf(_draggingEmployee); // 被拖动的 Employee 对象的原位置
                    var newIndex = e.Position.Index + e.Position.Offset; // 被拖动的 Employee 对象的新位置
    
                    // 修改数据源
                    _dataSource.Move(oldIndex, newIndex);
    
                    _draggingEmployee = null;
                }
                
            }
    
            // GridView 中的 item 开始被拖动时
            private void gridView_DragItemsStarting_1(object sender, DragItemsStartingEventArgs e)
            {
                _draggingEmployee = e.Items.First() as Employee;
            }
    
    
            // GridView 中的 item 被 drop 到了指定的位置后
            private void gridDelete_Drop_1(object sender, DragEventArgs e)
            {
                // 从数据源中删除指定的 Employee 对象
                _dataSource.Remove(_draggingEmployee);
                _draggingEmployee = null;
    
                // 在 gridDelete 放下了拖动项
                Debug.WriteLine("Drop");
            }
    
            private void gridDelete_DragEnter_1(object sender, DragEventArgs e)
            {
                // 拖动项被拖进 gridDelete 了
                Debug.WriteLine("DragEnter");
            }
    
            private void gridDelete_DragLeave_1(object sender, DragEventArgs e)
            {
                // 拖动项被拖出 gridDelete 了
                Debug.WriteLine("DragLeave");
            }
    
            private void gridDelete_DragOver_1(object sender, DragEventArgs e)
            {
                // 拖动项在 gridDelete 上面拖动着
                Debug.WriteLine("DragOver");
            }
        }
    }


    2、演示如何指定 GirdView 中每个 item 所占尺寸
    GridView/ColorModel.cs

    using Windows.UI.Xaml.Media;
    
    namespace XamlDemo.Controls.GridView
    {
        /// <summary>
        /// 用于绑定到 VariableSized.xaml 中的 GridView 的数据实体模型
        /// </summary>
        class ColorModel
        {
            public string ColorName { get; set; }
            public SolidColorBrush ColorValue { get; set; }
    
            // 此对象所占的网格的列合并数
            public int ColSpan { get; set; }
            // 此对象所占的网格的行合并数
            public int RowSpan { get; set; }
        }
    }

    GridView/MyGridView.cs

    /*
     * 此控件可以指定 GridView 的每个 item 所占网格的列合并数和行合并数
     */
    
    using System;
    using System.Diagnostics;
    
    namespace XamlDemo.Controls.GridView
    {
        public class MyGridView : Windows.UI.Xaml.Controls.GridView
        {
            protected override void PrepareContainerForItemOverride(Windows.UI.Xaml.DependencyObject element, object item)
            {
                try
                {
                    // 指定 VariableSizedWrapGrid 的 ColumnSpan 和 RowSpan
    
                    dynamic dynamicItem = item;
                    element.SetValue(Windows.UI.Xaml.Controls.VariableSizedWrapGrid.ColumnSpanProperty, dynamicItem.ColSpan);
                    element.SetValue(Windows.UI.Xaml.Controls.VariableSizedWrapGrid.RowSpanProperty, dynamicItem.RowSpan);
                }
                catch(Exception ex)
                {
                    // 当有异常情况发生时(比如:item 没有 ColSpan 属性或 RowSpan 属性)
    
                    Debug.WriteLine(ex.ToString());
    
                    element.SetValue(Windows.UI.Xaml.Controls.VariableSizedWrapGrid.ColumnSpanProperty, 1);
                    element.SetValue(Windows.UI.Xaml.Controls.VariableSizedWrapGrid.RowSpanProperty, 1);
                }
                finally
                {
                    base.PrepareContainerForItemOverride(element, item);
                }
            }
        }
    }

    GridView/VariableSized.xaml

    <Page
        x:Class="XamlDemo.Controls.GridView.VariableSized"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:XamlDemo.Controls.GridView"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Page.Resources>
            <DataTemplate x:Key="ItemTemplate">
                <Grid Background="{Binding ColorValue}">
                    <Grid Background="Black" VerticalAlignment="Top" HorizontalAlignment="Stretch" Opacity="0.7">
                        <TextBlock Text="{Binding ColorName}" />
                    </Grid>
                </Grid>
            </DataTemplate>
            <Style x:Key="ItemContainerStyle" TargetType="GridViewItem">
                <Setter Property="VerticalContentAlignment" Value="Stretch" />
                <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                <!--
                    即使将 Margin 设置为“0”,也无法去掉 item 之间的 margin
                    如果想要去掉 item 之间的 margin,请将此 Margin 属性设置为“-4”
                -->
                <Setter Property="Margin" Value="-4" />
            </Style>
            <ItemsPanelTemplate x:Key="ItemsPanel">
                <!--
                    注:WrapGrid 继承了 VirtualizingPanel,而 VariableSizedWrapGrid 并未继承 VirtualizingPanel
                
                    ItemWidth, ItemHeight - 每个网格的宽和高
                    ColumnSpan, RowSpan - item 所在网格的列合并数和行合并数,本例在后台指定了这两个属性,参见 MyGridView.cs
                -->
                <VariableSizedWrapGrid MaximumRowsOrColumns="4" Orientation="Vertical" ItemWidth="100" ItemHeight="100" Height="400" />
            </ItemsPanelTemplate>
    
        </Page.Resources>
    
        <Grid Background="Transparent">
            <StackPanel Margin="120 0 0 0">
    
                <!--
                    使用 MyGridView 控件,其重写了 GridView 的 PrepareContainerForItemOverride() 方法,详见 MyGridView.cs
                -->
                <local:MyGridView x:Name="gridView" Height="400" VerticalAlignment="Top" Margin="0 10 10 0" Background="Yellow"
                                  ItemTemplate="{StaticResource ItemTemplate}"
                                  ItemContainerStyle="{StaticResource ItemContainerStyle}"
                                  ItemsPanel="{StaticResource ItemsPanel}" 
                                  IsItemClickEnabled="False" IsSwipeEnabled="False" SelectionMode="None"
                                  ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto">
                </local:MyGridView>
    
            </StackPanel>
        </Grid>
    </Page>

    GridView/VariableSized.xaml.cs

    /*
     * 演示如何指定 GirdView 中每个 item 所占尺寸
     * GridView 是一个网格控件,这里所谓的每个 item 所占尺寸,其本质上就是 item 所在网格的列合并数和行合并数
     * 
     * 要实现此需求的话:
     * 1、必须使用 VariableSizedWrapGrid,具体见 VariableSized.xaml
     * 2、需要重写 GridView 的 PrepareContainerForItemOverride() 方法,具体见 MyGridView.cs
     */
    
    using System.Reflection;
    using System.Linq;
    using System.Collections.Generic;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;
    using System;
    using Windows.UI;
    
    namespace XamlDemo.Controls.GridView
    {
        public sealed partial class VariableSized : Page
        {
            public VariableSized()
            {
                this.InitializeComponent();
    
                BindData();
            }
    
            private void BindData()
            {
                Random random = new Random();
    
                // 获取 Windows.UI.Colors 的全部数据
                List<ColorModel> colors = typeof(Colors)  // typeof 在 System.Reflection 命名空间下
                    .GetRuntimeProperties()
                    .Select(c => new ColorModel
                    {
                        ColorName = c.Name,
                        ColorValue = new SolidColorBrush((Color)c.GetValue(null)),
                        ColSpan = random.Next(1, 3), // 此对象所占网格的列合并数
                        RowSpan = random.Next(1, 3) // 此对象所占网格的行合并数
                    })
                    .ToList();
    
                // 绑定数据
                gridView.ItemsSource = colors;
            }
        }
    }


    3、演示如何分组显示集合数据(关于分组的示例会和之后的 SemanticZoom 一起写)
    GridView/Group.xaml

    <Page
        x:Class="XamlDemo.Controls.GridView.Group"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:XamlDemo.Controls.GridView"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="Transparent">
            <StackPanel Margin="120 0 0 0">
    
                <TextBlock Name="lblMsg" FontSize="14.667">
                    <Run>关于 GridView 的分组显示请参见本 app 的索引页 Index.xaml 和 Index.xaml.cs</Run>
                    <LineBreak />
                    <Run>分组的功能来源于 ItemsControl(GridView, ListView, FlipView, ListBox 等均继承了 ItemsControl)</Run>
                </TextBlock>
    
            </StackPanel>
        </Grid>
    </Page>



    OK
    [源码下载]

  • 相关阅读:
    python写泰勒展开式
    8.QR分解的python实现
    7.Bolzmann机解决旅行商问题
    6.BP神经网络的python实现
    5.梯度寻优
    4.推荐系统
    4.决策树的探赜索隐
    BZOJ 1251 序列终结者
    BZOJ 3223 文艺平衡树 [codevs3303翻转区间]
    BZOJ 3224 普通平衡树
  • 原文地址:https://www.cnblogs.com/webabcd/p/2965362.html
Copyright © 2020-2023  润新知