4

我需要创建一个简单的菜单/选择设计工具 - 想法是选择类别和更多选择,这些选择由所选类别过滤。最终这将在 Kiosk 风格的环境中运行。

我正在使用 MVVM,我的设计包含一个视图,其中包含两个 ItemsControls 内的 2 个网格 - 一个用于类别(2 行 x 10 列),一个用于选择(10 x 10)。在我的 ViewModel 中,这些 ItemsControl 都绑定到 ObservableCollection 对象,其中一些细节(标题、颜色等)绑定到部件的属性。DataTemplate 绑定到单独程序集中的项目类,因为我也想在信息亭应用程序中重用它们。

我使用“ModifiedBehaviours”类将我的网格对象上的左右单击映射到 ViewModel 拾取的命令,类似于此

如何将两个附加行为附加到一个 XAML 元素?

从我读过的内容来看,该设计似乎“干净”(此处对 MVVM 而言相对较新),因为视图的代码隐藏除了将 ViewModel 分配给窗口的 DataContext 之外没有任何内容,视图中没有 x:name= 标签和ViewModel 不直接与视图交互。

但是我确实有性能问题。

当用户单击一个类别时,我会创建一个新的 ObservableCollection,其中包含它的详细信息项目 - 我还在设计模式下填写空白,因此我最终得到 100 个选项,其中包含“右键单击编辑”的空白选项。

创建这个集合的时间很短 - 在 1.6 Ghz 上网本上 < 0.01 秒(Kiosk PC 会很慢,所以我在较慢的硬件上进行测试)。但是,一旦刷新了控件绑定到的集合,UI 大约需要 2 秒才能更新,这比我正在重新创建的旧应用程序要慢得多——这是用非常旧的 Delphi 编写的。

我尝试过各种各样的事情。首先,我通过删除一些渐变和其他内容来简化我的 XAML,以使其尽可能简单 - 最终归结为单个文本块。然后在刷新集合时,我单独创建它,然后将其分配给绑定的集合,以便更新“一次”发生。第三,我稍微打破了我的设计,并在窗口和网格的更新代码周围添加了 BeginInit() 和 EndInit()。

这些都没有丝毫改善。

以下做了 - 这导致了我的问题。

  1. 我从项目控件中删除了其中一个命令行为——尽管我需要左右单击。这必须将每个项目单元格(其中 100 个)的事件绑定到命令的事实是否会导致问题?

是否有另一种方法来左右单击每个网格单元?

  1. <- 这是我标记中的 2!我将项目(边框、文本块和命令)的 XAML 从单独的程序集中复制到主窗口 XAML 中。这给出了最大、最简单的改进,但我不明白为什么。

两者分别产生了影响,两者共同使表现“可以接受” - 虽然仍然非常缓慢。还有什么我可以看的吗?

我的控件看起来像这样(在单独的程序集中)。在任何人如上所述指出之前,我已经尝试删除很多内容,甚至将其删除为只是一个文本块。

<Control.Resources>
    <Style x:Key="MyBorderStyle" TargetType="Border">
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsSelected}" Value="True">
                <Setter Property="BorderBrush" Value="Red"/>
                <Setter Property="BorderThickness" Value="3"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding IsSelected}" Value="False">
                <Setter Property="BorderBrush" Value="{Binding BackColour}"/>
                <Setter Property="BorderThickness" Value="0"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Control.Resources>
<Grid>
    <Border Margin="1" Style="{StaticResource MyBorderStyle}" CornerRadius="8">
        <CommandBehaviour:CommandBehaviorCollection.Behaviors>
            <CommandBehaviour:BehaviorBinding Event="MouseLeftButtonDown" Command="{Binding DataContext.SelectLeftCommand, 
                RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" CommandParameter="{Binding ItemKey}"/>
            <CommandBehaviour:BehaviorBinding Event="MouseRightButtonDown" Command="{Binding DataContext.SelectRightCommand, 
                RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" CommandParameter="{Binding ItemKey}"/>
        </CommandBehaviour:CommandBehaviorCollection.Behaviors>
        <Border.Background>
            <LinearGradientBrush StartPoint="0.7,0" EndPoint="0.7,1">
                <GradientStop Color="{Binding BackColour}" Offset="0"/>
                <GradientStop Color="#33333333" Offset="1.5"/>
            </LinearGradientBrush>
        </Border.Background>
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{Binding ForeColour}" Text="{Binding Description}"/>
    </Border>
</Grid>

当我将它复制到主窗口中的 ItemsTemplate 并且性能改进时,我可以保留很多这些。

Statement-Rant WPF 的最大问题之一似乎是许多性能(和其他)问题都在某个地方“陷入困境” - 在幕后的代码中 - 这使得很难弄清楚正在发生的事情无需外部且有时相当复杂的性能和分析工具,也无需下载、安装和学习它们的时间。

真的是裤子。

呼吸......声明结束-咆哮

4

2 回答 2

1

刷新集合时,我单独创建它,然后将其分配给绑定的集合,以便更新“一次”发生。

如果只是刷新,那么您不应该创建新的ObservableCollection,而只是添加/删除项目;分配新的ObservableCollection会导致 WPF 引擎清除旧 UI 并再次呈现整个 UI,这将非常耗时。

还要检查绑定错误,因为它们也会影响性能,在调试模式下查看 Visual Studio 中的输出窗口,您将获得绑定错误的详细信息。这种情况经常发生在 RelativeSource 绑定中,并且在您的情况下也可能成为瓶颈。

于 2012-07-16T09:18:27.070 回答
1

那就是你的问题:

“当用户单击一个类别时,我会创建一个包含详细信息的新 ObservableCollection”

创建一个新集合的成本很高。创建一个受用户每次点击限制的新集合 - 成本非常高。

您可以尝试只创建一次集合并重新使用它吗?
(这只是一个有根据的赌注——但如果我是你,我的目标就是这个)

于 2012-07-16T07:47:20.340 回答