WPF DataGrid Syncの列幅
-
03-07-2019 - |
質問
2つのWPF Toolkit DataGrids
があるので、ユーザーが最初のグリッドの最初の列のサイズを変更すると、2番目のグリッドの最初の列のサイズが変更されるようにします。 2番目のグリッドの DataGridColumn
の幅を最初のグリッドの適切な列にバインドしようとしましたが、機能しません。すべてのxamlを使用したいのですが、コードビハインドも使用できます。
<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>
ActualWidth
ではなく Width
にバインドしようとしましたが、どちらも機能しません。
ご協力ありがとうございます。
解決
まあ、ストレートXAMLを使用することは可能だとは思いませんが、 DataGridColumn
は DependencyObject
から派生しているため、まだそうすべきだと感じています。しかし、プログラムでそれを行う方法を見つけました。私はそれについて興奮していませんが、うまくいきます:
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);
}
他のヒント
DataGrid
LayoutUpdated
メソッドを使用して、列幅に関する他のオブジェクトを操作できます。
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;
}
これを試しました:
<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>
ただし、 DataGridColumn
は FrameworkElement
から派生するのではなく、 DependencyObject
から派生するため、この方法でバインドすることはできません。
XAMLで列のWidthプロパティをバインドする場合、2つの DataGrid
で次の操作を行う必要があります。
最初の DataGrid
の名前は DataGridTextColumn
:
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn x:Name="Col1"/>
</DataGrid.Columns>
</DataGrid>
2番目の DataGrid
で、リソースとして上記の列を指す DiscreteObjectKeyFrame
を追加し、次の Binding
をに使用します&quot;リンク&quot;する
プロパティ: DataGridTextColumn
の幅
<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>
添付のビヘイビアを使用することで、上記のアーメドの回答に触発されて、これに対する簡単な解決策を実行しました。
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>
2番目のDataGrid、ヘッダーとセルの幅は、最初のグリッドヘッダーの幅と同期します。
この問題の解決策と、さらにクールな解決策を見つけました:-)
WPFツールキットをダウンロードして、DataGridのコードを取得できます。
コードを取得したら、DataGridColumnクラスを変更して、DependencyObjectではなくFrameworkElementを継承するだけです。
これを行うと、列は論理ツリーの一部ではないため、列のDataContextは初期化されず、論理ツリーに追加するだけでこれが解決されます。
次のようにできます:
OnColumnInitializationは次のとおりです。
private void OnColumnInitialization(オブジェクト送信者、EventArgs e)
{
AddLogicalChild(sender);
}
これは論理ツリーの一部であるため、同じデータコンテキストがあり、バインディングを使用できます
幅プロパティ。
すべてが同じ幅にバインドされている場合-列の幅が完全に同期されます。
これは私のために働いた:-)
ギリ