Chciałbym mieć WPG DataGrid z orientacją poziomą, czy ktoś zna rozwiązanie?Pozioma DataFrid WPF
Odpowiedz
Zrobiłem to wcześniej, ponieważ chcieliśmy móc używać tego samego kontrolera dla DataGrid
i PropertyGrid
. Wiele rzeczy musi zostać zmienionych (np. Wyrównanie, przewijanie, pozycjonowanie strzałek sortowania itp.). Jest wiele sposobów na napisanie całego rozwiązania, ale powinno zacząć. Jest to przykład z autogenerowanymi kolumnami TextColumns, ale można go łatwo zmodyfikować, aby korzystać z innych typów kolumn.
<ScrollViewer Name="c_dataGridScrollViewer"
Loaded="c_dataGridScrollViewer_Loaded"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<DataGrid x:Name="c_dataGrid"
HorizontalAlignment="Left"
VerticalAlignment="Top"
AutoGeneratedColumns="c_dataGrid_AutoGeneratedColumns"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="LayoutTransform">
<Setter.Value>
<TransformGroup>
<RotateTransform Angle="90"/>
</TransformGroup>
</Setter.Value>
</Setter>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.LayoutTransform>
<TransformGroup>
<RotateTransform Angle="-90"/>
</TransformGroup>
</DataGrid.LayoutTransform>
</DataGrid>
</ScrollViewer>
I gdy kolumny są generowane odwrócić ich pozycji i obraca TextBlocks i otaczaniem (Jest to lepsze, niż obrót DataGridCell
chodzi o położenie, plama etc.)
private void c_dataGridScrollViewer_Loaded(object sender, RoutedEventArgs e)
{
// Add MouseWheel support for the datagrid scrollviewer.
c_dataGrid.AddHandler(MouseWheelEvent, new RoutedEventHandler(DataGridMouseWheelHorizontal), true);
}
private void DataGridMouseWheelHorizontal(object sender, RoutedEventArgs e)
{
MouseWheelEventArgs eargs = (MouseWheelEventArgs)e;
double x = (double)eargs.Delta;
double y = c_dataGridScrollViewer.VerticalOffset;
c_dataGridScrollViewer.ScrollToVerticalOffset(y - x);
}
private void c_dataGrid_AutoGeneratedColumns(object sender, EventArgs e)
{
TransformGroup transformGroup = new TransformGroup();
transformGroup.Children.Add(new RotateTransform(90));
foreach (DataGridColumn dataGridColumn in c_dataGrid.Columns)
{
if (dataGridColumn is DataGridTextColumn)
{
DataGridTextColumn dataGridTextColumn = dataGridColumn as DataGridTextColumn;
Style style = new Style(dataGridTextColumn.ElementStyle.TargetType, dataGridTextColumn.ElementStyle.BasedOn);
style.Setters.Add(new Setter(TextBlock.MarginProperty, new Thickness(0, 2, 0, 2)));
style.Setters.Add(new Setter(TextBlock.LayoutTransformProperty, transformGroup));
style.Setters.Add(new Setter(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Center));
Style editingStyle = new Style(dataGridTextColumn.EditingElementStyle.TargetType, dataGridTextColumn.EditingElementStyle.BasedOn);
editingStyle.Setters.Add(new Setter(TextBox.MarginProperty, new Thickness(0, 2, 0, 2)));
editingStyle.Setters.Add(new Setter(TextBox.LayoutTransformProperty, transformGroup));
editingStyle.Setters.Add(new Setter(TextBox.HorizontalAlignmentProperty, HorizontalAlignment.Center));
dataGridTextColumn.ElementStyle = style;
dataGridTextColumn.EditingElementStyle = editingStyle;
}
}
List<DataGridColumn> dataGridColumns = new List<DataGridColumn>();
foreach (DataGridColumn dataGridColumn in c_dataGrid.Columns)
{
dataGridColumns.Add(dataGridColumn);
}
c_dataGrid.Columns.Clear();
dataGridColumns.Reverse();
foreach (DataGridColumn dataGridColumn in dataGridColumns)
{
c_dataGrid.Columns.Add(dataGridColumn);
}
}
Uprościliśmy nieco wcześniejsze rozwiązanie. Nie lubię czarnej magii z dodatkowym scrollviewerem, więc jej nie używam. Zamiast tego używam dodatkowej transformacji skali.
<DataGrid.LayoutTransform>
<TransformGroup>
<RotateTransform Angle="-90"/>
<ScaleTransform ScaleX="1" ScaleY="-1" />
</TransformGroup>
</DataGrid.LayoutTransform>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}"
BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
<Setter Property="LayoutTransform">
<Setter.Value>
<TransformGroup>
<RotateTransform Angle="-90"/>
<ScaleTransform ScaleX="1" ScaleY="-1" />
</TransformGroup>
</Setter.Value>
</Setter>
</Style>
</DataGrid.ColumnHeaderStyle>
W przypadku predefiniowanej listy colums możliwe jest transfom komórki zawartość bezpośrednio w XAML:
<Style x:Key="TextCellStyle" TargetType="{x:Type TextBlock}">
<Setter Property="LayoutTransform">
<Setter.Value>
<TransformGroup>
<RotateTransform Angle="-90"/>
<ScaleTransform ScaleX="1" ScaleY="-1" />
</TransformGroup>
</Setter.Value>
</Setter>
</Style>
Pozwala to całkowicie uciec codebehind.
Znalazłem to podejście bardzo użyteczne, ja jednak zrobił obrót i mirroring:
TransformGroup transformGroup = new TransformGroup();
transformGroup.Children.Add(new RotateTransform(90));
transformGroup.Children.Add(new MatrixTransform(-1, 0, 0, 1, 0, 0));
lub w XAML:
<!-- we rotate the whole DataGrid by -90 degree and then mirror via y-Axis so that it is docked vertically to the left side-->
<DataGrid.LayoutTransform>
<TransformGroup>
<RotateTransform Angle="90"/>
<MatrixTransform Matrix="-1,0,0,1,0,0"/>
</TransformGroup>
</DataGrid.LayoutTransform>
Używając mirroring Mam pole na końcu lista kolumn u dołu zamiast u góry.
Naprawdę stoję tu na ramionach gigantów :-), ale mam dodatkowe ulepszenie.
@dimaKudr zasugerował sposób przekształcania predefiniowanych kolumn bez kodu z tyłu, a @FrankE uściślił kolejność kolumn. To, co dodaję, to sposób przekształcania kolumn generowanych automatycznie (AutoGenerateColumns="True"
) za pomocą szablonu DataGrid.CellStyle
. Więc kompletne (i dość eleganckie) rozwiązanie to:
<DataGrid ItemsSource="{Binding YourObservableCollection}"
AutoGenerateColumns="True"
AutoGeneratingColumn="OnAutoGeneratingColumn">
<DataGrid.LayoutTransform>
<TransformGroup>
<RotateTransform Angle="90"/>
<MatrixTransform Matrix="-1,0,0,1,0,0"/>
</TransformGroup>
</DataGrid.LayoutTransform>
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}"
BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
<Setter Property="LayoutTransform">
<Setter.Value>
<TransformGroup>
<RotateTransform Angle="-90"/>
<ScaleTransform ScaleX="1" ScaleY="-1" />
</TransformGroup>
</Setter.Value>
</Setter>
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="LayoutTransform">
<Setter.Value>
<TransformGroup>
<RotateTransform Angle="-90"/>
<ScaleTransform ScaleX="1" ScaleY="-1" />
</TransformGroup>
</Setter.Value>
</Setter>
</Style>
</DataGrid.CellStyle>
</DataGrid>
Dzięki! Działa całkiem nieźle, poziomy pasek przewijania po włączeniu pojawia się u góry (co należy się spodziewać), a zmiana rozmiaru nagłówka jest dziwna (również można się tego spodziewać), ale jest to dobry punkt wyjścia dla mnie. Czy masz szansę na opublikowanie całego rozwiązania? Byłoby to bardzo doceniane;) – eriksmith200
Przepraszam, nie mogę. Jest wbudowany w rozwiązanie, które jest własnością mojej poprzedniej firmy. Mogę Ci pomóc w szczegółach, jeśli publikujesz pytania, ale nie mogę przesłać całego rozwiązania. Powodzenia! –
OK dziękuję, na razie wystarczy, że prototypuję jakiś interfejs użytkownika :) – eriksmith200