c# – WPF和MVVM的结构和性能

我需要创建一个简单的菜单/选择设计工具 – 我们的想法是选择一个类别和更多的选择,这些选择按选择的类别进行筛选.最终,这将在Kiosk风格的环境中运行.

我正在使用MVVM,我的设计包含一个视图,其中包含2个ItemsControls中的2个网格 – 一个用于类别(2行乘10列),另一个用于选择(10 x 10).在我的ViewModel中,这些ItemsControls都绑定到ObservableCollection对象,并且某些细节(标题,颜色等)绑定到零件的属性. DataTemplate绑定到单独程序集中的项类,因为我想在kiosk应用程序中重用它们.

我使用了“ModifiedBehaviours”类将我的网格对象的右键和左键点击映射到ViewModel选择的命令,类似于此

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

这个设计看起来很“干净”(我在这里看起来比较新),因为除了将ViewModel分配给窗口的DataContext,视图中没有x:name =标签之外,视图的代码隐藏在其中没有任何内容. ViewModel不会直接与视图相互影响.

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

当用户点击一个类别时,我创建了一个包含其详细项目的新ObservableCollection – 我还在设计模式中填入空白,所以我最终得到100个选项,空的那些选项中有“右键单击编辑”.

创建此集合的时间很短 – 首先,我通过删除一些渐变和其他东西来简化我的XAML,以使其尽可能简单 – 最终归结为单个文本块.
然后在刷新集合时,我单独创建它,然后将其分配给绑定的集合,以便更新“一次性”发生.
第三,我稍微破坏了我的设计,并在窗口和网格的更新代码周围添加了BeginInit()和EndInit().

这些都没有做出任何改进.

以下做了 – 这导致了我的问题.

>我从项目控件中删除了一个命令行为 – 我需要同时左右键单击.事实上,这必须将每个项目单元格(其中100个)的事件绑定到命令会导致问题吗?

是否有针对每个网格单元的右键和左键单击的替代方法?

>< – 我的标记中有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并且性能提升时,我可以留下很多这样的东西.

声明-咆哮
WPF最大的问题之一似乎是许多性能(和其他)问题在某个地方“陷入困境” – 在幕后的代码中 – 这使得很难在没有外部的情况下弄清楚正在发生的事情.有时相当复杂的性能和分析工具以及下载,安装和学习它们的时间.

这真的是裤子.

呼吸……
陈述结束 – 咆哮

最佳答案

when refreshing the collection I create it seperately and then assign
it to the bound one so the update happens “all at once”.

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

同时检查绑定错误,因为它们的性能也是如此,在调试模式下查看Visual Studio中的输出窗口,您将获得绑定错误的详细信息.使用RelativeSource绑定会发生很多事情,并且在您的情况下也可能成为瓶颈.

点赞