Привязка DataGridColumn в коде - PullRequest
       27

Привязка DataGridColumn в коде

1 голос
/ 09 августа 2010

Кто-нибудь знает, как я могу сделать эквивалентную привязку XAML в коде?

<DataGrid ... >
    <DataGrid.Columns>
        <DataGridTextColumn 
            Binding="{Binding Description}"  <=== set in code **
        />
    </DataGrid.Columns>
</DataGrid>

Приветствия,
Berryl

=== ОБНОВЛЕНИЕ ====

Похоже, что метод, который я искал, это DataGridColumn.GenerateElement

Если это так, то в центре этого вопроса теперь находится вопрос о том, как правильно установить привязку.Причина, по которой я хочу сделать этот код, состоит в том, что моя сетка имеет 7 столбцов, которые визуально идентичны и данные которых можно узнать по индексу.

Поэтому я хочу иметь возможность упростить xaml с помощью подкласса DataGridTextColumnкоторый имеет свойство index и просто имеет:

<DataGrid ... >
    <DataGrid.Columns >
        <local:DayOfWeekColumn Index="0" />
        <local:DayOfWeekColumn Index="1" />
        ....
        <local:DayOfWeekColumn Index="7" />
    </DataGrid.Columns >
</DataGrid >

=== ПЕРЕСМОТРЕННЫЙ ВОПРОС ===

Предполагая, что само связывание является логически и синтаксически корректным, что должно соответствовать параметрам для BindingOperations.SetBinding be ??

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) {
        var activity = (ActivityViewModel)dataItem;
        var cellData = activity.Allocations[Index];
        var b = new Binding
                {
                    Source = cellData,
                    UpdateSourceTrigger = UpdateSourceTrigger.LostFocus,
                    Converter = new AllocationAmountConverter()
                };


        BindingOperations.SetBinding(??, ??, b);
        return ??;
    }

=== РЕДАКТИРОВАТЬ для ARAN =====

Сейчас я не переопределяю GenerateElement, а скорее пытаюсь получить статический помощник для установки моей привязкидля меня.Помощник необходим в любом случае, чтобы компенсировать неспособность связать содержимое заголовка в текущей реализации MSFT DataGrid.

По сути, идея состоит в том, чтобы перехватить DC из сетки и использовать его по мере необходимости на каждом изстолбцы, в данном случае это содержимое заголовка, стиль ячейки и привязка.Вот код:

public class TimesheetDataGridColumnContextHelper
{

    static TimesheetDataGridColumnContextHelper() {
        FrameworkElement.DataContextProperty.AddOwner(typeof (DataGridTextColumn));
        FrameworkElement.DataContextProperty.OverrideMetadata(
            typeof (DataGrid), 
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, OnDataContextChanged));
    }

    public static void OnDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var grid = d as DataGrid;
        if (grid == null || !grid.Name.Equals("adminActivityGrid")) return;

        foreach (var col in grid.Columns) {

            var dowCol = col as DayOfTheWeekColumn;
            if (dowCol == null) continue;

            var context = (IActivityCollectionViewModelBase) e.NewValue;
            var index = Convert.ToInt32(dowCol.DowIndex);

            _setHeader(dowCol, context, index);

            var editStyle = (Style) grid.FindResource("GridCellDataEntryStyle");
            dowCol.CellStyle = editStyle;

            _setBinding(dowCol, index, context);

        }
    }

    private static void _setBinding(DayOfTheWeekColumn dowCol, int index, IActivityCollectionViewModelBase context) {
        dowCol.Binding = new Binding
                         {
                             Path = new PropertyPath(string.Format("Allocations[{0}]", index)),
                             UpdateSourceTrigger = UpdateSourceTrigger.LostFocus,
                             Converter = new AllocationAmountConverter()
                         };
    }

    private static void _setHeader(DataGridColumn col, IActivityCollectionViewModelBase context, int index)
    {
        var date = context.HeaderDates[index];
        var tb = new TextBlock
                 {
                     Text = date.ToString(Strings.ShortDayOfWeekFormat),
                     ToolTip = date.ToLongDateString()
                 };
        col.Header = tb;
    }

}

}

