LayoutTransform应用于DataGridCell内容时的性能问题

时间:2016-01-19 13:03:24

标签: wpf xaml datagrid

我有一个自定义数据网格,其单元格的样式如下

<Style x:Key="CellStyleBase"
           TargetType="{x:Type DataGridCell}">
        <Setter Property="Visibility"
                Value="Visible" />
        <Setter Property="Background"
                Value="{Binding RelativeSource={RelativeSource Self}, Path=Column.Header.CellBackground}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridCell}">
                    <Grid x:Name="BackgroundGrid"
                          Background="{TemplateBinding Background}">
                        <TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Content.Text}"
                                   HorizontalAlignment="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Column.Header.CellHorzontalAlignment}"
                                   VerticalAlignment="Center"
                                   FontWeight="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Column.Header.CellFontWeight}"
                                   Margin="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Content.Margin}"
                                   Padding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Content.Padding}" />
                        <Grid.LayoutTransform>
                            <TransformGroup>
                                <RotateTransform Angle="-90" />
                            </TransformGroup>
                        </Grid.LayoutTransform>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

数据网格的样式如下

<Style TargetType="{x:Type local:CustomDataGrid}">
        <Setter Property="BorderThickness"
                Value="1" />
        <!-- This is needed to force DG to have a non-default value.  Otherwise the DGR.DetailsVisibility cannot have a value of VisibleWhenSelected by default. -->
        <Setter Property="RowDetailsVisibilityMode"
                Value="VisibleWhenSelected" />
        <Setter Property="ScrollViewer.CanContentScroll"
                Value="true" />
        <Setter Property="VirtualizingPanel.IsVirtualizing"
                Value="True" />
        <Setter Property="VirtualizingPanel.VirtualizationMode"
                Value="Recycling" />
        <Setter Property="ScrollViewer.IsDeferredScrollingEnabled"
                Value="True" />
        <Setter Property="EnableColumnVirtualization"
                Value="True" />
        <Setter Property="EnableRowVirtualization"
                Value="True" />
        <Setter Property="LayoutTransform">
            <Setter.Value>
                <TransformGroup>
                    <RotateTransform Angle="90" />
                </TransformGroup>
            </Setter.Value>
        </Setter>
        <Setter Property="CellStyle"
                Value="{StaticResource CellStyleBase}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CustomDataGrid}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            SnapsToDevicePixels="True"
                            Padding="{TemplateBinding Padding}">
                        <ScrollViewer Focusable="false"
                                      Name="DG_ScrollViewer">
                            <ScrollViewer.Template>
                                <ControlTemplate TargetType="{x:Type ScrollViewer}">
                                    <Grid>
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="Auto" />
                                            <RowDefinition Height="*" />
                                            <RowDefinition Height="Auto" />
                                        </Grid.RowDefinitions>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto" />
                                            <ColumnDefinition Width="*" />
                                            <ColumnDefinition Width="Auto" />
                                        </Grid.ColumnDefinitions>

                                        <!--Left Column Header Corner -->
                                        <Border BorderBrush="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:CustomDataGrid}}, Path=HeaderBorderBrush}"
                                                BorderThickness="0,0,1,0"
                                                Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:CustomDataGrid}}, Path=HeaderBackground}"
                                                Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=CellsPanelHorizontalOffset}"
                                                Visibility="Collapsed" />
                                        <!--Column Headers-->
                                        <DataGridColumnHeadersPresenter Grid.Column="1"
                                                                        Name="PART_ColumnHeadersPresenter"
                                                                        Visibility="Visible">
                                            <DataGridColumnHeadersPresenter.Style>
                                                <Style TargetType="{x:Type DataGridColumnHeadersPresenter}">
                                                    <Setter Property="Template">
                                                        <Setter.Value>
                                                            <ControlTemplate TargetType="{x:Type DataGridColumnHeadersPresenter}">
                                                                <Border Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:CustomDataGrid}}, Path=NameHeaderBackground}">
                                                                    <ItemsPresenter />
                                                                </Border>
                                                            </ControlTemplate>
                                                        </Setter.Value>
                                                    </Setter>
                                                </Style>
                                            </DataGridColumnHeadersPresenter.Style>
                                        </DataGridColumnHeadersPresenter>

                                        <!--Column Header Splitter-->
                                        <GridSplitter Grid.Row="1"
                                                      Grid.Column="0"
                                                      Grid.ColumnSpan="2"
                                                      Height="4"
                                                      HorizontalAlignment="Stretch"
                                                      Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:CustomDataGrid}}, Path=NameHeaderBackground}"
                                                      Foreground="Transparent"
                                                      Cursor="SizeWE" />

                                        <!-- Line separates the column header with the content-->
                                        <Canvas Grid.Row="1"
                                                Grid.Column="0"
                                                Grid.ColumnSpan="2"
                                                Height="1.5"
                                                HorizontalAlignment="Stretch"
                                                VerticalAlignment="Bottom"
                                                Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:CustomDataGrid}}, Path=HorizontalGridLinesBrush}" />


                                        <!--DataGrid content-->
                                        <ScrollContentPresenter x:Name="PART_ScrollContentPresenter"
                                                                Grid.Row="2"
                                                                Grid.ColumnSpan="2"
                                                                CanContentScroll="{TemplateBinding CanContentScroll}" />

                                        <ScrollBar Grid.Row="0"
                                                   Grid.RowSpan="3"
                                                   Grid.Column="2"
                                                   Name="PART_VerticalScrollBar"
                                                   Orientation="Vertical"
                                                   Maximum="{TemplateBinding ScrollableHeight}"
                                                   ViewportSize="{TemplateBinding ViewportHeight}"
                                                   Value="{Binding Path=VerticalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
                                                   Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
                                                   Style="{StaticResource ScrollBarStyle}" />

                                        <Grid Grid.Row="3"
                                              Grid.Column="1">
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=NonFrozenColumnsViewportHorizontalOffset}" />
                                                <ColumnDefinition Width="*" />
                                            </Grid.ColumnDefinitions>
                                            <ScrollBar Grid.Column="1"
                                                       Name="PART_HorizontalScrollBar"
                                                       Orientation="Horizontal"
                                                       Maximum="{TemplateBinding ScrollableWidth}"
                                                       ViewportSize="{TemplateBinding ViewportWidth}"
                                                       Value="{Binding Path=HorizontalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
                                                       Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
                                                       Style="{StaticResource ScrollBarStyle}" />
                                        </Grid>
                                    </Grid>
                                </ControlTemplate>
                            </ScrollViewer.Template>
                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                        </ScrollViewer>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger SourceName="DG_ScrollViewer"
                                 Property="ComputedVerticalScrollBarVisibility"
                                 Value="Visible">
                            <Setter Property="IsShowingHorizontalScrollBar"
                                    Value="True" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

