WPF / Xaml Привязка заголовка столбца DataGrid и ячейки к различным значениям - PullRequest
4 голосов
/ 25 мая 2011

Следующий придуманный пример иллюстрирует мою проблему.

Моя ViewModel:

public class MyViewModel : ViewModel 
{
    public MyViewModel() 
    {
        var table = new DataTable("MyDatatable");
        table.Columns.Add("Some Val", typeof(double));
        table.Columns.Add("Ref");

        var row = table.NewRow();
        row["Some Val"] = 3.14;
        row["Ref"] = new {Title = "My Title", Description = "My Description"};
        table.Rows.Add(row);

        MyDataView = table.DefaultView;
    }

    DataView MyDataView { get; set; }   
}

Теперь моя проблема заключается в моем коде Xaml. Я хочу, чтобы один из заголовков моих столбцов был «Мой заголовок», а соответствующее значение строки - «Мое описание» ...

Мой Xaml:

<DataGrid ItemsSource="MyDataView" AutoGenerateColumns="False">
  <DataGrid.Columns>
    <!--This column works fine. -->
    <DataGridTextColumn Header="Some Val" Binding="{Binding 'Some Val'}" Width="50"/>
    <!--This column doesn't work... I'm looking for something similar to this: -->
    <DataGridTextColumn Header="{Binding Path='Ref.Title'}" Binding="{Binding Path='Ref.Description'}"/>
  </DataGrid.Columns>
</DataGrid>

Имеет ли это смысл? Заголовок второго столбца должен быть «Мой заголовок» со значением ячейки «Мое описание». Есть идеи, как это сделать?

1 Ответ

5 голосов
/ 25 мая 2011

Я считаю, что ваша вторая колонка должна быть:

<DataGridTextColumn Header="{Binding Path=['Ref'].Title}"
    Binding="{Binding Path=['Ref'].Description}"/>

EDIT:

Хорошо, похоже, DataGridTextColumn не будет наследовать DataContext от DataGrid. На самом деле это не FrameworkElement или Freezable, поэтому у него вообще не будет DataContext.

Столбец должен применяться к любому количеству строк, даже если у вас есть только 1 строка. Заголовок должен быть общим для всех строк, а привязка - для каждой строки. Но вы пытаетесь привязать оба к первому ряду.

Если у вас на самом деле было две строки с разными заголовками, то что должно отображаться в заголовке?

Для описания, следующие работы:

public class Test {
    public string Title { get; set; }
    public string Description { get; set; }
}

public class MyViewModel  {
    public MyViewModel() {
        var table = new DataTable("MyDatatable");
        table.Columns.Add("Some Val", typeof(double));
        table.Columns.Add("Ref", typeof(Test));

        var row = table.NewRow();
        row["Some Val"] = 3.14;
        row["Ref"] = new Test() { Title = "My Title", Description = "My Description" };
        table.Rows.Add(row);

        MyDataView = table.DefaultView;
    }

    public DataView MyDataView { get; set; }
}

Если XAML выглядит следующим образом:

<DataGrid ItemsSource="{Binding MyDataView}" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Some Val" Binding="{Binding 'Some Val'}" Width="50" />
        <DataGridTextColumn Header="Test" Binding="{Binding Path=[Ref].Description}" />
    </DataGrid.Columns>
</DataGrid>

Если вы удалите часть typeof(Test) при определении столбца, тогда Path=[Ref] будет ссылаться на строку, а не на объект типа Test. Поэтому я не думаю, что вы сможете использовать анонимные типы.

РЕДАКТИРОВАНИЕ JP Ричардсона:

Основываясь на ответе CodeNaked, мне напомнили о некоторых предыдущих проблемах, решение которых я знал, и они позволили мне полностью решить проблему.

Во-первых, можно привязать к анонимным типам данных. Модификация кода должна быть:

table.Columns.Add("Ref", typeof(object));

Вместо :

table.Columns.Add("Ref");

Как заявлено CodeNaked, без typeof (объекта) типом объекта по умолчанию считается строка.

Кроме того, как заявил CodeNaked, DataGridTextColumn не «знает» ни DataContext для строки, ни DataGrid. Для каждого объекта Window (типичный сценарий MVVM есть только один) должен иметь этот код:

private static void RegisterDataGridColumnsToDataContext() {
        FrameworkElement.DataContextProperty.AddOwner(typeof(DataGridColumn));
        FrameworkElement.DataContextProperty.OverrideMetadata(typeof(DataGrid), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnDataContextChanged)));
}

public static void OnDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
        DataGrid grid = d as DataGrid;
        if (grid != null)
            foreach (DataGridColumn col in grid.Columns)
                col.SetValue(FrameworkElement.DataContextProperty, e.NewValue);
}

А затем вызовите «RegisterDataGridColumnsToDataContext ()» перед отображением окна.

Измените MyViewModel, чтобы он выглядел следующим образом:

public class MyViewModel : ViewModelBase {
  ...
  public string ColumnTitle { get { return "My Title"; } }
  ...   
}

Модифицированный Xaml будет выглядеть так:

<DataGrid ItemsSource="{Binding MyDataView}" AutoGenerateColumns="False">
  <DataGrid.Columns>
    <DataGridTextColumn Header="Some Val" Binding="{Binding 'Some Val'}" Width="50" />
    <DataGridTextColumn Header="{Binding (FrameworkElement.DataContext).ColumnTitle, RelativeSource={x:Static RelativeSource.Self}}" Binding="{Binding Path=[Ref].Description}" />
  </DataGrid.Columns>
</DataGrid>

Примечание. Первоначально причина, по которой у меня был заголовок столбца в каждой строке, заключалась в том, что я не мог придумать другой способ привязать его к свойству 'Header' в моем DataGridTextColumn. Я планировал, чтобы свойство «Заголовок» каждого анонимного объекта было одинаковым. К счастью, интернет преобладает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...