概述

UWP Community Toolkit Extensions 中有一个为 ListView 提供的扩展 - ListViewExtensions,本篇我们结合代码详细讲解 ListView Extensions 的实现。

ListViewExtensions 为每一种继承了 ListViewBase 类的控件提供了一种轻量级的方式来扩展它的附加属性。目前扩展的附加属性有 AlternateColor、AlternateItemTemplate 和 StretchItemContainerDirection;需要注意的是,扩展使用 ContainerContentChanging 事件来保证工作,如果控件的 ItemsPanel 被设置为 ItemsStackPanel 或 ItemsWrapGrid,那么扩展将不能正常工作。另外 StretchItemContainerDirection 有 Horizontal、Vertical 和 Both 三个选项。我们来看官方示例截图:

Source: https://github.com/Microsoft/UWPCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI/Extensions/ListViewBase

Doc: https://docs.microsoft.com/zh-cn/windows/uwpcommunitytoolkit/extensions/listviewextensions

Namespace: Microsoft.Toolkit.Uwp.UI.Extensions; Nuget: Microsoft.Toolkit.Uwp.UI;

开发过程

代码分析

首先来看 ListView Extension - ListViewBase 的类结构:

  • ListViewBase.Data.cs -  ListViewBase 部分类中 StretchDirection 的定义,枚举类型,有 Horizontal,Vertical 和 Both 三种类型;
  • ListViewBase.Properties.cs - 已标记为 Obsolete,被 ListViewExtensions 替代;
  • ListViewBase.cs - ListViewBase 部分类中负责事件响应处理逻辑的定义;
  • ListViewBaseExtensions.cs - 已标记为 Obsolete,被 ListViewBase 替代;
  • ListViewExtensions.cs - ListView Extension 的依赖属性定义和事件处理逻辑定义;
  • StretchDirection.cs - StretchDirection 的定义,枚举类型,有 Horizontal,Vertical 和 Both 三种类型;

首先来看 ListViewBase.cs 类,类中定义了 4 个PropertyChanged 事件处理方法:

  • OnCommandPropertyChanged(sender, args) - 重新为 listViewBase 绑定 OnItemClicked 事件;
  • OnAlternateColorPropertyChanged(sender, args) - 重新为 listViewBase 绑定 ColorContainerContentChanging 事件;
  • OnAlternateItemTemplatePropertyChanged(sender, args) - 重新为 listViewBase 绑定 ItemTemplateContainerContentChanging 事件;
  • ItemTemplateContainerContentChanging(sender, args) -  重新为 listViewBase 绑定 StretchItemContainerDirectionChanging 事件;

主要看一下后面三个事件的处理方法:

① ColorContainerContentChanging(sender, args):

获取当前 sender 在 container 中的索引,根据索引的奇偶数来判断,偶数则设置背景为 AlternateColor,奇数则设置背景为空;

private static void ColorContainerContentChanging(Windows.UI.Xaml.Controls.ListViewBase sender, ContainerContentChangingEventArgs args)
{
    var itemContainer = args.ItemContainer as SelectorItem;
    var itemIndex = sender.IndexFromContainer(itemContainer);

     == )
    {
        itemContainer.Background = GetAlternateColor(sender);
    }
    else
    {
        itemContainer.Background = null;
    }
}

② ItemTemplateContainerContentChanging(sender, args):

同样获取当前 sender 在 container 中的索引,根据索引的奇偶数来判断,偶数则设置内容模板为 AlternateItemTemplate,奇数则设置为 sender 的元素模板;

private static void ItemTemplateContainerContentChanging(Windows.UI.Xaml.Controls.ListViewBase sender, ContainerContentChangingEventArgs args)
{
    var itemContainer = args.ItemContainer as SelectorItem;
    var itemIndex = sender.IndexFromContainer(itemContainer);

     == )
    {
        itemContainer.ContentTemplate = GetAlternateItemTemplate(sender);
    }
    else
    {
        itemContainer.ContentTemplate = sender.ItemTemplate;
    }
}

以上两个方法,主要处理就是自定义 ListView 奇偶数元素不同的背景色和元素模板;

③ StretchItemContainerDirectionChanging(sender, args):

