【问题标题】:Structure and Performance with WPF and MVVMWPF 和 MVVM 的结构和性能
【发布时间】:2012-07-16 07:25:32
【问题描述】:

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

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

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

How can I attach two attached behaviors to one XAML element?

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

但是我确实遇到了性能问题。

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

创建这个集合的时间很短——在 1.6 Ghz 上网本上

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

这些都没有丝毫改善。

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

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

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

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

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

<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 时,我可以保留很多内容,并且性能改进持续存在。

声明-咆哮 WPF 的最大问题之一似乎是许多性能(和其他)问题都在某个地方“陷入困境” - 在幕后的代码中 - 这使得在没有外部和有时非常复杂的性能和分析工具以及下载、安装和学习它们的时间。

真的是裤子。

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

【问题讨论】:

  • 您是否尝试过重新设计以使您无需在绑定中使用RelativeSource

标签: c# .net wpf mvvm


【解决方案1】:

刷新集合时,我单独创建它然后分配 将其绑定到一个,因此更新“一次”发生。

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

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

【讨论】:

  • 感谢您的回复。我选择了该方法,因为我看到的建议是将原始集合设置为 null(以停止任何绑定控件刷新),构建新集合,然后一次性分配它。否则每次更新、添加或删除不会导致绑定刷新吗? - 编辑,无论如何我都会尝试一下,因为这是一个建议。
  • 好的 - 我很困惑 - 这似乎有效!非常好,非常感谢 - 稍后将标记为答案。回顾一下我正在做的事情是创建第二个集合,然后根据插入和更新将触发刷新的想法将其分配给发布的属性,并且最好进行一次更新。现在将其更改为覆盖原始集合(它们的大小相同,因此我可以使用项目的索引来执行此操作)并且它会在
  • @Morph:另外,不要忘记virtualization。对于框架内大多数基于 ItemsControl 的 UI 元素,您可以 turn on virtualization。使用虚拟化,未显示的 UI 元素不会添加到可视化树中,从而减少了在将新元素添加到绑定集合时更新 UI 所花费的时间。
  • @Will - 谢谢 - 我会看看,但是控件内的大多数项目是 120 (12x10) - 除此之外,网格方块变得太小,用户无法看到或者用粗大的手指敲击;)我会看看我必须使用的几个列表。
【解决方案2】:

那是你的问题:

"当用户点击一个类别时,我创建一个新的 包含细节项的 ObservableCollection"

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

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

【讨论】:

  • 也为这个道歉 +1 - 它,我只是在看了另一个之后才发现时间。这是相同的答案,确实是正确的。
猜你喜欢
  • 2011-03-28
  • 1970-01-01
  • 2013-09-20
  • 1970-01-01
  • 1970-01-01
  • 2013-06-28
  • 1970-01-01
  • 2013-10-16
  • 1970-01-01
相关资源
最近更新 更多