首页 > 解决方案 > 具有可编辑多行文本框性能的 UWP 分组列表视图

问题描述

尝试使用可编辑的多行 TextBoxes 实现 Grouped ListView 时遇到此问题:尝试输入 TextBox 并更改行(按 Enter 或文本需要换行)并且输入 TextBox 的高度增加会导致 ListViewItem(行)增加的话,UI线程的性能就显得迟钝了。

当有相当多的组且每组具有不同数量的项目(从 0 到假设 5)并且每个文本具有多行内容时,这种 UI 性能障碍更加明显。

在以下情况下问题消失:

  1. ListView 未分组

  2. ListView 虚拟化被覆盖(通过使用 StackPanel 而不是 ItemsStackPanel 作为 ItemsPanelTemplate),但我失去了虚拟化的加载性能优势和 Group 标头良好的粘性行为。

为了填充 ListView,我使用模型绑定。这是我使用的代码:

这是一个虚拟模型,用于保存可编辑文本框和 MyModel 的集合对象的数据,以生成具有 CollectionName 属性的组,以显示为组标题。

public class MyModel
{
    public string Cell1 { get; set; }
    public string Cell2 { get; set; }
    public string Cell3 { get; set; }
}

public class MyModelCollection : Collection<MyModel>
{
    public string CollectionName { get; set; }
}

然后 ViewModel 填充数据以显示在 View 中:您可以注意到我生成了包含 0 到 5 个项目(行)的组。每行应包含三个多行文本框(单元格)。

public class MainPageViewModel
{
    public List<MyModelCollection> MyModelCollections { get; set; }
    public MainPageViewModel()
    {
        var myCollections = new List<MyModelCollection>();

        for (var j = 0; j < 20; j++)
        {
            var myCollection = new MyModelCollection();
            myCollection.CollectionName = "Title of group " + j;
            var iMax = 5;
            if (j == 0|| j == 5 || j == 6 || j == 9 || j == 11) iMax = 0;
            if (j == 3 || j == 7 || j == 8) iMax = 1;
            if (j == 2 || j == 10) iMax = 3;
            for (var i = 0; i < iMax; i++)
            {
                var row = new MyModel();

                var multiLine1 = new StringBuilder();
                multiLine1.AppendLine("Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1Line1Line1Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 Line1 ");
                multiLine1.AppendLine("Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2Line2Line2 Line2 Line2Line2 Line2Line2 Line2 Line2 Line2 Line2 Line2 Line2Line2 Line2 Line2 Line2 Line2Line2 Line2 Line2 Line2 Line2");
                row.Cell1 = multiLine1.ToString();

                var multiLine2 = new StringBuilder();
                multiLine2.AppendLine("Line1");
                multiLine2.AppendLine("Line2Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2Line2Line2 Line2 Line2Line2 Line2Line2 Line2 Line2 Line2 Line2 Line2 Line2Line2 Line2 Line2 Line2 Line2Line2 Line2 Line2 Line2 Line2");
                multiLine2.AppendLine("Line3");
                multiLine2.AppendLine("Line4");
                row.Cell2 = multiLine2.ToString();

                var multiLine3 = new StringBuilder();
                multiLine3.AppendLine("Line1");
                multiLine3.AppendLine("Line2Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2 Line2Line2Line2 Line2 Line2Line2 Line2Line2 Line2 Line2 Line2 Line2 Line2 Line2Line2 Line2 Line2 Line2 Line2Line2 Line2 Line2 Line2 Line2");
                multiLine3.AppendLine("Line3 Line3 Line3 Line3Line3 Line3Line3 Line3Line3 Line3Line3 Line3Line3 Line3Line3 Line3Line3 Line3Line3 Line3Line3 Line3Line3 Line3");
                row.Cell3 = multiLine3.ToString();

                myCollection.Add(row);
            }

            myCollections.Add(myCollection);
        }


        MyModelCollections = myCollections;
    }
}

然后将 MainPageViewModel 设置为 XAML 页面的 DataContext(命名为 ViewModel)

<Page.DataContext>
    <local:MainPageViewModel x:Name="ViewModel"/>
</Page.DataContext>

然后在 XAML 页面资源中的 CollectionViewSource 启用绑定:

<Page.Resources>
    <CollectionViewSource x:Key="CollectionsSource" IsSourceGrouped="True" Source="{x:Bind ViewModel.MyModelCollections, Mode=OneWay}"></CollectionViewSource>
</Page.Resources>

最后是 XAML 视图中的 ListView 控件

<ListView ItemsSource="{Binding Source={StaticResource CollectionsSource}}">
    <ListView.GroupStyle>
        <GroupStyle HidesIfEmpty="False" >
            <GroupStyle.HeaderTemplate>
                <DataTemplate x:DataType="local:MyModelCollection">
                    <Grid>
                        <TextBlock Text="{x:Bind CollectionName}"/>
                    </Grid>
                </DataTemplate>
            </GroupStyle.HeaderTemplate>
        </GroupStyle>
    </ListView.GroupStyle>
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:MyModel">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <TextBox Text="{x:Bind Cell1, Mode=TwoWay}" TextWrapping="Wrap" BorderThickness="0" Grid.Column="0" AcceptsReturn="True"/>
                <TextBox Text="{x:Bind Cell2, Mode=TwoWay}" TextWrapping="Wrap" BorderThickness="0" Grid.Column="1" AcceptsReturn="True"/>
                <TextBox Text="{x:Bind Cell3, Mode=TwoWay}" TextWrapping="Wrap" BorderThickness="0" Grid.Column="2" AcceptsReturn="True"/>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

尝试运行上述代码时,如果我向下滚动到第 4 组的最后一项(屏幕下方显示了第 5,6 和 7 组)并尝试在第一个单元格中写入导致该项的高度增加,然后UI的性能很差。在其他一些打字情况下,这种性能障碍并不那么明显,您可以尝试...

如前所述,性能问题消失了:

  1. 如果我删除组项目 (ListViewHeaderItem) 并且最简单的方法是从 XAML 中的 ListView 中完全删除 ListView.GroupStyle 元素
  2. 或者我通过使用普通 StackPanel 作为 ItemsPanelTemplate 删除 ListView 虚拟化(请参阅下面的新 ListView xaml)

    <ListView ItemsSource="{Binding Source={StaticResource CollectionsSource}}">
        <ListView.GroupStyle>
            <GroupStyle HidesIfEmpty="False" >
                <GroupStyle.HeaderTemplate>
                    <DataTemplate x:DataType="local:MyModelCollection">
                        <Grid >
                            <TextBlock Text="{x:Bind CollectionName}"/>
                        </Grid>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </ListView.GroupStyle>
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Vertical"/>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="local:MyModel">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
    
                    <TextBox Text="{x:Bind Cell1, Mode=TwoWay}" TextWrapping="Wrap" BorderThickness="0" Grid.Column="0" AcceptsReturn="True"/>
                    <TextBox Text="{x:Bind Cell2, Mode=TwoWay}" TextWrapping="Wrap" BorderThickness="0" Grid.Column="1" AcceptsReturn="True"/>
                    <TextBox Text="{x:Bind Cell3, Mode=TwoWay}" TextWrapping="Wrap" BorderThickness="0" Grid.Column="2" AcceptsReturn="True"/>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    

标签: c#performancexamllistviewuwp

解决方案


推荐阅读