Files

13 KiB
Raw Permalink Blame History

ListView 使用文档

本文档介绍 AtomUI ListView 控件的各种使用方式,示例代码摘自 Gallery 演示程序。

📖 Gallery 源码位置:controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/ListShowCase.axaml


前置准备

在 AXAML 中使用 ListView,需要引入以下命名空间:

xmlns:atom="https://atomui.net"

在 C# 代码中引入:

using AtomUI.Desktop.Controls;    // ListView, ListViewItem, Pagination
using AtomUI.Controls;             // SizeType 等共享类型
using AtomUI.Controls.Data;        // IListItemData, ListItemData, ListSortDescription

1. 基础用法

ListView 通过 ItemsSource 绑定数据源,数据项需要实现 IListItemData 接口:

<atom:ListView ItemsSource="{Binding ListItems}" />
// ViewModel 或 Code-behind 中准备数据
var listItems = new List<IListItemData>
{
    new ListItemData { Content = "Blue" },
    new ListItemData { Content = "Green" },
    new ListItemData { Content = "Red" },
    new ListItemData { Content = "Yellow" }
};

默认情况下,ListView 使用内置的 ItemTemplate 渲染 IListItemData.Content 属性为文本:

<!-- 默认 ItemTemplate(内置,通常无需手动指定) -->
<DataTemplate x:DataType="atom:IListItemData">
    <atom:TextBlock Text="{Binding Content}" />
</DataTemplate>

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/ListShowCase.axaml 中 "Basic usage" 示例。


2. 选择模式

通过 SelectionMode 属性设置选择模式,结合 IsShowSelectedIndicator 展示选中状态:

<atom:ListView SelectionMode="Single"
               ItemsSource="{Binding SelectionListItems}"
               IsShowSelectedIndicator="True" />

单选模式(默认)

<atom:ListView SelectionMode="Single"
               ItemsSource="{Binding Items}"
               IsShowSelectedIndicator="True" />

多选模式

<atom:ListView SelectionMode="Multiple"
               ItemsSource="{Binding Items}"
               IsShowSelectedIndicator="True" />

Toggle 模式

<atom:ListView SelectionMode="Toggle"
               ItemsSource="{Binding Items}"
               IsShowSelectedIndicator="True" />

动态切换选择模式

<StackPanel Spacing="20">
    <StackPanel Orientation="Horizontal" Spacing="5">
        <atom:TextBlock VerticalAlignment="Center">Selection Mode:</atom:TextBlock>
        <atom:OptionButtonGroup ButtonStyle="Solid" Name="SelectionModeOptionGroup">
            <atom:OptionButton IsChecked="True"
                               Tag="{x:Static SelectionMode.Single}">Single</atom:OptionButton>
            <atom:OptionButton Tag="{x:Static SelectionMode.Multiple}">Multiple</atom:OptionButton>
            <atom:OptionButton Tag="{x:Static SelectionMode.Toggle}">Toggle</atom:OptionButton>
        </atom:OptionButtonGroup>
    </StackPanel>
    <atom:ListView SelectionMode="{Binding SelectionMode}"
                   ItemsSource="{Binding SelectionListItems}"
                   IsShowSelectedIndicator="True" />
</StackPanel>
// Code-behind 处理选择模式切换
SelectionModeOptionGroup.OptionCheckedChanged += (sender, e) =>
{
    if (DataContext is ListViewModel viewModel &&
        e.CheckedOption.IsChecked == true &&
        e.CheckedOption.Tag is SelectionMode selectionMode)
    {
        viewModel.SelectionMode = selectionMode;
    }
};

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/ListShowCase.axaml 中 "Selection" 示例。


3. 分组

通过 IsGroupEnabled="True" 开启分组功能。数据项需要实现 IGroupHeader 接口或通过 Group 属性指定分组:

<atom:ListView ItemsSource="{Binding GroupListItems}"
               IsGroupEnabled="True"
               Height="300" />
