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 Data开发者_高级运维Grid. 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?
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.
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
This is the expected behaviour actually: The DataContex
t 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.
精彩评论