views:

8698

answers:

4

I'm trying to build a data grid where one of the columns is a font name displayed in that font. Previously, I was working with a list box where I had defined the following template:

<TextBlock Text="{Binding Path=Name}" FontFamily="{Binding Path=Name}"/>

This worked just fine. So, I tweaked the data structure (Name became Font.Name) and moved onto a data grid to try this:

<dg:DataGridTextColumn Binding="{Binding Font.Name}" 
    FontFamily="{Binding Font.Name}" IsReadOnly="True" Header="Font"/>

Now the font names are all displayed in the default font, and I get this error:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or 
FrameworkContentElement for target element. 
BindingExpression:Path=Font.Name; DataItem=null; target element is 
'DataGridTextColumn' (HashCode=56915998); target property is 'FontFamily' 
(type 'FontFamily')

A few Google results dealing with custom controls suggest changing the property from DependencyObject to FrameworkElement, but I'd have to inherit DataGridTextColumn and define my own property to do so - there must be a better way.

I've tried several different approaches to the binding, including attempting to change just the font size with a distinct property in my data class (i.e., FontSize="{Binding FontSize}"). They've all resulted in the same error as above.

Anyone know what I'm doing wrong here?

Edit:

Thanks to Jared's reply, I found the following:

http://blogs.msdn.com/jaimer/archive/2008/11/22/forwarding-the-datagrid-s-datacontext-to-its-columns.aspx

The method looks sound, but I need to make a binding that references the correct element in the DataContext for each row, as opposed to sharing a single value for the entire column.

Code behind:

fontDataGrid.DataContext = from font 
    in new InstalledFontCollection().Families;

XAML:

Binding="{Binding Font.Name}"
FontFamily="{Binding (FrameworkElement.DataContext).Font.Name, 
    RelativeSource={x:Static RelativeSource.Self}}"

Using the above XAML clearly isn't correct, because DataContext is the entire collection of fonts. But I can't index the collection, since I don't know what the row number is (or do I?). Is there some approach I can use to achieve this?

And a secondary question - why does the Binding attribute seem to work just fine, even without the DataContext? Is it looking at ItemsSource instead?

+5  A: 

Take a look at the following blog post. It covers in detail the problem that you are seeing.

http://blogs.msdn.com/nickkramer/archive/2006/08/18/705116.aspx

Essentially the problem is that the DataGridTextColumn has no parent from which to inherit a Binding because it is not a part of the logical or visual tree. You must setup an inheritance context in order to get access to the binding information. The blog I referenced goes into detail about how to do this.

JaredPar
+1  A: 

Try

TextBlock.FontFamily="{Binding Font.Name}"

Sometimes the binding system has a problem finding where a property is declared so you need to give it some help.

Bryan Anderson
In this particular case, FontFamily isn't inherited from Control; it's a property in DataGridTextColumn.
Matthew Maravillas
My bad, I'll update it to TextBlock since that should be what it will use.
Bryan Anderson
Still no go, with same original error. I think Jared has the right cause.
Matthew Maravillas
+2  A: 

Jared's answer is correct, but I've found a concrete solution that's solved my problem.

http://blogs.msdn.com/vinsibal/archive/2008/12/17/wpf-datagrid-dynamically-updating-datagridcomboboxcolumn.aspx

Following this example, I changed my DataGridTextColumn definition to:

<dg:DataGridTextColumn Binding="{Binding Font.Name}" IsReadOnly="True" Header="Font">
    <dg:DataGridTextColumn.ElementStyle>
        <Style TargetType="TextBlock">
            <Setter Property="FontFamily" Value="{Binding Font.Name}" />
        </Style>
    </dg:DataGridTextColumn.ElementStyle>
</dg:DataGridTextColumn>

And I don't need to worry about the column inheriting the DataContext. This gives me the result I want.

Matthew Maravillas
A: 

Hi.How can I bind Header for DataGrid ? I try to set binding for a header, but I only got "System.Windows.Data.Binding" , what's wrong? Does the header support binding ? alt text

xiemails