在WPF的时代,我们多是使用ListBox和ListView来展示,纵向滚动条显示的集合数据。这两个控件的默认样式,以及对触控的支持,已完全落后于时代。他们两个分别长这样,和Win10及Win11的风格完全不沾边。

今天我来看下WinUI 3中适用于Desktop App的ListView,我们略过ListBox是因为ListBox使用较为简单,通常用于将少量数据同时显示在页面上。
而显示需要滚动条的大量数据,会推荐使用ListView,同时ListView的表现形式也较为丰富。例如分组,拖拽,缩放,以及页头页脚的自定义。
本篇我们将试着应用以上这些特性到Desktop App中,通过WinUI 3库,我们不再需要Xaml Islands这样曲线救国的做法。而是真正在Desktop App中用上原生的新ListView。
首先我们来看分组,WinUI 3中的ListView通过CollectionViewSource这个组件来实现分组功能。当然我们也可以通过嵌套集合的方式来实现,例如将ListView的ListViewItem同样也包含一个ListView/ItemsControl。但是这样做有一些缺陷,第一是会破坏UI虚拟化(UI virtualization),因为用于虚拟化的容器(Item Container)在面对重复的Item才会起到效果,用ListView/ItemsControl这样的可变集合作为Item,在数量增多后会有明显的性能问题。第二是嵌套集合的话,SeletedItem和ItemClick处理起来会比较困难。所以我更推荐使用CollectionViewSource。

ListView的分组并不复杂,在XAML中我们需要于Resources节点中放置CollectionViewSource对象,该对象是真正数据源的一个视图。我们可以对这个视图做分组和排序,但不会自动影响到真正的数据源。
假设我们有一个Person类:

    public class Person
{
public string Name { get; set; }
}

并构建了PersionList作为数据源,同时创建了分组视图PersonGroup。

            this.PersonList = new List<Person>
{
new Person{ Name = "Abe"},
new Person{ Name = "Alice"},
new Person{ Name = "Bell"},
new Person{ Name = "Ben"},
new Person{ Name = "Bob"},
new Person{ Name = "Fox"},
new Person{ Name = "Gray"},
new Person{ Name = "James"},
new Person{ Name = "Jane"},
new Person{ Name = "Roy"},
new Person{ Name = "Vincent"}
};
PersonGroup = PersonList.GroupBy(p => p.Name.First().ToString());

那么我们在XAML中,将通过如下形式的binding来使用该分组视图:

    <Grid>
<Grid.Resources>
<CollectionViewSource x:Name="personListCVS" IsSourceGrouped="True" Source="{x:Bind PersonGroup}"/>
</Grid.Resources>
<ListView ItemsSource="{x:Bind personListCVS.View}">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Key}"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>

上面的XAML中定义简单的仅TextBlock的HeaderTemplate和ItemTemplate,实际生产中可按需编写更复杂的模板。
接下来我们看拖拽的实现,这里我们创建一个DragDropPage.xaml,假设ListView作为被拖走数据的一方,在DataTemplate的子节点上,将CanDrag设置为True,因为接受数据的需要,我们要明确被拖拽走的是个什么东西,通过DragStarting事件可以获得被操作的UIElement。

        <ListView Grid.Column="0" ItemsSource="{x:Bind PersonList}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" CanDrag="True" DragStarting="TextBlock_DragStarting"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

作为接受拖拽对象的ComboxBox,除了设置AllowDrop=True以外,还需要通过DragOver来响应图标的变化(假设在鼠标移过来后,图标从“无效”的样式转变成了“复制”,表示可以接受该数据),以及通过Drop来处理接受数据。

        <ComboBox Grid.Column="1" ItemsSource="{x:Bind PersonList}" SelectedItem="{x:Bind SelectedPerson,Mode=TwoWay}"
AllowDrop="True" DragOver="ComboBox_DragOver" Drop="ComboBox_Drop">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"></TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

