概述

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,奇数则设置背景为空;

  1. private static void ColorContainerContentChanging(Windows.UI.Xaml.Controls.ListViewBase sender, ContainerContentChangingEventArgs args)
  2. {
  3. var itemContainer = args.ItemContainer as SelectorItem;
  4. var itemIndex = sender.IndexFromContainer(itemContainer);
  5.  
  6. == )
  7. {
  8. itemContainer.Background = GetAlternateColor(sender);
  9. }
  10. else
  11. {
  12. itemContainer.Background = null;
  13. }
  14. }

② ItemTemplateContainerContentChanging(sender, args):

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

  1. private static void ItemTemplateContainerContentChanging(Windows.UI.Xaml.Controls.ListViewBase sender, ContainerContentChangingEventArgs args)
  2. {
  3. var itemContainer = args.ItemContainer as SelectorItem;
  4. var itemIndex = sender.IndexFromContainer(itemContainer);
  5.  
  6. == )
  7. {
  8. itemContainer.ContentTemplate = GetAlternateItemTemplate(sender);
  9. }
  10. else
  11. {
  12. itemContainer.ContentTemplate = sender.ItemTemplate;
  13. }
  14. }

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

③ StretchItemContainerDirectionChanging(sender, args):

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

  1. private static void StretchItemContainerDirectionChanging(Windows.UI.Xaml.Controls.ListViewBase sender, ContainerContentChangingEventArgs args)
  2. {
  3. var itemContainer = args.ItemContainer as SelectorItem;
  4. var stretchDirection = GetStretchItemContainerDirection(sender);
  5.  
  6. if (stretchDirection == StretchDirection.Vertical || stretchDirection == StretchDirection.Both)
  7. {
  8. itemContainer.VerticalContentAlignment = VerticalAlignment.Stretch;
  9. }
  10.  
  11. if (stretchDirection == StretchDirection.Horizontal || stretchDirection == StretchDirection.Both)
  12. {
  13. itemContainer.HorizontalContentAlignment = HorizontalAlignment.Stretch;
  14. }
  15. }

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

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

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

① OnAlternateColorPropertyChanged(sender, args):

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

  1. private static void OnAlternateColorPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
  2. {
  3. Windows.UI.Xaml.Controls.ListViewBase listViewBase = sender as Windows.UI.Xaml.Controls.ListViewBase;
  4.  
  5. if (listViewBase == null)
  6. {
  7. return;
  8. }
  9.  
  10. listViewBase.ContainerContentChanging -= ColorContainerContentChanging;
  11. listViewBase.Items.VectorChanged -= ColorItemsVectorChanged;
  12. listViewBase.Unloaded -= OnListViewBaseUnloaded;
  13.  
  14. _itemsForList[listViewBase.Items] = listViewBase;
  15. if (AlternateColorProperty != null)
  16. {
  17. listViewBase.ContainerContentChanging += ColorContainerContentChanging;
  18. listViewBase.Items.VectorChanged += ColorItemsVectorChanged;
  19. listViewBase.Unloaded += OnListViewBaseUnloaded;
  20. }
  21. }

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

  1. private static void ColorItemsVectorChanged(IObservableVector<object> sender, IVectorChangedEventArgs args)
  2. {
  3. // If the index is at the end we can ignore
  4. )) { return; }
  5.  
  6. // Only need to handle Inserted and Removed because we'll handle everything else in the
  7. // ColorContainerContentChanging method
  8. if ((args.CollectionChange == CollectionChange.ItemInserted) || (args.CollectionChange == CollectionChange.ItemRemoved))
  9. {
  10. _itemsForList.TryGetValue(sender, out Windows.UI.Xaml.Controls.ListViewBase listViewBase);
  11. if (listViewBase == null) { return; }
  12.  
  13. int index = (int)args.Index;
  14. for (int i = index; i < sender.Count; i++)
  15. {
  16. var itemContainer = listViewBase.ContainerFromIndex(i) as Control;
  17. if (itemContainer != null)
  18. {
  19. SetItemContainerBackground(listViewBase, itemContainer, i);
  20. }
  21. }
  22. }
  23. }

② OnAlternateItemTemplatePropertyChanged(sender, args):

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

  1. private static void OnAlternateItemTemplatePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
  2. {
  3. Windows.UI.Xaml.Controls.ListViewBase listViewBase = sender as Windows.UI.Xaml.Controls.ListViewBase;
  4.  
  5. if (listViewBase == null)
  6. {
  7. return;
  8. }
  9.  
  10. listViewBase.ContainerContentChanging -= ItemTemplateContainerContentChanging;
  11. listViewBase.Unloaded -= OnListViewBaseUnloaded;
  12.  
  13. if (AlternateItemTemplateProperty != null)
  14. {
  15. listViewBase.ContainerContentChanging += ItemTemplateContainerContentChanging;
  16. listViewBase.Unloaded += OnListViewBaseUnloaded;
  17. }
  18. }

