zoukankan      html  css  js  c++  java
  • 背水一战 Windows 10 (52)

    [源码下载]


    背水一战 Windows 10 (52) - 控件(集合类): ItemsControl - 自定义 ItemsControl, 自定义 ContentPresenter



    作者:webabcd


    介绍
    背水一战 Windows 10 之 控件(集合类 - ItemsControl)

    • 自定义 ItemsControl(自定义 GirdView 使其每个 item 占用不同大小的空间)
    • 自定义 ContentPresenter 实现类似 GridViewItemPresenter 和 ListViewItemPresenter 的效果



    示例
    1、自定义 ItemsControl(自定义 GirdView 使其每个 item 占用不同大小的空间)
    Controls/CollectionControl/ItemsControlDemo/MyItemsControlDemo.xaml

    <Page
        x:Class="Windows10.Controls.CollectionControl.ItemsControlDemo.MyItemsControlDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:Windows10.Controls.CollectionControl.ItemsControlDemo"
        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" 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" />
                <Setter Property="Margin" Value="0" />
                <Setter Property="Padding" Value="0" />
            </Style>
            <ItemsPanelTemplate x:Key="ItemsPanel">
                <VariableSizedWrapGrid MaximumRowsOrColumns="8" Orientation="Horizontal" ItemWidth="100" ItemHeight="100"  />
            </ItemsPanelTemplate>
    
        </Page.Resources>
    
        <Grid Background="Transparent" Margin="10 0 10 10">
            <!--
                使用 MyGridView 控件,其重写了 GridView 的 PrepareContainerForItemOverride() 方法,详见 MyGridView.cs
            -->
            <local:MyGridView x:Name="gridView" Width="812" VerticalAlignment="Top" HorizontalAlignment="Left"
                              ItemTemplate="{StaticResource ItemTemplate}"
                              ItemContainerStyle="{StaticResource ItemContainerStyle}"
                              ItemsPanel="{StaticResource ItemsPanel}" 
                              IsItemClickEnabled="False" 
                              SelectionMode="None">
            </local:MyGridView>
        </Grid>
    </Page>

    Controls/CollectionControl/ItemsControlDemo/MyItemsControlDemo.xaml.cs

    /*
     * ItemsControl - 集合控件(继承自 Control, 请参见 /Controls/BaseControl/ControlDemo/)
     *     protected virtual void PrepareContainerForItemOverride(DependencyObject element, object item); - 为 item 准备 container 时
     *         element - item 的 container
     *         item - item
     *         
     * 
     * 本例用于演示如何使 GirdView 中的每个 item 占用不同大小的空间
     * 1、布局控件要使用 VariableSizedWrapGrid(利用其 RowSpan 和 ColumnSpan 来实现 item 占用不同大小的空间),需要注意的是其并非是虚拟化布局控件
     * 2、自定义 GridView,并重写 ItemsControl 的 protected override void PrepareContainerForItemOverride(DependencyObject element, object item) 方法
     *    然后设置每个 item 的 VariableSizedWrapGrid.RowSpan 和 VariableSizedWrapGrid.ColumnSpan
     */
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Windows.UI;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;
    using System.Reflection;
    
    namespace Windows10.Controls.CollectionControl.ItemsControlDemo
    {
        public sealed partial class MyItemsControlDemo : Page
        {
            public MyItemsControlDemo()
            {
                this.InitializeComponent();
       
                BindData();
            }
    
            private void BindData()
            {
                Random random = new Random();
    
                // 获取 Windows.UI.Colors 的全部数据
                Type type = typeof(Colors);
                List<ColorModel> colors = type.GetRuntimeProperties() // GetRuntimeProperties() 在 System.Reflection 命名空间下
                    .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;
            }
        }
    
    
        /// <summary>
        /// 用于数据绑定的对象
        /// </summary>
        public class ColorModel
        {
            public string ColorName { get; set; }
            public SolidColorBrush ColorValue { get; set; }
    
            // 此对象所占的网格的列合并数
            public int ColSpan { get; set; }
            // 此对象所占的网格的行合并数
            public int RowSpan { get; set; }
        }
    
    
        /// <summary>
        /// 自定义 GridView,重写 ItemsControl 的 protected override void PrepareContainerForItemOverride(DependencyObject element, object item) 方法
        /// 用于指定 GridView 的每个 item 所占网格的列合并数和行合并数
        /// </summary>
        public class MyGridView : GridView
        {
            protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
            {
                try
                {
                    // 设置每个 item 的 VariableSizedWrapGrid.RowSpan 和 VariableSizedWrapGrid.ColumnSpan, 从而实现每个 item 占用不同大小的空间
                    // 仅为演示用,由于这里的 ColSpan 和 RowSpan 都是随机计算的,所以可能会出现空白空间
    
                    dynamic dynamicItem = item;
                    element.SetValue(VariableSizedWrapGrid.ColumnSpanProperty, dynamicItem.ColSpan);
                    element.SetValue(VariableSizedWrapGrid.RowSpanProperty, dynamicItem.RowSpan);
                }
                catch (Exception ex)
                {
                    var ignore = ex;
    
                    // 当有异常情况发生时(比如:item 没有 ColSpan 属性或 RowSpan 属性)
    
                    element.SetValue(VariableSizedWrapGrid.ColumnSpanProperty, 1);
                    element.SetValue(VariableSizedWrapGrid.RowSpanProperty, 1);
                }
                finally
                {
                    base.PrepareContainerForItemOverride(element, item);
                }
            }
        }
    }


    2、自定义 ContentPresenter 实现类似 GridViewItemPresenter 和 ListViewItemPresenter 的效果
    Controls/CollectionControl/ItemsControlDemo/MyItemPresenter.cs

    /*
     * 自定义 ContentPresenter 实现类似 GridViewItemPresenter 和 ListViewItemPresenter 的效果
     */
    
    using System;
    using Windows.Foundation;
    using Windows.UI;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Media.Animation;
    using Windows.UI.Xaml.Shapes;
    
    namespace Windows10.Controls.CollectionControl.ItemsControlDemo
    {
        class MyItemPresenter : ContentPresenter
        {
            Panel _container = null; // item 的容器(即在 DataTemplate 中定义的根元素,在示例 MyItemPresenterDemo.xaml 中用的是 Grid)
            Rectangle _pointerOverBorder = null; // 鼠标经过 item 时覆盖在 item 上的 rectangle
            Rectangle _focusVisual = null; // 选中 item 时覆盖在 item 上的 rectangle
    
            Storyboard _pointerDownStoryboard = null; // 鼠标按下时的动画
            Storyboard _pointerUpStoryboard = null; // 鼠标抬起时的动画
    
            public MyItemPresenter()
                : base()
            {
                base.Margin = new Thickness(10);
            }
    
            // override OnApplyTemplate() - 应用控件模板时调用
            protected override void OnApplyTemplate()
            {
                base.OnApplyTemplate();
    
                _container = (Panel)VisualTreeHelper.GetChild(this, 0);
            }
    
            // override GoToElementStateCore() - VisualState 转换时调用(此方法仅在自定义 ContentPresenter 并将其应用于 GridView 或 ListView 的 ItemContainerStyle 时才会被调用)
            //     stateName - VisualState 的名字
            //     useTransitions - 是否使用 VisualTransition 过渡效果
            protected override bool GoToElementStateCore(string stateName, bool useTransitions)
            {
                base.GoToElementStateCore(stateName, useTransitions);
    
                switch (stateName)
                {
                    // 正常状态
                    case "Normal":
                        HidePointerOverVisuals();
                        HideFocusVisuals();
                        if (useTransitions)
                        {
                            StopPointerDownAnimation();
                        }
                        break;
    
                    // 选中状态
                    case "Selected":
                    case "PointerFocused":
                        ShowFocusVisuals();
                        if (useTransitions)
                        {
                            StopPointerDownAnimation();
                        }
                        break;
    
                    // 取消选中状态
                    case "Unfocused":
                        HideFocusVisuals();
                        break;
    
                    // 鼠标经过状态
                    case "PointerOver":
                        ShowPointerOverVisuals();
                        if (useTransitions)
                        {
                            StopPointerDownAnimation();
                        }
                        break;
    
                    // 鼠标点击状态
                    case "Pressed":
                    case "PressedSelected":
                        if (useTransitions)
                        {
                            StartPointerDownAnimation();
                        }
                        break;
    
                    default: break;
                }
    
                return true;
            }
    
            private void StartPointerDownAnimation()
            {
                if (_pointerDownStoryboard == null)
                    CreatePointerDownStoryboard();
    
                _pointerDownStoryboard.Begin();
            }
    
            private void StopPointerDownAnimation()
            {
                if (_pointerUpStoryboard == null)
                    CreatePointerUpStoryboard();
    
                _pointerUpStoryboard.Begin();
            }
    
            private void ShowFocusVisuals()
            {
                if (!FocusElementsAreCreated())
                    CreateFocusElements();
    
                _focusVisual.Opacity = 1;
            }
    
            private void HideFocusVisuals()
            {
                if (FocusElementsAreCreated())
                    _focusVisual.Opacity = 0;
            }
    
            private void ShowPointerOverVisuals()
            {
                if (!PointerOverElementsAreCreated())
                    CreatePointerOverElements();
    
                _pointerOverBorder.Opacity = 1;
            }
    
            private void HidePointerOverVisuals()
            {
                if (PointerOverElementsAreCreated())
                    _pointerOverBorder.Opacity = 0;
            }
    
            private void CreatePointerDownStoryboard()
            {
                /*
                 * 用这种方式为 item 实现鼠标按下的效果会报错(Attempted to read or write protected memory. This is often an indication that other memory is corrupt.),不知道为什么
                 * PointerDownThemeAnimation pointerDownAnimation = new PointerDownThemeAnimation();
                 * Storyboard.SetTarget(pointerDownAnimation, _container);
                 * Storyboard pointerDownStoryboard = new Storyboard();
                 * pointerDownStoryboard.Children.Add(pointerDownAnimation);
                 */
    
                DoubleAnimation da1 = new DoubleAnimation()
                {
                    To = 0.9,
                    Duration = TimeSpan.FromMilliseconds(100)
                };
                DoubleAnimation da2 = new DoubleAnimation()
                {
                    To = 0.9,
                    Duration = TimeSpan.FromMilliseconds(100)
                };
                Storyboard.SetTarget(da1, _container);
                Storyboard.SetTargetProperty(da1, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)");
                Storyboard.SetTarget(da2, _container);
                Storyboard.SetTargetProperty(da2, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)");
                if (!(_container.RenderTransform is TransformGroup))
                {
                    TransformGroup Group = new TransformGroup();
                    Group.Children.Add(new ScaleTransform());
                    _container.RenderTransform = Group;
                    _container.RenderTransformOrigin = new Point(0.5, 0.5);
                }
    
                _pointerDownStoryboard = new Storyboard();
                _pointerDownStoryboard.Children.Add(da1);
                _pointerDownStoryboard.Children.Add(da2);
                _pointerDownStoryboard.Begin();
            }
    
            private void CreatePointerUpStoryboard()
            {
                DoubleAnimation da1 = new DoubleAnimation()
                {
                    To = 1,
                    Duration = TimeSpan.FromMilliseconds(100)
                };
                DoubleAnimation da2 = new DoubleAnimation()
                {
                    To = 1,
                    Duration = TimeSpan.FromMilliseconds(100)
                };
                Storyboard.SetTarget(da1, _container);
                Storyboard.SetTargetProperty(da1, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)");
                Storyboard.SetTarget(da2, _container);
                Storyboard.SetTargetProperty(da2, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)");
                if (!(_container.RenderTransform is TransformGroup))
                {
                    TransformGroup Group = new TransformGroup();
                    Group.Children.Add(new ScaleTransform());
                    _container.RenderTransform = Group;
                    _container.RenderTransformOrigin = new Point(0.5, 0.5);
                }
    
                _pointerUpStoryboard = new Storyboard();
                _pointerUpStoryboard.Children.Add(da1);
                _pointerUpStoryboard.Children.Add(da2);
                _pointerUpStoryboard.Begin();
            }
    
            private void CreatePointerOverElements()
            {
                _pointerOverBorder = new Rectangle();
                _pointerOverBorder.IsHitTestVisible = false;
                _pointerOverBorder.Opacity = 0;
                // 这里把颜色写死了,仅为演示用,实际写的时候要摘出来写成依赖属性
                _pointerOverBorder.Fill = new SolidColorBrush(Color.FromArgb(0x50, 0x50, 0x50, 0x50));
    
                _container.Children.Insert(_container.Children.Count, _pointerOverBorder);
            }
    
            private void CreateFocusElements()
            {
                _focusVisual = new Rectangle();
                _focusVisual.IsHitTestVisible = false;
                _focusVisual.Height = 10;
                _focusVisual.VerticalAlignment = VerticalAlignment.Bottom;
                // 这里把颜色写死了,仅为演示用,实际写的时候要摘出来写成依赖属性
                _focusVisual.Fill = new SolidColorBrush(Color.FromArgb(0xff, 0xff, 0x0, 0x0));
    
                _container.Children.Insert(0, _focusVisual);
            }
    
            private bool FocusElementsAreCreated()
            {
                return _focusVisual != null;
            }
    
            private bool PointerOverElementsAreCreated()
            {
                return _pointerOverBorder != null;
            }
        }
    }

    Controls/CollectionControl/ItemsControlDemo/MyItemPresenterDemo.xaml

    <Page
        x:Class="Windows10.Controls.CollectionControl.ItemsControlDemo.MyItemPresenterDemo"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:Windows10.Controls.CollectionControl.ItemsControlDemo"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Page.Resources>
            <Style x:Key="MyGridViewItemPresenterTemplate" TargetType="GridViewItem">
                <Setter Property="Background" Value="Transparent"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="GridViewItem">
                            <!--
                                自定义 ContentPresenter 实现类似 GridViewItemPresenter 和 ListViewItemPresenter 的效果
                            -->
                            <local:MyItemPresenter />
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Page.Resources>
    
        <Grid Background="Transparent">
            <GridView x:Name="gridView" SelectionMode="Single" Margin="10 0 10 10" 
                      ItemContainerStyle="{StaticResource MyGridViewItemPresenterTemplate}">
                <GridView.ItemTemplate>
                    <DataTemplate>
                        <Grid Height="100" Width="100" Background="Blue">
                            <TextBlock x:Name="lblName" Text="{Binding Name}" Foreground="Yellow" />
                        </Grid>
                    </DataTemplate>
                </GridView.ItemTemplate>
            </GridView>
        </Grid>
    </Page>

    Controls/CollectionControl/ItemsControlDemo/MyItemPresenterDemo.xaml.cs

    /*
     * 本例用于演示如何自定义 ContentPresenter 实现类似 GridViewItemPresenter 和 ListViewItemPresenter 的效果
     */
    
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    using Windows10.Common;
    
    namespace Windows10.Controls.CollectionControl.ItemsControlDemo
    {
        public sealed partial class MyItemPresenterDemo : Page
        {
            public MyItemPresenterDemo()
            {
                this.InitializeComponent();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                gridView.ItemsSource = TestData.GetEmployees();
            }
        }
    }



    OK
    [源码下载]

  • 相关阅读:
    web前端攻城狮都来晒一晒你的收藏夹吧
    淘宝前端技术系列课程分享
    HTML5编程实战之二:用动画的形式切换图片
    HTML5编程实战之一:HTML5时钟
    【转】chrome developer tool 调试技巧
    Android 云端推送C2DM php实现向终端推送消息
    简单的泰国IP判断
    [翻译]延迟着色(Shawn Hargreaves)〔1〕
    [翻译]延迟着色(2)
    [3D基础]投影矩阵的推导(1)
  • 原文地址:https://www.cnblogs.com/webabcd/p/6991305.html
Copyright © 2011-2022 走看看