// 数据准备 — 使用 Group 属性指定分组
var groupListItems = new List<IListItemData>
{
    new ListItemData { Content = "Red",    Group = "Basic Colors" },
    new ListItemData { Content = "Orange", Group = "Basic Colors" },
    new ListItemData { Content = "Green",  Group = "Basic Colors" },
    new ListItemData { Content = "Blue",   Group = "Basic Colors" },
    new ListItemData { Content = "Brown",  Group = "Neutral Colors" },
    new ListItemData { Content = "White",  Group = "Neutral Colors" },
    new ListItemData { Content = "Black",  Group = "Neutral Colors" },
    new ListItemData { Content = "Turquoise", Group = "Specific Shades" },
    new ListItemData { Content = "Violet",    Group = "Specific Shades" },
    new ListItemData { Content = "Magenta",   Group = "Specific Shades" },
};

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/ListShowCase.axaml 中 "Group" 示例。


4. 禁用项

通过设置 IListItemData.IsEnabled = false 禁用特定列表项:

<atom:ListView ItemsSource="{Binding ListItemsWidthDisabled}" />
var listItems = new List<IListItemData>
{
    new ListItemData { Content = "Blue" },
    new ListItemData { Content = "Green" },
    new ListItemData { Content = "Red" },
    new ListItemData { Content = "Yellow", IsEnabled = false }  // 此项被禁用
};

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/ListShowCase.axaml 中 "Item disabled" 示例。


5. 空状态

当数据源为空时,ListView 自动显示空状态指示器。通过按钮动态增删项目来演示空/非空切换:

<StackPanel Spacing="12">
    <StackPanel Orientation="Horizontal" Spacing="8">
        <atom:Button Content="Add Item" Click="HandleAddEmptyItemClicked" />
        <atom:Button Content="Remove Item" Click="HandleRemoveEmptyItemClicked" />
    </StackPanel>
    <atom:ListView ItemsSource="{Binding EmptyDemoItems}"
                   IsShowEmptyIndicator="True" />
</StackPanel>
private void HandleAddEmptyItemClicked(object? sender, RoutedEventArgs e)
{
    if (DataContext is not ListViewModel viewModel) return;

    var items = viewModel.EmptyDemoItems != null
        ? new List<IListItemData>(viewModel.EmptyDemoItems)
        : new List<IListItemData>();

    items.Add(new ListItemData { Content = "Dynamic item" });
    viewModel.EmptyDemoItems = items;
}

private void HandleRemoveEmptyItemClicked(object? sender, RoutedEventArgs e)
{
    if (DataContext is not ListViewModel viewModel) return;

    if (viewModel.EmptyDemoItems is null || viewModel.EmptyDemoItems.Count <= 1)
    {
        viewModel.EmptyDemoItems = [];
        return;
    }

    var items = new List<IListItemData>(viewModel.EmptyDemoItems);
    items.RemoveAt(items.Count - 1);
    viewModel.EmptyDemoItems = items;
}

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/ListShowCase.axaml 中 "Empty" 示例。


6. 过滤

通过 Filter 和 FilterValue 属性对数据进行过滤。可使用内置的 ValueFilterProvider 标记扩展:

<atom:ListView ItemsSource="{Binding FilteredGroupListItems}"
               Filter="{atom:ValueFilterProvider Contains}"
               FilterValue="a" />

上述配置会过滤出内容包含字母 "a" 的所有项目。

自定义过滤值提取

如果需要按数据项的特定属性过滤,可设置 FilterValueSelector:

// 按自定义属性过滤
listView.FilterValueSelector = record =>
{
    if (record is MyDataItem item)
        return item.Category;
    return null;
};

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/ListShowCase.axaml 中 "Filter" 示例。


7. 排序

通过 SortDescriptions 属性对数据进行排序:

<atom:ListView Name="OrderedList"
               ItemsSource="{Binding OrderedGroupListItems}"
               IsGroupEnabled="True" />
// Code-behind 设置排序
OrderedList.SortDescriptions = [ListSortDescription.FromPath("Content")];

ListSortDescription.FromPath 根据属性路径创建排序描述,默认为升序。

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/ListShowCase.axaml 中 "Ordered" 示例。


8. 分页

ListView 支持内置分页功能,通过 BottomPagination(或 TopPagination)放置分页器,配合 PageSize 设置每页数量:

<atom:ListView ItemsSource="{Binding PaginationListItems}"
               PaginationVisibility="Bottom"
               SelectionMode="Multiple"
               Height="400"
               PageSize="100">
    <atom:ListView.BottomPagination>
        <atom:Pagination />
    </atom:ListView.BottomPagination>
</atom:ListView>
// 准备大量数据用于分页
var list = new List<IListItemData>();
for (var i = 0; i < 2000; i++)
{
    list.Add(new ListItemData
    {
        ItemKey = $"{i}",
        Content = $"Content {i}"
    });
}
viewModel.PaginationListItems = list;