在datagrid中,行将使用后台线程动态添加,并且可以包含数千个数据。 datagrid存在性能问题。 CPU使用率不断增加。

我发现原因是LayoutTransform。如果我设置Height的{​​{1}}或DataGridCell Width这是单元格的内容,则CPU使用率会降低。但我不能硬编码。应根据内容的长度设置宽度。

设置硬编码高度:

Grid

设置硬编码宽度:

<Setter Property="Height"
            Value="50" />

首先,我尝试绑定一个传递内容的转换器,并计算宽度并返回<Grid x:Name="BackgroundGrid" Background="{TemplateBinding Background}" Width="50"> <TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Content.Text}" HorizontalAlignment="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Column.Header.CellHorzontalAlignment}" VerticalAlignment="Center" FontWeight="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Column.Header.CellFontWeight}" Margin="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Content.Margin}" Padding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Content.Padding}" /> <Grid.LayoutTransform> <TransformGroup> <RotateTransform Angle="-90" /> </TransformGroup> </Grid.LayoutTransform> </Grid> Width属性。这会导致闪烁,同时添加新数据并增加CPU使用率。

Grid

其次,我将<Grid x:Name="BackgroundGrid" Background="{TemplateBinding Background}" Width="{Binding Path=Content.Text,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Converter={StaticResource WidthConverter}}"> <TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Content.Text}" HorizontalAlignment="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Column.Header.CellHorzontalAlignment}" VerticalAlignment="Center" FontWeight="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Column.Header.CellFontWeight}" Margin="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Content.Margin}" Padding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}},Path=Content.Padding}" /> <Grid.LayoutTransform> <TransformGroup> <RotateTransform Angle="-90" /> </TransformGroup> </Grid.LayoutTransform> </Grid> 替换为LayoutTransform。单元格的宽度不会根据将导致仅显示部分数据的内容而增加。

第三,我尝试将属性绑定到RenderTransform的{​​{1}},Height动态更新DataGridCell中值的最大宽度。这也消耗了CPU使用率。

DataGridCell以外,还有其他替代方法可以达到LayoutTransform的结果吗?

期待任何形式的意见/建议。感谢。

1 个答案:

答案 0 :(得分:0)

我会尝试在渲染逻辑本身中进行转换。我自己没有试过这个,但我认为值得一试,看看这是否会提供与使用RenderTransform相似的性能,同时还会给你如果你使用{{1}的结果用RotatedText代替TextBlock

LayoutTransform