Ширина столбца синхронизации WPF DataGrid

У меня есть два WPF Toolkit 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, но ни один из них не работает.

Любая помощь приветствуется.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
12
0
12 950
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Я пробовал это:

<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, но я все же считаю, что это должно быть, потому что 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);
}

Извините, но я не получил ваш код. Какие два первых определения? Методы? Они не похожи на метод, а параметры не имеют типа ...

Ignacio Soler Garcia 07.10.2011 17:05

@SoMoS - DataGridColumn.WidthProperty - это свойство зависимости. AddValueChanged - это метод расширения для свойства зависимости, аргументы, которые ему нужны, - это исходный объект и обработчик событий. Делегат, который вы видите в первых двух определениях, - это анонимный метод, обрабатывающий событие.

viggity 26.01.2012 18:04

Я нашел решение этой проблемы и очень крутое решение :-) Вы можете загрузить набор инструментов WPF и получить код DataGrid. Когда у вас есть код, все, что вам нужно сделать, это изменить класс DataGridColumn, чтобы он наследовал FrameworkElement вместо DependencyObject. Как только вы это сделаете - у вас останется только одна проблема: DataContext столбца не будет инициализирован, поскольку столбец не является частью логического дерева, добавление его в логическое дерево решит эту проблему. Сделать это можно так: Где OnColumnInitialization: private void OnColumnInitialization (отправитель объекта, EventArgs e) {
AddLogicalChild (отправитель); } Теперь, когда он является частью логического дерева, у вас есть тот же контекст данных, и вы можете использовать привязку к Свойство ширины. Если все привязаны к одной и той же ширине - у вас полная синхронизация ширины ваших столбцов. Это сработало для меня :-) Гили

Исправление ошибки в коде фреймворка мне не кажется «очень крутым решением». Это больше похоже на огромную боль.

Michael 03.06.2012 02:45

Вы можете использовать метод DataGridLayoutUpdated для управления другими объектами относительно ширины столбца.

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;
}

Если вы хотите привязать свойство ширины столбца в XAML, в двух DataGrid вам необходимо сделать следующее.

В первом DataGrid назовите DataGridTextColumn:

<DataGrid>
    <DataGrid.Columns>
        <DataGridTextColumn x:Name = "Col1"/>
    </DataGrid.Columns>
</DataGrid>

Во втором DataGrid добавьте DiscreteObjectKeyFrame, указывающий на вышеупомянутый столбец в качестве ресурса, и используйте следующее свойство Binding to 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>

Вторая сетка данных, ширина заголовка и ячейки, теперь синхронизируется с шириной заголовка первой сетки.

Другие вопросы по теме