WPF DataGrid Sync Widths
-
03-07-2019 - |
سؤال
لدي مجموعة أدوات WPF DataGrids
, ، أود أن يقوم المستخدم بتغيير حجم العمود الأول في الشبكة الأولى ، فإنه يقيم العمود الأول في الشبكة الثانية. لقد حاولت ربط عرض 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>
لقد حاولت أيضًا الربط Width
بدلاً من ActualWidth
, ، ولكن لا يعمل.
أي مساعدة يحظى بتقدير كبير.
المحلول
حسنًا ، لا أعتقد أنه من الممكن استخدام 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
S لا تستمد من FrameworkElement
ولكن بدلا من ذلك اشتق من DependencyObject
, ، ملزمة بهذه الطريقة غير متوفرة.
إذا كنت تريد ربط خاصية عرض العمود في XAML ، في 2 DataGrid
من عليك أن تفعل ما يلي.
في الاول DataGrid
اسم DataGridTextColumn
:
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn x:Name="Col1"/>
</DataGrid.Columns>
</DataGrid>
في الثانية DataGrid
أضف DiscreteObjectKeyFrame
مشيرا إلى العمود المذكور أعلاه كمورد ، واستخدم ما يلي Binding
إلى Width
خاصية على 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>
يتم الآن مزامنة بيانات البيانات الثانية ، الرأس وعرض الخلية ، مع عرض رأس الشبكة الأول.
لقد وجدت حلاً لهذه المشكلة ، وحلًا رائعًا إضافيًا :-) يمكنك تنزيل مجموعة أدوات WPF والحصول على رمز DataGrid. بمجرد حصولك على الكود ، كل ما عليك فعله هو تغيير فئة DataGridColumn إلى ورث الإطار الإطار بدلاً من الاعتماد. بمجرد القيام بذلك - يتم تركك لمشكلة واحدة فقط ، لن يتم تهيئة datacontext من العمود لأن العمود ليس جزءًا من الشجرة المنطقية ، فإن إضافته إلى الشجرة المنطقية سيحل هذا. يمكنك أن تفعل ذلك مثل هذا: حيث يكون oncolumninitialization: private void oncolumninitialization (كائن مرسل ، eventargs e) {
addlogicalchild (المرسل) ؛ } الآن بعد أن أصبح جزءًا من الشجرة المنطقية ، لديك نفس سياق البيانات ويمكنك استخدام الربط في خاصية العرض. إذا كانت جميعها مرتبطة بنفس العرض - لديك مزامنة كاملة لعرض الأعمدة. هذا عمل بالنسبة لي :-) جيلي