Привязка к DataContext вне текущего контекста ItemsSource

У меня есть DataSet привязан к Window.DataContext; у меня тоже есть DataGrid:

<DataGrid ItemsSource={Binding Tables[Items]}>
    <DataGrid.Columns>
        <DataGridTextBoxColumn Header={Binding Path=DataContext.Tables[Names]/Test, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}} />
    </DataGrid.Columns>
</DataGrid>

По сути, я пытаюсь привязать заголовок этого столбца к DataTable "Имена", столбец "Тест", первая строка.

Однако я не могу понять это правильно. Обратите внимание, что я могу связать это отлично за пределами DataGrid. ItemsSource в Grid изменяет контекст данных, и я не знаю, как ссылаться на исходный DataContext.

Кажется, что связывание успешно; но проблема в том, что текущий элемент (первая строка) таблиц [Names] в Window.DataContext потерян.

Если я сделаю DataSet статическим и получу доступ к нему через {x:Static local:dataset}, тогда все будет хорошо. Но я не могу использовать статические наборы данных, потому что будет несколько экземпляров (многопользовательский).

Может кто-нибудь, пожалуйста, укажите мне в правильном направлении?

3 ответа

Я уверен, что вы можете сделать то, что вы пытаетесь сделать, используя RelativeSource связывание.

<DataGrid ItemsSource="{Binding StringCollection}" 
          AutoGenerateColumns="False">
  <DataGrid.Columns>
    <DataGridTextColumn Binding="{Binding}" />
    <DataGridTextColumn Binding="{
                          Binding RelativeSource={
                            RelativeSource FindAncestor, 
                            AncestorType={x:Type Window}},
                          Path=DataContext.SomethingOutsideDataContext}" />
  </DataGrid.Columns>
</DataGrid>

Я сделал быстрый пример по адресу: http://bitbucket.org/claus/wpf-bindingoutsidedatacontext

Это позволяет вам привязать к родительскому окну, которое в моем случае имеет viewmodel как datacontext (со свойством SomethingOutsideDataContext на нем).

Однако вы должны знать, что это будет работать только с WPF, а не с Silverlight - материал "FindAncestor, AncestorType" еще не был реализован в Silverlight... Я не уверен, есть ли другой метод, кроме использования статических ресурсов.

Это ожидаемое поведение на самом деле: DataContexт для DataGridCell это целый ряд.

Таким образом, у вас есть 3 решения: либо вы добавляете свою привязку в коде так:

в конструкторе каждого столбца:

string source = String.Format(CultureInfo.InvariantCulture, "[{0}].", thisColumnIndex);
base.Binding = new Binding(source + "Text");

(Вы должны найти способ получить "thisColumnIndex". Насколько я понимаю, я добавляю столбцы сразу после их создания, например, просто помещаю туда dataGridOwner.Columns.Count).

или же...

Вы можете найти способ получить требуемый dataContext в каждой ячейке (пробовал, но он плохо работает, когда включена виртуализация столбцов / строк)

или же...

посмотрите там:

Привязка свойства объекта ячейки к DataGridCell в WPF DataGrid

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


Что касается columnHeaders (и только columnsHeaders, а не строк), вы можете также изучить способ "DataTemplate":

установите заголовок столбца на сам столбец (таким образом вы установите столбец как DataContext для заголовка) и используйте DataTemplate.

например:

в каждом классе столбца:

private static DependencyProperty ColumnHeaderProperty = DependencyProperty.Register("ColumnHeader", typeof(MyDataGridColumnHeader), typeof(MyTextBoxColumn));
public MyDataGridColumnHeader ColumnHeader
{
    get { return (MyDataGridColumnHeader)(GetValue(ColumnHeaderProperty)); }
    set { SetValue(ColumnHeaderProperty, value); }
}

this.ColumnHeader = new MyDataGridColumnHeader();
Header = this;

и в xaml вашей dataGrid, что-то вроде:

<DataGrid.ColumnHeaderStyle>
    <Style TargetType="{x:Type DataGridColumnHeader}">
        <Style.Setters>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Stretch"/>
            <Setter Property="BorderThickness" Value="{Binding BorderThickness}" />
            <Setter Property="BorderBrush" Value="{StaticResource DataGridLinesBrush}" />
            <Setter Property="Background" Value="{StaticResource DataGridColumnHeaderBackground}" />

            <Setter Property="FontFamily" Value="{Binding ColumnHeader.Font.Family, TargetNullValue={StaticResource DefaultFontFamily}}" />
            <Setter Property="FontSize" Value="{Binding ColumnHeader.Font.Size, TargetNullValue={StaticResource DefaultFontSize}}" />
            <Setter Property="FontStyle" Value="{Binding ColumnHeader.Font.Style, TargetNullValue=Normal}" />
            <Setter Property="FontWeight" Value="{Binding ColumnHeader.Font.Weight, TargetNullValue=Bold}" />
            <Setter Property="Foreground" Value="{Binding ColumnHeader.Font.Brush, TargetNullValue={StaticResource DataGridColumnHeaderForeground}}" />

            <Setter Property="ContentTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <Grid Background="{Binding ColumnHeader.Background}">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <Image Name="LeftImage" Grid.Column="0" Stretch="None" Margin="3, 0, 0, 0" Source="{Binding ColumnHeader.LeftImage}" VerticalAlignment="Center"/>
                            <Image Name="RightImage" Grid.Column="2" Stretch="None" Margin="0, 0, 5, 0" Source="{Binding ColumnHeader.RightImage}" VerticalAlignment="Center"/>
                            <TextBlock Name="HeaderText"
                                       Grid.Column="1"
                                       VerticalAlignment="Center"
                                       HorizontalAlignment="Center"
                                       TextDecorations="{Binding ColumnHeader.Font.Decorations}"
                                       Text="{Binding ColumnHeader.Text}" />
                        </Grid>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style.Setters>
    </Style>
</DataGrid.ColumnHeaderStyle>

Конечно, мой класс "MyDataGridColumnHeader" содержит определения для всех свойств, на которые здесь ссылаются.

надеюсь это поможет.

Не знаю, сработает ли это в вашей ситуации, но вы можете попробовать что-то вроде этого: 1) Дайте вашему окну атрибут Name, например Name=ZeWindow. 2) Свяжите свой DataGridTextBoxColumn Заголовок как это:

<DataGridTextBoxColumn Header="{Binding Path=DataContext.Tables[Names]/Text, ElementName=ZeWindow}"/>

Так что в основном вместо привязки к DataContext из DataGridпривязываешься к DataContext из UIElement с именем = ZeWindow.

PS: я довольно новичок в WPF, так что это может не работать с окном, но я сделал нечто подобное, используя UserControls

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