获取当前 sender 的 stretchDirection,如果为 Vertical 或 Both,则 container 的纵向内容对齐设置为 Stretch;如果为 Horizontal 或 Both,则 container 的横向内容对齐设置为 Stretch;

private static void StretchItemContainerDirectionChanging(Windows.UI.Xaml.Controls.ListViewBase sender, ContainerContentChangingEventArgs args)
{
    var itemContainer = args.ItemContainer as SelectorItem;
    var stretchDirection = GetStretchItemContainerDirection(sender);

    if (stretchDirection == StretchDirection.Vertical || stretchDirection == StretchDirection.Both)
    {
        itemContainer.VerticalContentAlignment = VerticalAlignment.Stretch;
    }

    if (stretchDirection == StretchDirection.Horizontal || stretchDirection == StretchDirection.Both)
    {
        itemContainer.HorizontalContentAlignment = HorizontalAlignment.Stretch;
    }
}

接下来看 ListViewExtensions 类,首先来看类中定义的依赖属性:

  • AlternateColor - ListView 的备用颜色画刷,改变时触发 OnAlternateColorPropertyChanged 事件;
  • AlternateItemTemplate - ListView 的备用元素模板,改变时触发 OnAlternateItemTemplatePropertyChanged 事件;
  • StretchItemContainerDirection - 拉伸元素容器方向,改变时触发 OnStretchItemContainerDirectionPropertyChanged 事件;

来看这三个事件的处理逻辑:

① OnAlternateColorPropertyChanged(sender, args):

分别重新绑定 ColorContainerContentChanging、ColorItemsVectorChanged 和 OnListViewBaseUnloaded 事件;其中主要处理在 ColorItemsVectorChanged 中;

private static void OnAlternateColorPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
    Windows.UI.Xaml.Controls.ListViewBase listViewBase = sender as Windows.UI.Xaml.Controls.ListViewBase;

    if (listViewBase == null)
    {
        return;
    }

    listViewBase.ContainerContentChanging -= ColorContainerContentChanging;
    listViewBase.Items.VectorChanged -= ColorItemsVectorChanged;
    listViewBase.Unloaded -= OnListViewBaseUnloaded;

    _itemsForList[listViewBase.Items] = listViewBase;
    if (AlternateColorProperty != null)
    {
        listViewBase.ContainerContentChanging += ColorContainerContentChanging;
        listViewBase.Items.VectorChanged += ColorItemsVectorChanged;
        listViewBase.Unloaded += OnListViewBaseUnloaded;
    }
}

ColorItemsVectorChanged(sender, args) 方法对于 ColorContainerContentChanging 方法中未处理的 Insert 和 Remove 场景做处理,获取当前的 ListViewBase,遍历每个元素,为元素容器设置背景,依据是元素的索引;ColorContainerContentChanging 方法的处理同样是根据元素的索引奇偶数来设置背景;

private static void ColorItemsVectorChanged(IObservableVector<object> sender, IVectorChangedEventArgs args)
{
    // If the index is at the end we can ignore
    )) { return; }

    // Only need to handle Inserted and Removed because we'll handle everything else in the
    // ColorContainerContentChanging method
    if ((args.CollectionChange == CollectionChange.ItemInserted) || (args.CollectionChange == CollectionChange.ItemRemoved))
    {
        _itemsForList.TryGetValue(sender, out Windows.UI.Xaml.Controls.ListViewBase listViewBase);
        if (listViewBase == null) { return; }

        int index = (int)args.Index;
        for (int i = index; i < sender.Count; i++)
        {
            var itemContainer = listViewBase.ContainerFromIndex(i) as Control;
            if (itemContainer != null)
            {
                SetItemContainerBackground(listViewBase, itemContainer, i);
            }
        }
    }
}

② OnAlternateItemTemplatePropertyChanged(sender, args):

分别重新绑定 ItemTemplateContainerContentChanging 和 OnListViewBaseUnloaded 事件,处理主要是根据元素的索引的奇偶数,设置元素模板;  

private static void OnAlternateItemTemplatePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
    Windows.UI.Xaml.Controls.ListViewBase listViewBase = sender as Windows.UI.Xaml.Controls.ListViewBase;

    if (listViewBase == null)
    {
        return;
    }

    listViewBase.ContainerContentChanging -= ItemTemplateContainerContentChanging;
    listViewBase.Unloaded -= OnListViewBaseUnloaded;

    if (AlternateItemTemplateProperty != null)
    {
        listViewBase.ContainerContentChanging += ItemTemplateContainerContentChanging;
        listViewBase.Unloaded += OnListViewBaseUnloaded;
    }
}

③ OnStretchItemContainerDirectionPropertyChanged(sender, args):

分别重新绑定 StretchItemContainerDirectionChanging 和 OnListViewBaseUnloaded 事件,处理是获取当前 itemContainer 的 stretchDirection,如果为 Vertical 或 Both,则 container 的纵向内容对齐设置为 Stretch;如果为 Horizontal 或 Both,则 container 的横向内容对齐设置为 Stretch;

private static void OnStretchItemContainerDirectionPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
    Windows.UI.Xaml.Controls.ListViewBase listViewBase = sender as Windows.UI.Xaml.Controls.ListViewBase;

    if (listViewBase == null)
    {
        return;
    }

    listViewBase.ContainerContentChanging -= StretchItemContainerDirectionChanging;
    listViewBase.Unloaded -= OnListViewBaseUnloaded;

    if (StretchItemContainerDirectionProperty != null)
    {
        listViewBase.ContainerContentChanging += StretchItemContainerDirectionChanging;
        listViewBase.Unloaded += OnListViewBaseUnloaded;
    }
}

调用示例

我们把 AlternateColor 设置为浅灰色,AlternateItemTemplate 中的文字前景色设置为橙色,StretchItemContainerDirection 设置为 Both;可以看到运行显示中 test01 test03 这些元素的显示和设置是一致的。

<Page.Resources>
    <DataTemplate x:Name="NormalTemplate">
        <TextBlock Text="{Binding Title}" Foreground="Green"></TextBlock>
    </DataTemplate>
    <DataTemplate x:Name="AlternateTemplate">
        <TextBlock Text="{Binding Title}" Foreground="Orange"></TextBlock>
    </DataTemplate>
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ListView x:Name="SampleListView" Margin="12"
                    ItemTemplate="{StaticResource NormalTemplate}"
                    extensions:ListViewExtensions.AlternateColor="LightGray"
                    extensions:ListViewExtensions.AlternateItemTemplate="{StaticResource AlternateTemplate}"
                    extensions:ListViewExtensions.StretchItemContainerDirection="Both">
    </ListView>
</Grid>

总结

到这里我们就把 UWP Community Toolkit Extensions 中的 ListViewExtensions 的源代码实现过程和简单的调用示例讲解完成了,希望能对大家更好的理解和使用这个扩展有所帮助。欢迎大家多多交流,谢谢!

最后,再跟大家安利一下 UWPCommunityToolkit 的官方微博:https://weibo.com/u/6506046490大家可以通过微博关注最新动态。

衷心感谢 UWPCommunityToolkit 的作者们杰出的工作,Thank you so much, UWPCommunityToolkit authors!!!

