Extensions in UWP Community Toolkit - ListViewExtensions
概述
UWP Community Toolkit Extensions 中有一个为 ListView 提供的扩展 - ListViewExtensions,本篇我们结合代码详细讲解 ListView Extensions 的实现。
ListViewExtensions 为每一种继承了 ListViewBase 类的控件提供了一种轻量级的方式来扩展它的附加属性。目前扩展的附加属性有 AlternateColor、AlternateItemTemplate 和 StretchItemContainerDirection;需要注意的是,扩展使用 ContainerContentChanging 事件来保证工作,如果控件的 ItemsPanel 被设置为 ItemsStackPanel 或 ItemsWrapGrid,那么扩展将不能正常工作。另外 StretchItemContainerDirection 有 Horizontal、Vertical 和 Both 三个选项。我们来看官方示例截图:

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的更多相关文章
- Extensions in UWP Community Toolkit - Overview
概述 UWP Community Toolkit 中有一个 Extensions 的集合,它们可以帮助开发者实现很多基础功能,省去自己造轮子的过程,本篇我们先来看一下 Extensions 的功能都 ...
- Extensions in UWP Community Toolkit - FrameworkElement Extensions
概述 UWP Community Toolkit Extensions 中有一个为FrameworkElement 提供的扩展 - FrameworkElement Extensions,本篇我们结合 ...
- Extensions in UWP Community Toolkit - Mouse Cursor
概述 UWP Community Toolkit Extensions 中有一个为 Mouse 提供的扩展 - Mouse Cursor Extensions,本篇我们结合代码详细讲解 Mouse C ...
- Extensions in UWP Community Toolkit - SurfaceDialTextbox
概述 UWP Community Toolkit Extensions 中有一个为TextBox 提供的 SurfaceDial 扩展 - SurfaceDialTextbox,本篇我们结合代码详细讲 ...
- Extensions in UWP Community Toolkit - ViewExtensions
概述 UWP Community Toolkit Extensions 中有一个为 View 提供的扩展 - View Extensions,本篇我们结合代码详细讲解 View Extensions ...
- Extensions in UWP Community Toolkit - Visual Extensions
概述 UWP Community Toolkit Extensions 中有一个为可视元素提供的扩展 - VisualExtensions,本篇我们结合代码详细讲解 VisualExtensions ...
- Extensions in UWP Community Toolkit - WebViewExtensions
概述 UWP Community Toolkit Extensions 中有一个为 WebView 提供的扩展 - WebViewExtensions,本篇我们结合代码详细讲解 WebView Ext ...
- New UWP Community Toolkit
概述 UWP Community Toolkit 是一个 UWP App 自定义控件.应用服务和帮助方法的集合,能够很大程度的简化和指引开发者的开发工作,相信广大 UWPer 并不陌生. 下面是截取自 ...
- Animations in UWP Community Toolkit - Overview
概述 UWP Community Toolkit 中有一个 Animations 的集合,它们可以帮助开发者实现很多的动画,本篇我们先来看一下 Animations 的功能都有哪些,再后面会针对每一 ...
随机推荐
- 源码实现 --> strdel
删除字符串中某个字符strdel 函数 char *strDel(char* str,const char chToDel) 不是库里面的函数,自己实现的原型,删除str中所有的chToDel字符. ...
- Java多线程:乐观锁、悲观锁、自旋锁
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁.传统的关系型数据 ...
- C#添加背景音乐
<MediaElement Name="audio"/> <Button Name="music" Content="点我有音乐哦& ...
- 第二次作业-Steam软件分析
1 .介绍产品相关信息 随着电子音频游戏产业的发展以及正版意识的崛起,Steam已经成为大部分游戏爱好者必备的一款游戏下载平台.这款软件也使得Valve公司从一个游戏制作公司成功扩展业务到一个承揽众多 ...
- Alpha第六天
Alpha第六天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...
- [Android FrameWork 6.0源码学习] View的重绘过程之WindowManager的addView方法
博客首页:http://www.cnblogs.com/kezhuang/p/关于Activity的contentView的构建过程,我在我的博客中已经分析过了,不了解的可以去看一下<[Andr ...
- day-3 python多线程编程知识点汇总
python语言以容易入门,适合应用开发,编程简洁,第三方库多等等诸多优点,并吸引广大编程爱好者.但是也存在一个被熟知的性能瓶颈:python解释器引入GIL锁以后,多CPU场景下,也不再是并行方式运 ...
- Apache自带 ab压测工具 Windows配置使用说明 - 随笔记录
我们先来了解一下ab工具的概念,摘自网络: ab是apache自带的压力测试工具.ab非常实用,它不仅可以对apache服务器进行网站访问压力测试,也可以对或其它类型的服务器进行压力测试.比如ngin ...
- mongodb 定时备份
通过centos 脚步来执行备份操作,使用crontab实现定时功能,并删除指定天数前的备份 具体操作: 1.创建Mongodb数据库备份目录 mkdir -p /home/backup/mongod ...
- EasyUI 主布局整合。
博文学习地址:http://www.cnblogs.com/xishuai/p/3620327.html html: <%@ Page Language="C#" AutoE ...