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:
https://docs.microsoft.com/en-us/archive/blogs/jaimer/forwarding-the-datagrids-datacontext-to-its-columns
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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With