Extensions in UWP Community Toolkit - ListViewExtensions的更多相关文章

  1. Extensions in UWP Community Toolkit - Overview

    概述 UWP Community Toolkit  中有一个 Extensions 的集合,它们可以帮助开发者实现很多基础功能,省去自己造轮子的过程,本篇我们先来看一下 Extensions 的功能都 ...

  2. Extensions in UWP Community Toolkit - FrameworkElement Extensions

    概述 UWP Community Toolkit Extensions 中有一个为FrameworkElement 提供的扩展 - FrameworkElement Extensions,本篇我们结合 ...

  3. Extensions in UWP Community Toolkit - Mouse Cursor

    概述 UWP Community Toolkit Extensions 中有一个为 Mouse 提供的扩展 - Mouse Cursor Extensions,本篇我们结合代码详细讲解 Mouse C ...

  4. Extensions in UWP Community Toolkit - SurfaceDialTextbox

    概述 UWP Community Toolkit Extensions 中有一个为TextBox 提供的 SurfaceDial 扩展 - SurfaceDialTextbox,本篇我们结合代码详细讲 ...

  5. Extensions in UWP Community Toolkit - ViewExtensions

    概述 UWP Community Toolkit Extensions 中有一个为 View 提供的扩展 - View Extensions,本篇我们结合代码详细讲解 View Extensions  ...

  6. Extensions in UWP Community Toolkit - Visual Extensions

    概述 UWP Community Toolkit Extensions 中有一个为可视元素提供的扩展 - VisualExtensions,本篇我们结合代码详细讲解 VisualExtensions ...

  7. Extensions in UWP Community Toolkit - WebViewExtensions

    概述 UWP Community Toolkit Extensions 中有一个为 WebView 提供的扩展 - WebViewExtensions,本篇我们结合代码详细讲解 WebView Ext ...

  8. New UWP Community Toolkit

    概述 UWP Community Toolkit 是一个 UWP App 自定义控件.应用服务和帮助方法的集合,能够很大程度的简化和指引开发者的开发工作,相信广大 UWPer 并不陌生. 下面是截取自 ...

  9. Animations in UWP Community Toolkit - Overview

    概述 UWP Community Toolkit  中有一个 Animations 的集合,它们可以帮助开发者实现很多的动画,本篇我们先来看一下 Animations 的功能都有哪些,再后面会针对每一 ...

随机推荐

  1. 【Python】 垃圾回收机制和gc模块

    垃圾回收机制和gc模块 Py的一个大好处,就是灵活的变量声明和动态变量类型.虽然这使得学习py起来非常方便快捷,但是同时也带来了py在性能上的一些不足.其中相关内存比较主要的一点就是py不会对已经销毁 ...

  2. LeetCode --> 771. Jewels and Stones

    Jewels and Stones You're given strings J representing the types of stones that are jewels, and S rep ...

  3. java各种概念 Core Java总结

    Base: OOA是什么?OOD是什么?OOP是什么?{ oo(object-oriented):基于对象概念,以对象为中心,以类和继承为构造机制,来认识,理解,刻画客观世界和设计,构建相应的软件系统 ...

  4. linux scp 命令

    scp 命令 scp 命令 意思是 secure copy 即安全拷贝,可以把它看做是 cp 命令的高级版,可以跨主机拷贝. 经常用来在局域网内不同主机之间分享文件,或者在本机与远程主机中分享文件. ...

  5. Linux进程间通信-消息队列(mqueue)

    前面两篇文章分解介绍了匿名管道和命名管道方式的进程间通信,本文将介绍Linux消息队列(posix)的通信机制和特点. 1.消息队列 消息队列的实现分为两种,一种为System V的消息队列,一种是P ...

  6. JavaScript(第二十三天)【事件入门】

    JavaScript事件是由访问Web页面的用户引起的一系列操作,例如:用户点击.当用户执行某些操作的时候,再去执行一系列代码.   一.事件介绍 事件一般是用于浏览器和用户操作进行交互.最早是IE和 ...

  7. 利用jmeter做一个简单的性能测试并进行参数化设置

    1.新增一个线程组,并在下面添加基本原件,包括:监听器.http请求默认值和一个事务控制器 在http请求默认值中填写 ip 地址和端口号,协议类型默认为http 2.添加代理服务器,以便之后进行录制 ...

  8. C第九次博客作业--指针

    一.PTA实验作业 题目1:两个4位正整数的后两位互换 1. 本题PTA提交列 2. 设计思路 3.代码截图 本题调试过程碰到问题及PTA提交列表情况说明 刚开始想到的交换是令t=a;a=b;b=t这 ...

  9. 20162311张之睿 Linux基础与Java开发环境实验报告

    实验一 Java开发环境的熟悉 实验内容 1.使用JDK编译.运行简单的Java程序: 2.使用Eclipse 编辑.编译.运行.调试Java程序. 实验要求 1.没有Linux基础的同学建议先学习& ...

  10. 20162318 实验二《Java面向对象程序设计》实验报告

    北京电子科技学院(BESTI) 实 验 报 告 课程:程序设计与数据结构 班级:1623班 姓名:张泰毓 指导老师:娄老师.王老师 实验日期:2017年4月14日 实验密级:非密级 实验器材:带Lin ...