在创建本篇的Sample Code时,WinUI 3 的SDK版本已经从0.5更新到0.8了(稳定版)。但是在Drop事件里依然遇到了bug,无法访问DragEventArgs中的DataView来获取DragStarting时存放的数据。这个问题已经有大量的issue开给了某软,并不是WinUI 3库本身的bug,锅已丢给CsWinRT项目,但什么时候修好就不知道了。
Unable to drop files onto Grid in WinUI3 Desktop · Issue #2715 · microsoft/microsoft-ui-xaml (github.com)
DataView无法使用,直接影响了应用间的数据传递。对于本篇的APP内部的拖拽,倒是可以写个Property绕过去。拖拽操作的流程先是通过DragStarting来获取和存放要传递的数据。DragOver负责更改图标,反馈给用户某个控件可以接受Drop操作。最后由Drop来接受数据和更新UI。

        private void ComboBox_Drop(object sender, DragEventArgs e)
{
//if (e.DataView.Contains(StandardDataFormats.Text))
//{
// var name = await e.DataView.GetTextAsync();
// this.SelectedPerson = this.PersonList.FirstOrDefault(p => p.Name == name);
//} this.SelectedPerson = DragPerson;
} private void ComboBox_DragOver(object sender, DragEventArgs e)
{
e.AcceptedOperation = DataPackageOperation.Copy;
} private void TextBlock_DragStarting(UIElement sender, DragStartingEventArgs args)
{
DragPerson = (sender as TextBlock).DataContext as Person;
//args.Data.SetData(StandardDataFormats.Text, DragPerson.Name);
}

本篇最后我想讨论下<ListView.Header>和<ListView.Footer>,通常认为额外做一个<StackPanel>或<Grid>放置在ListView的上下方即可。不过我想说的是,如果遇到Layout变化,通过VisaulState等方式来位移控件的情况,一个整体的ListView会比较方便。在ListViewHeaderFooterPage中,假设ListView上方存在MenuBar,下部需要CommandBar。如果这两个控件一直和ListView保持紧密的联系,那就可以放到Header和Footer中作为一个整体。

以上就是本篇对WinUI 3中ListView的一些讨论。缩放视图打算后面结合SemanticZoom 再来演示。感谢阅读到这里的同学们!

Sample Code:
https://github.com/manupstairs/WinUI3Samples/tree/main/WinUI3Samples/ListViewSample

以下链接,是MS Learn上Windows开发的入门课程,单个课程三十分钟到60分钟不等,如需补充基础知识的同学点这里:

开始使用 Visual Studio 开发 Windows 10 应用

开发 Windows 10 应用程序

编写首个 Windows 10 应用

创建 Windows 10 应用的用户界面 (UI)

增强 Windows 10 应用的用户界面

在 Windows 10 应用中实现数据绑定

WinUI 3学习笔记(2)—— 用ListView来展示集合的更多相关文章

  1. WinUI 3学习笔记(3)—— ComboBox & DropDownButton & SplitButton

    本篇想介绍相对小众但颇具使用价值的控件SplitButton,提到SplitButton难免会拿来与ComboBox进行比较,同时在WinUI 3的控件库中,还有一个默默无闻的DropDownButt ...

  2. springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定

    springmvc学习笔记(13)-springmvc注解开发之集合类型參数绑定 标签: springmvc springmvc学习笔记13-springmvc注解开发之集合类型參数绑定 数组绑定 需 ...

  3. Java学习笔记——浅谈数据结构与Java集合框架(第一篇、List)

    横看成岭侧成峰,远近高低各不同.不识庐山真面目,只缘身在此山中. --苏轼 这一块儿学的是云里雾里,咱们先从简单的入手.逐渐的拨开迷雾见太阳.本次先做List集合的三个实现类的学习笔记 List特点: ...

  4. Android学习笔记(20)————利用ListView制作带竖线的多彩表格

    http://blog.csdn.net/conowen/article/details/7421805 /********************************************** ...

  5. AppCan学习笔记----关闭页面listview动态加载数据

    AppCan页面关闭 AppCan 的页面是由两个HTML组成,如果要完全关闭的话需要在主HTML eg.index.html中关闭,关闭方法:appcan.window.close(-1); 管道 ...

  6. ANDROID_MARS学习笔记_S04_008_用Listview、自定义adapter显示返回的微博数据

    一.简介 运行结果 二.代码1.xml(1)activity_main.xml <?xml version="1.0" encoding="utf-8"? ...

  7. Android(java)学习笔记194:ListView编写步骤(重点)

    1.ListView在我们的手机android编写程序中使用是十分广泛的,比如如下图中 短信 和 手机设置 都是ListView的效果: 手机设置:             短信:    2.正因为这 ...

  8. Android(java)学习笔记137:ListView编写步骤(重点)

    1.ListView在我们的手机android编写程序中使用是十分广泛的,比如如下图中 短信 和 手机设置 都是ListView的效果: 手机设置:             短信:    2.正因为这 ...

  9. JavaScript学习笔记——简单无缝循环滚动展示图片的实现

    今天做了一个简单的无缝循环滚动的实例,这种实例在网页中其实还挺常见的,下面分享一下我的学习收获. 首先,无缝滚动的第一个重点就是——动.关于怎么让页面的元素节点动起来,这就得学明白关于JavaScri ...