Все работает кроме Связывание.Я не могу сказать, связано ли это с тем, что моя привязка как-то неправильна (хотя я не получаю очевидных ошибок) или это не подходящее место для ее установки.Когда я его запускаю, столбцы сетки просто пусты.

Есть идеи ??

Приветствия,
Берриль

=== ИСПРАВЛЕНО!===

Логика в последнем обновлении была на самом деле правильной, но, заблудившись во внутренностях DataGrid, я пропустил, что в моем Binding.Path отсутствует свойство, с которым нужно связываться!Благодарим Арана за понимание проблемы, понимание того, что переопределения GenerateElement не были необходимы, и обнаружение того, что источник привязки не должен быть установлен.

Ответы [ 2 ]

5 голосов
/ 09 августа 2010

Ты всегда делаешь невероятные биты сетки, а, Берил?

Сделай пару вещей.Используйте отражатель , чтобы посмотреть на реализацию GenerateElement в DataGridTextColumn.(Программисты .NET живут в рефлекторе)

Теперь ответим:

В таблице данных каждый столбец не является частью визуального дерева.Столбец имеет два метода GenerateElement и GenerateEditingElement.Эти методы возвращают средство просмотра и редактор для ячейки соответственно.В приведенном выше методе вы не создаете средство просмотра, которое, вероятно, будет TextBlock.

из отражателя, реализация GenerateElement, как показано ниже, обратите внимание, что первое, что они делают, это создают средство просмотра для ячейки.

protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
    TextBlock e = new TextBlock();
    this.SyncProperties(e);
    base.ApplyStyle(false, false, e);
    base.ApplyBinding(e, TextBlock.TextProperty);
    return e;
}

Когда у вас есть текстовый блок, вы можете использовать строку ниже, чтобы установить привязку к нему.

BindingOperations.SetBinding(textBlock, TextBlock.TextProperty, binding);

Однако я не уверен, что вам действительно нужно переопределить GenerateElement и GenerateEditingElementчтобы получить желаемый эффект.Я думаю, что вы можете переопределить свойство Binding базового класса и просто изменить привязку там своим дополнительным полем, когда оно будет установлено.Это будет означать, что все остальное будет работать, и вы не будете удалять функциональность из своей колонки.Еще раз было бы полезно просканировать отражатель, глядя на класс DataGridBoundColumn (абстрактный базовый класс).

Я делаю что-то похожее в одном из наших столбцов всякий раз, когда устанавливается привязка, я изменяю привязку буфера обмена, добавляя дополнительныйсвойство, поэтому я могу эффективно копировать и вставлять.

РЕДАКТИРОВАТЬ: Обновить ... это, вероятно, другой вопрос, но ..

Вы явно устанавливаете источник привязки в вашем методе setBinding.В сетке источником привязки являются данные, содержащиеся в строке.Вы устанавливаете его, что означает, что он будет одинаковым для каждой строки.Вы можете применить эти классные привязки без свойства источника до того, как будет задан контекст данных, источник станет элементом в каждой строке, и ваша привязка должна отражать индекс в свойстве, которое содержится в каждой строке.

0 голосов
/ 09 августа 2010

Исходя из MSDN , похоже, что первый параметр SetBinding() должен быть элементом управления, для которого вы хотите отобразить привязку в (this в этом случае, предполагая, что GenerateElement() являетсячлен класса DayOfWeekColumn), а вторым свойством является свойство, к которому привязываются данные.Я не очень часто использовал WPF DataGrid, но я не видел ничего похожего на текстовое свойство для установки.

Я вижу, что DataGridTextColumn имеет свойство Binding, хотя,Может быть, это поможет установить привязку, созданную вами выше?

...