2016-01-19 30 views
9

mam niestandardową DataGrid którego komórka jest stylizowany jak poniżejWydajność podczas LayoutTransform jest stosowana do treści DataGridCell

<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> 

DataGrid jest stylizowany jak poniżej

<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> 

W datagrid wiersze będą dynamicznie dodawane przy użyciu wątku tła i może zawierać tysiące danych. Wystąpił problem z wydajnością z datagridem. Zużycie procesora wzrasta.

Dowiedziałem się, że powodem jest LayoutTransform. Jeśli ustawię z DataGridCell lub Width z Grid, która jest zawartością komórki, użycie procesora zostanie zmniejszone. Ale nie mogę tego zakodować na stałe. Szerokość powinna być ustawiona na podstawie długości treści.

Ustawianie wysokości Hardcoded:

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

Ustawianie szerokości Hardcoded:

<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> 

Najpierw próbowałem wiążące konwerter do której treść jest przekazywana i szerokość jest obliczany i wrócił do Width własności Grid. Powoduje to migotanie podczas dodawania nowych danych i zwiększenie wykorzystania procesora.

<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> 

drugie Wymieniłem LayoutTransform z RenderTransform. Szerokość komórki nie wzrośnie w oparciu o zawartość, która spowoduje wyświetlenie tylko części danych.

Po trzecie, próbowałem powiązać właściwość z Height z DataGridCell, która jest aktualizowana dynamicznie z najwyższą szerokością wartości w DataGridCell. Spowoduje to również zużycie procesora.

Czy jest jakaś inna alternatywa dla osiągnięcia wyniku LayoutTransform innego niż RenderTransform?

Czekamy na wszelkiego rodzaju dane wejściowe/sugestie. Dzięki.

+0

Czy otrzymujesz tekst komórki na poziomie 90 stopni, wszystko, co chcesz tutaj zrobić? Jeśli tak, to dlaczego nie zastosować jednej transformacji do całej siatki zamiast do każdej pojedynczej komórki? –

+0

@Chris W: Doceń swoją odpowiedź. Jeśli spojrzysz na styl datagridu, zobaczysz, że jego transformacja również. Wymaganie można osiągnąć tylko wtedy, gdy przekształcę zarówno datagrid, jak i komórkę. – Subru

+1

Powodem, dla którego LayoutTransform powoduje wysoki procesor, jest to, że każda zmiana układu wymaga przejścia całego układu - wszystkie komórki będą musiały ponownie obliczyć swoją szerokość i wysokość. Jeśli ustalisz szerokość/wysokość do określonego rozmiaru, wtedy będzie mniej kalkulacji (nie musisz mierzyć zawartości itp.). Impelementacja DataGrid jest mega powolna w odniesieniu do przepustki układu.RenderTransform po prostu renderuje piksele inaczej, bez zmiany układu, a tym samym lepszą wydajność. Jeśli chodzi o twoje aktualne pytanie - jak alternatywnie osiągnąć ten sam wynik - którego nie znam ... – Marko

Odpowiedz

0

Chciałbym spróbować przekształcić się w samej logiki renderowania. Nie próbowałem tego samemu, ale myślę, że warto się przekonać, czy dałoby to podobną wydajność do używania RenderTransform, a jednocześnie daje wynik, którego szukasz, jeśli użyjesz RotatedText zamiast swojego TextBlock z LayoutTransform:

public class RotatedText : FrameworkElement 
{ 
    public string Text { get; set; } 

    protected override void OnRender(DrawingContext drawingContext) 
    { 
     base.OnRender(drawingContext); 

     var ft = new FormattedText(Text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Calibri"), 12, Brushes.Black); 

     drawingContext.PushTransform(new RotateTransform(-90, 0, ft.Width)); 
     drawingContext.DrawText(ft, new Point(0, ft.Width)); 
     drawingContext.Pop(); 

     Width = ft.Height; 
     Height = ft.Width; 
    } 
}