在ListBox中显示边框图块,在WPF中显示大量项目

时间:2015-11-28 20:02:11

标签: c# wpf listbox tile

我正在尝试构建类似于第一个屏幕截图的GUI: What I'm trying to achieve

基本上它是一个瓷砖视图,以带状网格显示,在调整窗口大小时动态更改列数。这些项目是可选择的。这些可能看起来像图片,但它们只是Unicode字符。

我已经创建了一个自定义对象列表,并成功地将列表绑定到ListBox控件。当然,这给了我一个垂直堆叠的字符列表。

所以我用Google搜索了一些,发现我可以为列表框设置自定义ItemsPanelTemplate:

<ListBox.ItemsPanel>
    <ItemsPanelTemplate>
       <WrapPanel Margin="0"/>
    </ItemsPanelTemplate>
</ListBox.ItemsPanel>

结果如下: Effect of using a WrapPanel

为了设置图块的边框和大小,我还添加了一个ItemTemplate:

<ListBox Margin="0,0,0,0" Padding="0,0,0,0" Grid.Row="0" Grid.Column="0" x:Name="tw" 
            SelectionChanged="tw_SelectionChanged" 
            ScrollViewer.HorizontalScrollBarVisibility="Disabled" 
            ScrollViewer.VerticalScrollBarVisibility="Visible">
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel Margin="0,0,0,0"/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Label 
                        Padding="0,0,0,0"
            Margin="0,0,0,0"
                        Width="50" 
                        Height="50" 
                        FontSize="20" 
                        Background="White"
                        HorizontalAlignment="Left" 
                        HorizontalContentAlignment="Center"
                        VerticalContentAlignment="Center"
                        BorderThickness="1"
                        BorderBrush="Black"
                    Content="{Binding Path=LiteralString}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

结果如下: Using Labels for ItemTemplate  这是我得到的。

第一个问题是,正如你所看到的,瓷砖之间有空间我无法摆脱。您会在标记中注意到我尝试尽可能手动将边距和填充设置为0。空间仍在那里。

第二个问题是,你无法真正看到选择了哪个项目。选择底部的第3个字符和右侧的第2个字符,但标签覆盖蓝色。你只能在角色左边的空白处看到它。我不知道如何解决这个问题。

另一个潜在的问题是表现。该视图最终将具有过滤器,但是当所有过滤器都关闭时,有大约6500个项目要显示。当我只有一个基本的ListBox时,应用程序在运行时占用了大约28MB的RAM。当我使用WrapPanel添加ItemsPanelTemplate时,内存使用量跃升至约136MB。当我添加带有标签的ItemTemplate时,内存使用率跃升至183MB,更糟糕的是,窗口现在需要更长时间才能加载。

我已经尝试用TextBlocks替换标签,因为我读过它们的重量要轻得多。事情变得更快,内存使用量回落到130MB左右,但TextBlocks并不好。我无法将文字置于其中,或给它们边框。正如您在屏幕截图中看到的那样,所选项目搞砸了: Using TextBlocks in ItemTemplate

当然,我的计算机速度很慢,而且183MB不是终身的,但它仍然有点低效。我打算在这个应用程序中添加更多功能,如果这一件事占用了大量的RAM,那么最终的应用程序可能会成为一个无法使用的资源吸血鬼。另外,我相信我模仿的应用程序也是用.NET编写的(虽然我不确定它是否是WPF)并且在显示视图时只使用17.5MB的RAM。

还有另一种方法可以做到这一点,既有效又更容易定制?

谢谢。

编辑:

我找到了一种稍微好一些的方法。我完全删除了ItemTemplate,而是使用ItemContainerStyle:

 <ListBox.ItemContainerStyle>
                <Style TargetType="ListBoxItem">
                    <Style.Setters>
                        <Setter Property="BorderBrush" Value="Black"/>
                        <Setter Property="BorderThickness" Value="1"/>
                        <Setter Property="Width" Value="50"/>
                        <Setter Property="Height" Value="50"/>
                        <Setter Property="FontSize" Value="20"/>
                        <Setter Property="HorizontalContentAlignment" Value="Center" />
                        <Setter Property="VerticalContentAlignment" Value="Center" />
                    </Style.Setters>
                    <Style.Triggers>
                        <Trigger Property="IsSelected" Value="True" >
                            <Setter Property="FontWeight" Value="Bold" />
                            <Setter Property="Background" Value="SteelBlue" />
                        </Trigger>
                    </Style.Triggers>

                </Style>
            </ListBox.ItemContainerStyle>

这会产生更好的效果。瓷砖之间没有可见的空间,我可以自定义选定和取消选择的瓷砖的外观。 Using ItemContainerStyle

我唯一不知道该怎么办的是一条厚度为1像素的边框线。我得到两条厚度为1的线,导致厚度为2.我尝试将边距和填充设置为0和-1。没运气。奇怪的是,将BorderBrush设置为Black并将BorderThickness设置为0.5不会产生厚度为1的组合黑线,而是产生厚度为2的灰线。

与使用标签时相比,内存使用率略有下降至约150MB,但加载时间仍然很恶劣,因此我仍在寻找更好的解决方案。

编辑2:

我在边缘玩了一段时间,我终于把它钉了起来。我通过将ListBoxItem的边距设置为-0.5得到了正确的边框厚度,将图块稍微压缩在一起。我想保持这个问题,所以希望有人会提出一个更有效的解决方案。 UI一旦运行就会响应,但加载时间很糟糕。在使用我的应用程序期间,将重复填充ListBox,因为调整了过滤器并进行了查询。我希望这很快发生。此外,在我看来,内存使用率也不必要地高。

1 个答案:

答案 0 :(得分:0)

由于我没有足够的代表发表评论,会尝试回答,或者至少指出正确的方向。 1)厚度为2的原因是相邻边界连接各自的厚度。并且你使用-0.5边距使它们交叉,使得结果厚度为1.相反,你可以尝试设置右边和底边的边框厚度,如:

<Setter Property="BorderThickness" Value="0,0,1,1"/>

这意味着LeftSide = 0,Top = 0,RightSide = 1,Bottom = 1 thick。所以最左边的项目不会有左边框,最顶层的项目不会有顶边框。因此,相邻的边界不会使其厚度增加一倍。

2)并且因为内存使用过多而整体性能下降。当您使用WrapPanel for ItemsPanel时,您将丢弃UI虚拟化。因为通常非UI计算不需要花费太多时间首先考虑UI性能。尝试加载您的数据并在没有UI的情况下进行计算,我认为区别很明显。   我建议你为ListBox ItemsPanel使用某种VirtualizingWrapPanel。就个人而言,我使用这个更有经验的编码员提出的更正:

Original implementation

First correction

Second correction