③ OnStretchItemContainerDirectionPropertyChanged(sender, args):

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

  1. private static void OnStretchItemContainerDirectionPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
  2. {
  3. Windows.UI.Xaml.Controls.ListViewBase listViewBase = sender as Windows.UI.Xaml.Controls.ListViewBase;
  4.  
  5. if (listViewBase == null)
  6. {
  7. return;
  8. }
  9.  
  10. listViewBase.ContainerContentChanging -= StretchItemContainerDirectionChanging;
  11. listViewBase.Unloaded -= OnListViewBaseUnloaded;
  12.  
  13. if (StretchItemContainerDirectionProperty != null)
  14. {
  15. listViewBase.ContainerContentChanging += StretchItemContainerDirectionChanging;
  16. listViewBase.Unloaded += OnListViewBaseUnloaded;
  17. }
  18. }

调用示例

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

  1. <Page.Resources>
  2. <DataTemplate x:Name="NormalTemplate">
  3. <TextBlock Text="{Binding Title}" Foreground="Green"></TextBlock>
  4. </DataTemplate>
  5. <DataTemplate x:Name="AlternateTemplate">
  6. <TextBlock Text="{Binding Title}" Foreground="Orange"></TextBlock>
  7. </DataTemplate>
  8. </Page.Resources>
  9.  
  10. <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
  11. <ListView x:Name="SampleListView" Margin="12"
  12. ItemTemplate="{StaticResource NormalTemplate}"
  13. extensions:ListViewExtensions.AlternateColor="LightGray"
  14. extensions:ListViewExtensions.AlternateItemTemplate="{StaticResource AlternateTemplate}"
  15. extensions:ListViewExtensions.StretchItemContainerDirection="Both">
  16. </ListView>
  17. </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. Laravel 中缓存驱动的速度比较

    缓存是web开发中重要的一部分,我相信很多人和我一样,经常忽略这个问题. 随着工作经验的累积,我已经意识到缓存是多么的重要,这里我通过 Scotch 来解释一下它的重要性. 通过观察发现,Scotch ...

  2. NEO从入门到开窗(4) - NEO CLI

    一.唠叨两句 首先,我们都知道区块链是去中心化的,其中节点都是对等节点,每个节点都几乎有完整的区块链特性,CLI就是NEO的一个命令行对等节点,当然也有GUI这个项目,图形化的NEO节点.节点之间需要 ...

  3. 根据IO流源码深入理解装饰设计模式使用

    一:摘要 通过对java的IO类中我们可以得出:IO源码中使用装饰设计模式频率非常高, 对装饰设计模式而言,他能够避免继承体系的臃肿,同时也可以动态的给一个对象添加一些额外的功能,如果要扩展一个功能, ...

  4. Java虚拟机之GC

    ⑴背景 Java堆和方法区实现类所需内存是不一样的,每个方法的多分支需要的内存也可能不一样,我们只有在运行期间才能制动创建哪些对象.这部分内存分配与回收都是动态的,而垃圾回收器所关注的就是这些这部分内 ...

  5. 【Java】0X001.配置开发环境,JDK、classpath等

    [Java]0x01 配置开发环境,JDK.CLASSPATH等 一. 下载JDK安装文件 首先,进入Oracle官网Java页面. 注意,要下载的是JDK而不是JRE,这点很重要,因为JRE并不包含 ...

  6. 极光征文 | 写写文章就能赢 Filco,岂不美滋滋

    由极光社区举办的第二届征文大赛 --「我和极光的那些事儿」又来啦! 在简书平台发布文章并投稿至「我和极光的那些事」专题,只要参与就能 100% 获得京东购物卡,更有机会赢取象征信仰的 Filco 机械 ...

  7. Beta冲刺第一天

    一.昨天的困难 Beta阶段第一天,主要进行本阶段的计划和任务分配,主要问题是上阶段所做的测试工作较少,本阶段需要加强测试工作,并不断修复检测出来的BUG. 二.今天进度 所有成员写简单测试测试整体应 ...

  8. verilog学习笔记(2)_一个小module及其tb

    module-ex_cnt module ex_cnt( input wire sclk, input wire rst_n, output wire[9:0] cnt ); reg [9:0] cn ...

  9. mint-ui在vue中的使用。

    首先放上mint-ui中文文档 近来在使用mint-ui,发现部分插件在讲解上并不是很详细,部分实例找不到使用的代码.github上面的分享,里面都是markdown文件,内容就是网上的文档 刚好自己 ...

  10. Centos6.7下面配置vim及其插件

    Vim是在vi的基础上升级而来的,比vi更强大,提供代码补全,编译功能 [4]vim Vim是从 vi 发展出来的一个文本编辑器.代码补完.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用 ...