WPF DataGrid Sync Column Widths
-
03-07-2019 - |
Pregunta
Tengo dos WPF Toolkit DataGrids
, me gustaría que cuando el usuario cambie el tamaño de la primera columna en la primera cuadrícula, cambie el tamaño de la primera columna en la segunda cuadrícula. He intentado vincular el ancho de DataGridColumn
en la segunda cuadrícula a la columna apropiada en la primera cuadrícula, pero no funciona. Preferiría usar todo xaml, pero también estoy de acuerdo con usar el código que está detrás.
<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>
También intenté enlazar a Width
en lugar de ActualWidth
, pero ninguno funciona.
Cualquier ayuda es muy apreciada.
Solución
Bueno, no creo que sea posible usar XAML directo, pero sigo pensando que debería hacerlo porque DataGridColumn
se deriva de DependencyObject
. Aunque encontré la manera de hacerlo programáticamente. No estoy emocionado por eso, pero funciona:
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);
}
Otros consejos
Puede utilizar el método DataGrid
LayoutUpdated
para manipular otros objetos con respecto a los anchos de columna.
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;
}
He intentado esto:
<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>
Sin embargo, parece que, dado que DataGridColumn
no procede de FrameworkElement
, sino que deriva de DependencyObject
, el enlace de esta manera no está disponible . Si desea vincular la propiedad Width de la columna en XAML, en 2 DataGrid
es necesario hacer lo siguiente.
En el primer DataGrid
nombre el DataGridTextColumn
:
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn x:Name="Col1"/>
</DataGrid.Columns>
</DataGrid>
En el segundo DataGrid
agregue un DiscreteObjectKeyFrame
que apunta a la columna mencionada anteriormente como un recurso, y use el siguiente Binding
para Ancho
en el DataGridTextColumn
que desea " enlace " ;:
<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>
Hice una solución rápida a esto al usar un comportamiento adjunto, Inspired by Ahmed responde arriba.
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>
Las segundas redes de datos, el encabezado y el ancho de la celda, ahora están sincronizadas con el primer ancho del encabezado de la cuadrícula.
Encontré una solución a este problema, y ??una solución extra genial :-)
Puede descargar el kit de herramientas de WPF y obtener el código de DataGrid.
Una vez que tenga el código, todo lo que tiene que hacer es cambiar la clase DataGridColumn para heredar FrameworkElement en lugar de DependencyObject.
Una vez que lo haga, solo tendrá un problema, el DataContext de la columna no se inicializará, ya que la columna no forma parte del árbol lógico;
Puedes hacerlo así:
Donde está la OnColumnInitialization:
Vacío privado OnColumnInitialization (objeto remitente, EventArgs e)
{
AddLogicalChild (remitente);
}
Ahora que forma parte del árbol lógico, tiene el mismo contexto de datos y puede usar el enlace en el
Propiedad de ancho.
Si todos están vinculados al mismo ancho, tiene una sincronización completa del ancho de sus columnas.
Esto funcionó para mí :-)
Gili