Larghezze di colonna WPF DataGrid Sync
-
03-07-2019 - |
Domanda
Ho due WPF Toolkit DataGrids
, vorrei che quando l'utente ridimensionasse la prima colonna nella prima griglia, ridimensionasse la prima colonna nella seconda griglia. Ho provato ad associare la larghezza di DataGridColumn
nella seconda griglia alla colonna appropriata nella prima griglia, ma non funziona. Preferirei usare tutto xaml, ma sto bene anche usando il codice dietro.
<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>
Ho anche provato a legare a Width
anziché ActualWidth
, ma nessuno dei due funziona.
Qualsiasi aiuto è molto apprezzato.
Soluzione
Beh, non penso che sia possibile usare XAML direttamente, ma mi sento ancora come dovrebbe perché DataGridColumn
deriva da DependencyObject
. Ho trovato un modo per farlo programmaticamente però. Non ne sono entusiasta, ma funziona:
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);
}
Altri suggerimenti
Puoi usare il metodo DataGrid
LayoutUpdated
per manipolare altri oggetti riguardanti la larghezza delle colonne.
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;
}
Ho provato questo:
<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>
Tuttavia, sembra che poiché DataGridColumn
non derivano da FrameworkElement
ma derivano invece da DependencyObject
, l'associazione in questo modo non è disponibile .
Se si desidera associare la proprietà Width della colonna in XAML, in 2 DataGrid
è necessario eseguire le seguenti operazioni.
Nel primo DataGrid
denominare DataGridTextColumn
:
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn x:Name="Col1"/>
</DataGrid.Columns>
</DataGrid>
Nel secondo DataGrid
aggiungi un DiscreteObjectKeyFrame
che punta alla colonna sopra menzionata come risorsa e usa il Binding
seguente in Proprietà
su DataGridTextColumn
che vuoi " 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>
Ho fatto una rapida soluzione a questo usando un comportamento associato, ispirato dalla risposta Ahmed sopra.
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>
Il Second DataGrids, intestazione e larghezza della cella, è ora sincronizzato con la prima larghezza dell'intestazione della griglia.
Ho trovato una soluzione a questo problema e una soluzione davvero interessante :-)
È possibile scaricare il toolkit WPF e ottenere il codice di DataGrid.
Una volta che hai il codice, tutto ciò che devi fare è cambiare la classe DataGridColumn per ereditare FrameworkElement invece di DependencyObject.
Una volta che lo fai - ti rimane solo un problema, il DataContext della colonna non verrà inizializzato poiché la colonna non fa parte dell'albero logico, aggiungendolo all'albero logico risolverebbe questo.
Puoi farlo in questo modo:
Dove si trova OnColumnInitialization:
void privato OnColumnInitialization (mittente oggetto, EventArgs e)
{
AddLogicalChild (mittente);
}
Ora che fa parte dell'albero logico, hai lo stesso contesto di dati e puoi usare l'associazione su
Proprietà larghezza.
Se tutti sono associati alla stessa larghezza, hai una sincronizzazione completa della larghezza delle colonne.
Questo ha funzionato per me :-)
Gili