Binding to DataContext outside current ItemsSource context

為{幸葍}努か 提交于 2019-12-19 02:23:29

问题


I have a DataSet bound to the Window.DataContext; I also have a 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>

Basically, I'm trying to bind the Header of that column to DataTable "Names", Column "Test", first row.

However, I can't get it right. Note that I can bind it fine outside the DataGrid. The Grid's ItemsSource changes the data context and I don't know how to refer outside to the original DataContext.

It seems that the binding succeeds; but the problem is that the current item (first row) of the Tables[Names] in the Window.DataContext got lost.

If I make the DataSet static and access it via {x:Static local:dataset} then things work fine. But I can't use static datasets because there will be multiple instances (multi-user).

Can anyone please point me in the right direction?


回答1:


I'm pretty sure you could do what you're trying to do by using RelativeSource binding.

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

I made a quick example at: http://bitbucket.org/claus/wpf-bindingoutsidedatacontext

It allows you to bind to the parent Window, which in my case has the viewmodel as datacontext (with the SomethingOutsideDataContext property on it).

You should be aware though, this will only work with WPF and not Silverlight - the 'FindAncestor, AncestorType' stuff has not been implemented in Silverlight yet... I'm not sure if there's another method, besides using static resources.




回答2:


Don't know if this will work for you situation, but you could try something like this: 1) Give your Window a Name attribute e.g. Name=ZeWindow. 2) Bind your DataGridTextBoxColumn Header like this:

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

So basically, instead of binding to the DataContext of the DataGrid, you bind to the DataContext of the UIElement with Name=ZeWindow.

P.S.: I'm pretty new to WPF, so this might not work with the Window, but I did something similar using UserControls




回答3:


This is the expected behaviour actually: The DataContext for DataGridCell is the entireRow.

so you have 3 solutions: either you add your binding in code behind like this:

in each Column's Constructor:

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

(you have to find a way to get the "thisColumnIndex". As far as I'm concerned, I add the columns right after I create them, si I simply put "dataGridOwner.Columns.Count" there).

or...

you can find a way to get the dataContext you want on each cell (tried that but it messes up badly when column/row virtualization is on)

or...

have a look there:

Binding a cell object's property to a DataGridCell in WPF DataGrid

I personally find the first one to be the better for my purpose (since I add my columns in code behind anyway), but this is really up to you in the end...


As far as columnHeaders are concerned (and only columnsHeaders, not rows), you might also explore the "DataTemplate" way:

set the columns' header to the Column itself (that way you set the column as DataContext for the header) and use a DataTemplate.

e.g.:

in each column class:

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;

and in your dataGrid's xaml, something like:

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

of course, my "MyDataGridColumnHeader" class contains definitions for all the properties referenced here.

hope this helps.



来源:https://stackoverflow.com/questions/3920040/binding-to-datacontext-outside-current-itemssource-context

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!