随机推荐

  1. Docker减小镜像体积

    导航: 这里分为几个部分. 相关转载云原生:米开朗基杨 1.Docker减小镜像体积 2.Docker镜像针对不同语言的精简策略 对于刚接触容器的人来说,他们很容易被自己制作的 Docker 镜像体积 ...

  2. Python UI自动化

    Python3--Uiautomator2--Pytest--Alure使用 官方源码GitHub地址:https://github.com/openatx/uiautomator2 介绍 uiaut ...

  3. 面试:MyBatis面试总结

    1.什么是Mybatis? (1)Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动.创建连接.创建statement ...

  4. XCTF 3rd-GCTF-2017 hackme

    一.查壳的老生常谈了..2分的题目就不多bb了. 二..elf文件,拖入ida,直接查找字符串,找到对应的函数 三.直接分析: 这里讲道理我当时很懵逼,因为进去这个函数后,发现伪码非常复杂,这里困了挺 ...

  5. ESP32-FAT文件系统使用磨损均衡存储文件笔记

    基于ESP-IDF4.1 1 /* 2 FAT文件系统存储文件,使用磨损均衡库wear-leveling 3 */ 4 5 #include <stdlib.h> 6 #include & ...

  6. Redisson 分布式锁源码 11:Semaphore 和 CountDownLatch

    前言 Redisson 除了提供了分布式锁之外,还额外提供了同步组件,Semaphore 和 CountDownLatch. Semaphore 意思就是在分布式场景下,只有 3 个凭证,也就意味着同 ...

  7. Vue数据双向绑定不起作用、Vue如何正确的手动添加json数据、Vue视图层不刷新、手动刷新视图层

    Vue.set(obj,"key","value") 如果接收到来自服务器的消息时,我们需要对其进性进一步处理 我们想当然的会直接将数据添加进json 像这样: ...

  8. sqliab刷题笔记-联合注入

    Less-1 测试是字符型还是数字型 判断所在字段数 查看显示值 可以看出显示2,3位置.因此我们选择2的位置进行联合注入 查看表名 我们要对admin,users等字符敏感 查看admin表中的字段 ...

  9. Linux + .net core 开发升讯威在线客服系统:首个经过实际验证的高性能版本

    业余时间用 .net core 写了一个在线客服系统.并在博客园写了一个系列的文章,写介绍这个开发过程: .net core 和 WPF 开发升讯威在线客服系统:目录 https://blog.she ...

  10. nmcli命令行修改网络连接名称

    目前在网上能找到的文章中,使用nmcli命令修改Linux系统中网卡连接的名称都是先创建新的连接,然后删除旧的连接的方式 此种方式其实完全不恰当,简直就是在浪费时间,nmcli命令本身就提供了直接修改 ...