分页器位置控制

<!-- 仅顶部分页 -->
<atom:ListView PaginationVisibility="Top" PageSize="50">
    <atom:ListView.TopPagination>
        <atom:Pagination />
    </atom:ListView.TopPagination>
</atom:ListView>

<!-- 顶部 + 底部同时显示 -->
<atom:ListView PaginationVisibility="Both" PageSize="50">
    <atom:ListView.TopPagination>
        <atom:Pagination />
    </atom:ListView.TopPagination>
    <atom:ListView.BottomPagination>
        <atom:Pagination />
    </atom:ListView.BottomPagination>
</atom:ListView>

<!-- 隐藏分页(仍使用 PageSize 分页数据) -->
<atom:ListView PaginationVisibility="None" PageSize="50" />

分页器对齐

<atom:ListView TopPaginationAlign="Center"
               BottomPaginationAlign="End"
               PageSize="50">
    <!-- ... -->
</atom:ListView>

📖 参考:controlgallery/AtomUIGallery/ShowCases/Views/DataDisplay/ListShowCase.axaml 中 "Pagination list" 示例。


9. 选择绑定

绑定 SelectedItem

<atom:ListView ItemsSource="{Binding Items}"
               SelectedItem="{Binding CurrentItem}" />

绑定 SelectedIndex

<atom:ListView ItemsSource="{Binding Items}"
               SelectedIndex="{Binding CurrentIndex}" />

多选绑定 SelectedItems

<atom:ListView ItemsSource="{Binding Items}"
               SelectionMode="Multiple"
               SelectedItems="{Binding SelectedItemsList}" />

使用 SelectedValue + SelectedValueBinding

<atom:ListView ItemsSource="{Binding Items}"
               SelectedValue="{Binding SelectedId}"
               SelectedValueBinding="{Binding ItemKey}" />

监听选择变化事件

<atom:ListView ItemsSource="{Binding Items}"
               SelectionChanged="HandleSelectionChanged" />
private void HandleSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
    foreach (var added in e.AddedItems)
    {
        // 处理新选中的项
    }
    foreach (var removed in e.RemovedItems)
    {
        // 处理取消选中的项
    }
}

10. 加载状态

通过 IsOperating 属性展示加载状态覆盖层:

<atom:ListView ItemsSource="{Binding Items}"
               IsOperating="{Binding IsLoading}"
               OperatingMsg="Loading data..." />
// 模拟异步加载
public async Task LoadDataAsync()
{
    IsLoading = true;
    try
    {
        var data = await _service.GetDataAsync();
        Items = data;
    }
    finally
    {
        IsLoading = false;
    }
}

11. 监听项目点击

<atom:ListView ItemsSource="{Binding Items}"
               ItemClicked="HandleItemClicked" />
private void HandleItemClicked(object? sender, ListViewItemClickedEventArgs e)
{
    var clickedItem = e.Item;
    // 处理点击逻辑
}

常见组合模式

基础数据列表

<atom:ListView ItemsSource="{Binding Items}"
               IsShowSelectedIndicator="True"
               SelectionMode="Single" />

可搜索的过滤列表

<StackPanel Spacing="10">
    <atom:SearchEdit PlaceholderText="Search..."
                     TextChanged="HandleSearchTextChanged" />
    <atom:ListView Name="FilterableList"
                   ItemsSource="{Binding Items}"
                   Filter="{atom:ValueFilterProvider Contains}" />
</StackPanel>
private void HandleSearchTextChanged(object? sender, TextChangedEventArgs e)
{
    if (sender is SearchEdit searchEdit)
    {
        FilterableList.FilterValue = searchEdit.Text?.Trim();
    }
}

分组 + 排序列表

<atom:ListView ItemsSource="{Binding GroupItems}"
               IsGroupEnabled="True"
               Height="400" />
// 同时设置排序
listView.SortDescriptions = [ListSortDescription.FromPath("Content")];

大数据分页列表

<atom:ListView ItemsSource="{Binding LargeDataSet}"
               PageSize="50"
               SelectionMode="Multiple"
               PaginationVisibility="Bottom"
               BottomPaginationAlign="End"
               Height="500">
    <atom:ListView.BottomPagination>
        <atom:Pagination />
    </atom:ListView.BottomPagination>
</atom:ListView>