WPF Datagrid-Sync Spaltenbreiten
-
03-07-2019 - |
Frage
Ich habe zwei WPF Toolkit DataGrids
bekommt, würde Ich mag, so dass, wenn der Benutzer die erste Spalte in dem ersten Gitter ändert die Größe, es ändert die Größe die erste Spalte in dem zweiten Gitter. Ich habe versucht, in dem zweiten Gitter in der entsprechenden Spalte in dem ersten Raster, um die Breite der DataGridColumn
Bindung, aber es funktioniert nicht. Ich würde es vorziehen, alle XAML zu verwenden, aber ich bin gut mit hinter als auch unter Verwendung von Code.
<tk:DataGrid Width="100" Height="100">
<tk:DataGrid.Columns>
<tk:DataGridTextColumn x:Name="Column1" Width="50"/>
</tk:DataGrid.Columns>
</tk:DataGrid>
<tk:DataGrid Width="100" Height="100">
<tk:DataGrid.Columns>
<tk:DataGridTextColumn x:Name="Column1Copy" Width="{Binding Path=ActualWidth, ElementName=Column1}"/>
</tk:DataGrid.Columns>
</tk:DataGrid>
Ich habe auch versucht, anstatt Width
ActualWidth
Bindung, aber weder funktioniert.
Jede Hilfe wird sehr geschätzt.
Lösung
Nun, ich glaube nicht, dass es möglich ist, gerade XAML, aber ich fühle mich immer noch, wie es sollte, weil DataGridColumn
von DependencyObject
nicht ableiten. Ich habe einen Weg finden, es aber programmatisch zu tun. Ich bin nicht begeistert darüber, aber es funktioniert:
DataGridColumn.WidthProperty.AddValueChanged(upperCol, delegate
{
if (changing) return;
changing = true;
mainCol.Width = upperCol.Width;
changing = false;
});
DataGridColumn.WidthProperty.AddValueChanged(mainCol, delegate
{
if (changing) return;
changing = true;
upperCol.Width = mainCol.Width;
changing = false;
});
public static void AddValueChanged(this DependencyProperty property, object sourceObject, EventHandler handler)
{
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, property.OwnerType);
dpd.AddValueChanged(sourceObject, handler);
}
Andere Tipps
Sie können die DataGrid
LayoutUpdated
Methode verwenden, um andere Objekte in Bezug auf die Spaltenbreiten zu manipulieren.
private void dataGrid1_LayoutUpdated(object sender, EventArgs e)
{
for(int i = 0 ; i < dataGrid1.Columns.Count && i < dataGrid2.Columns.Count ; ++i)
dataGrid2.Columns[i].Width = dataGrid1.Columns[i].ActualWidth;
}
Ich habe versucht, dies:
<tk:DataGrid Width="100" Height="100" x:Name="Grid1" Grid.Column="0">
<tk:DataGrid.Columns>
<tk:DataGridTextColumn x:Name="Column1" Width="50"/>
</tk:DataGrid.Columns>
</tk:DataGrid>
<tk:DataGrid Width="100" Height="100" x:Name="Grid2" Grid.Column="1">
<tk:DataGrid.Columns>
<tk:DataGridTextColumn x:Name="Column1Copy" Width="{Binding Mode=TwoWay, Path=Columns[0].ActualWidth, ElementName=Grid1}"/>
</tk:DataGrid.Columns>
</tk:DataGrid>
Allerdings Es sieht aus wie seit DataGridColumn
s stammt nicht vom FrameworkElement
sondern aus DependencyObject
ableiten, auf diese Weise der Bindung ist nicht verfügbar.
Wenn Sie Spalte Width-Eigenschaft in XAML zu binden, in 2 DataGrid
als Sie folgendes zu tun haben.
Im ersten DataGrid
Namen des DataGridTextColumn
:
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn x:Name="Col1"/>
</DataGrid.Columns>
</DataGrid>
In der zweiten DataGrid
ein DiscreteObjectKeyFrame
hinzufügen zu der oben genannten Spalte als Ressource zeigt, und verwenden Sie die folgende Binding
Eigenschaft Width
auf dem DataGridTextColumn
Sie wollen „link“:
<DataGrid>
<DataGrid.Resources>
<DiscreteObjectKeyFrame x:Key="proxyCol1" Value="{Binding ElementName=Col1}"/>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Width="{Binding Path=Value.Width, Mode=TwoWay, Source={StaticResource proxyCol1}}"/>
</DataGrid.Columns>
</DataGrid>
habe ich eine schnelle Lösung dieses Problem ein angebrachtes Verhalten zu verwenden, inspiriert von Ahmed oben beantworten.
public class DataGridWidthSyncronizerBehavior
{
public static readonly DependencyProperty SyncronizeWidthWithProperty =
DependencyProperty.RegisterAttached("SyncronizeWidthWith",
typeof(DataGrid),
typeof(DataGridWidthSyncronizerBehavior),
new UIPropertyMetadata(null, SyncronizeWidthWithChanged));
public static void SetSyncronizeWidthWith(DependencyObject target, DataGrid value)
{
target.SetValue(SyncronizeWidthWithProperty, value);
}
public static DataGrid GetSyncronizeWidthWith(DependencyObject target)
{
return (DataGrid)target.GetValue(SyncronizeWidthWithProperty);
}
private static void SyncronizeWidthWithChanged(DependencyObject obj, DependencyPropertyChangedEventArgs dpargs)
{
if (!(obj is DataGrid sourceDataGrid))
return;
if (!(sourceDataGrid.GetValue(SyncronizeWidthWithProperty) is DataGrid targetDataGrid))
return;
void Handler(object sender, EventArgs e)
{
for (var i = 0; i < sourceDataGrid.Columns.Count && i < targetDataGrid.Columns.Count; ++i)
targetDataGrid.Columns[i].Width = sourceDataGrid.Columns[i].ActualWidth;
}
sourceDataGrid.LayoutUpdated -= Handler;
sourceDataGrid.LayoutUpdated += Handler;
}
}
XAML:
<DataGrid local:DataGridWidthSyncronizerBehavior.SyncronizeWidthWith="{Binding ElementName=SyncronizedHeaderGrid}">
<DataGrid.Columns>
<DataGridTextColumn Header="Header 1"
Binding="{Binding Item1}" />
<DataGridTextColumn Header="Header 2"
Binding="{Binding Item2}"/>
<DataGridTextColumn Header="Header 3"
Binding="{Binding Item3}"/>
</DataGrid.Columns>
</DataGrid>
<DataGrid x:Name="SyncronizedHeaderGrid">
<DataGrid.Columns>
<DataGridTextColumn Header="Header 1"
Binding="{Binding Item1}" />
<DataGridTextColumn Header="Header 2"
Binding="{Binding Item2}"/>
<DataGridTextColumn Header="Header 3"
Binding="{Binding Item3}"/>
</DataGrid.Columns>
</DataGrid>
Die Zweite Datagrids, Kopf- und Zellenbreite werden nun mit der ersten Gitter Kopfbreite synchronisiert.
fand ich eine Lösung für dieses Problem, und eine extra kühle Lösung :-)
Sie können das WPF-Toolkit herunterladen und den Code des Datagrid erhalten.
Sobald Sie den Code haben alles, was Sie tun müssen, ist die Datagrid Klasse ändern Framework statt DependencyObject zu erben.
Sobald Sie dies tun - Sie sind mit nur einem Problem verlassen, würde die Datacontext der Säule nicht initialisiert werden, da die Spalte nicht Teil der logischen Struktur ist, um es zu der logischen Struktur hinzugefügt würde dies lösen.
Sie können es tun, wie folgt:
Wo die OnColumnInitialization ist:
private void OnColumnInitialization (object sender, EventArgs e)
{
AddLogicalChild (Sender);
}
Jetzt, wo es ist ein Teil der logischen Struktur Sie denselben Datenkontext haben, und Sie können auf die Bindung verwenden
Width-Eigenschaft.
Wenn alle auf die gleiche Breite gebunden sind - haben Sie eine komplette Synchronisierung der Breite der Spalten.
Dieser arbeitete für mich :-)
Gili