WPF反转DataGrid行列调整行为异常,求恢复正常交互方法
Hey there! I get that reversed DataGrid resizing headache—when you flip it, the row/column resizing gets all messed up because the control’s built-in logic still expects the original horizontal-row/vertical-column orientation. Let’s fix this step by step to get the same look and feel as a normal DataGrid, but reversed.
The Problem with Rotating the Whole DataGrid
If you’re using LayoutTransform or RenderTransform to rotate the entire DataGrid, you’re visually flipping it, but the control’s internal interaction logic (like resizing) still uses the original coordinate system. That’s why resizing feels backwards—your vertical drag is being interpreted as horizontal, and vice versa.
Solution: Rotate Content, Not the Whole Control
Instead of rotating the entire DataGrid, we’ll rotate just the content inside column headers, row headers, and cells. Then we’ll adjust the resizing handles and fix the event logic to match the reversed layout.
Step 1: Style Column Headers, Row Headers, and Cells
First, update the styles to rotate content while keeping the control’s hit-test areas aligned with the visual layout:
<DataGrid x:Name="ReversedDataGrid" ItemsSource="{Binding YourDataSource}"> <!-- Column Header Style: Rotate content and adjust resize gripper --> <DataGrid.ColumnHeaderStyle> <Style TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}"> <Setter Property="Width" Value="60"/> <!-- Set initial "height" (now width) --> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type DataGridColumnHeader}"> <Grid> <!-- Rotate content to appear upright in reversed layout --> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"> <ContentPresenter.LayoutTransform> <RotateTransform Angle="270"/> </ContentPresenter.LayoutTransform> </ContentPresenter> <!-- Adjust resize gripper direction --> <Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" Cursor="SizeNS"> <!-- Change cursor to vertical resize --> <Thumb.LayoutTransform> <RotateTransform Angle="270"/> </Thumb.LayoutTransform> </Thumb> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </DataGrid.ColumnHeaderStyle> <!-- Row Header Style (mirror column header changes) --> <DataGrid.RowHeaderStyle> <Style TargetType="{x:Type DataGridRowHeader}" BasedOn="{StaticResource {x:Type DataGridRowHeader}}"> <Setter Property="Height" Value="60"/> <!-- Set initial "width" (now height) --> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type DataGridRowHeader}"> <Grid> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"> <ContentPresenter.LayoutTransform> <RotateTransform Angle="270"/> </ContentPresenter.LayoutTransform> </ContentPresenter> <Thumb x:Name="PART_TopHeaderGripper" VerticalAlignment="Top" Cursor="SizeWE"> <!-- Change cursor to horizontal resize --> <Thumb.LayoutTransform> <RotateTransform Angle="270"/> </Thumb.LayoutTransform> </Thumb> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </DataGrid.RowHeaderStyle> <!-- Cell Style: Rotate content to match reversed layout --> <DataGrid.CellStyle> <Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource {x:Type DataGridCell}}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type DataGridCell}"> <Grid Background="{TemplateBinding Background}"> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"> <ContentPresenter.LayoutTransform> <RotateTransform Angle="270"/> </ContentPresenter.LayoutTransform> </ContentPresenter> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </DataGrid.CellStyle> </DataGrid>
Step 2: Fix Resizing Logic with Code-Behind
Even with styled grippers, the DataGrid still uses original orientation logic. We’ll override the DragDelta event to convert mouse movement to the correct resizing direction:
private void ReversedDataGrid_Loaded(object sender, RoutedEventArgs e) { // Hook up column resize grippers foreach (var column in ReversedDataGrid.Columns) { if (column.Header is DataGridColumnHeader header) { var gripper = header.Template.FindName("PART_RightHeaderGripper", header) as Thumb; if (gripper != null) { gripper.DragDelta += ColumnGripper_DragDelta; } } } // Hook up row resize grippers (optional, if you need row resizing) foreach (var item in ReversedDataGrid.Items) { if (ReversedDataGrid.ItemContainerGenerator.ContainerFromItem(item) is DataGridRow row) { var header = row.Header as DataGridRowHeader; if (header != null) { var gripper = header.Template.FindName("PART_TopHeaderGripper", header) as Thumb; if (gripper != null) { gripper.DragDelta += RowGripper_DragDelta; } } } } } private void ColumnGripper_DragDelta(object sender, DragDeltaEventArgs e) { var gripper = sender as Thumb; var header = gripper.TemplatedParent as DataGridColumnHeader; if (header?.Column != null) { // Convert vertical drag to column width adjustment (matches reversed layout) header.Column.Width = new DataGridLength(header.Column.Width.Value + e.VerticalChange); e.Handled = true; } } private void RowGripper_DragDelta(object sender, DragDeltaEventArgs e) { var gripper = sender as Thumb; var header = gripper.TemplatedParent as DataGridRowHeader; if (header?.DataContext is DataGridRow row) { // Convert horizontal drag to row height adjustment (matches reversed layout) row.Height = new DataGridLength(row.Height.Value + e.HorizontalChange); e.Handled = true; } }
Key Notes for Newbies
- Avoid full control rotation: It breaks nearly all built-in interactions (resizing, scrolling, selection) because the coordinate system gets flipped.
- Test incrementally: Start with column headers, then cells, then add resizing logic to avoid overwhelm.
- Adjust cursors: Make sure the resize cursor matches the visual direction (e.g.,
SizeNSfor vertical column resizing in reversed layout) to keep the UI intuitive.
内容的提问来源于stack exchange,提问作者vicky

