Introduction
In this tip we will talk about how to apply same Fonts style to TextBlock
and Glyphs
controls from code behind. I am trying to apply the FontFamily
value for both controls from code behind. So this will give you better idea about how to use fall-back value and other fonts related property. This will also explain how to bind style
setter value also.
Background
If requirement is to apply the same fonts value (FontFamily
, Foreground,FontSize
) to all the TextBlocks
in the project.
Then it can simply be done by changing the value directly form XAML code. If we need it on the run time, it can be done from code behind.
Now the second scenario is, I have two different controls Glyphs
and TextBlock
. Both control have different properties for font value.
For example, Glyphs
have FontUri
property whereas TextBlock
has FontFamily
. Then if we try to use the same approach
as we have discussed above, it will result in very lengthy code to change the fonts from code behind at run time, but the value to both property has been same.
Usually this is done by just binding the different value to both controls, e.g.,
<Glyphs Name="glyphs" FontUri="C:\WINDOWS\Fonts\Arial.TTF" FontRenderingEmSize="50"/>
<TextBlock Name="text" FontFamily="Arial" FontSize = "50"/>
If we want to change these properties from code behind. We have to do something like this.
glyphs.FontUri = new Uri(@"C:\WINDOWS\Fonts\Arial.TTF");
glyphs.FontRenderingEmSize = 50.0;
text.FontFamily = new FontFamily("Arial");
text.FontSize = "50";
One solution is to apply the style to both control and bind the setter value to the same property variable. This will reduce the lines of code and give better extensiblity
and understanding.
Using the code
Now lets start with example, Here I want to update the properties like FontUri
, Fill
,
FontRenderingEmSize
, UnicodeString
for Glyphs
. Similarly for TextBlock
. I want to update the property values such
as FontFamily
, Foreground
, FontSize
, Text
, etc. So I took the two different styles in XAML.
<Style x:Key="ModelBodyGlyphsStyle" TargetType="Glyphs">
<Setter Property="FontUri" Value="{Binding ModelBodyFontFamily}"></Setter>
<Setter Property="Fill" Value="{Binding ModelBodyColor}"></Setter>
<Setter Property="FontRenderingEmSize"
Value="{Binding ModelBodyFontSize}"></Setter>
<Setter Property="UnicodeString"
Value="{Binding ModelBodyText}"></Setter>
</Style>
<Style x:Key="ModelBodyTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="{Binding ModelBodyFontFamily}"></Setter>
<Setter Property="Foreground" Value="{Binding ModelBodyColor}"></Setter>
<Setter Property="FontSize" Value="{Binding ModelBodyFontSize}"></Setter>
<Setter Property="Text" Value="{Binding ModelBodyText}"></Setter>
</Style>
And now apply this styles to the controls
<Glyphs Name="glyphs" Style="{StaticResource ModelBodyGlyphsStyle}" />
<TextBlock Name="text" Style="{StaticResource ModelBodyTextBlockStyle}" />
In the above style, I am using the binding values are ModelBodyFontFamily, ModelBodyColor, ModelBodyFontSize, ModelBodyText
.
These are the public properties of FontProperties
class. So that, I gave DataContext
of MainWindow
class as object
of FontProperties
class in code behind.
Let us now look at the FontProperties
class:
This class contains the four get and set properties name as ModelBodyFontFamily, ModelBodyColor, ModelBodyFontSize, ModelBodyText
. And importantly implement the interface INotifyPropertyChanged
for PropertyChanged
event. So this is basically a model class.
To look at the MainWindow code:
In this I took three buttons Arial, Verdana and Times. On their click event I change the values of all properties from FontProperties
class. And these values update the UI. Now here, I added another one property FallbackModelBodyFontFamily
which is used for FontFamily
Fallback value.
Lets look at the one setter from TextBlock
-
<Setter Property="FontFamily" Value="{Binding ModelBodyFontFamily}"></Setter>
So I bind two values in ModelBodyFontFamily
as comma separated values then it will choose best font and apply to the controls. This is explain on MSDN with very perfect manner FontFamily
. In this link they explain about fallback value with an example.
Note: [Taken as is from MSDN]You can define a font fallback sequence in your code, which lets you define an alternate font. When you create a FontFamily
object, provide multiple font family names, separated by commas, for the String parameter, such as "Comic Sans MS, Verdana". In this case, if the glyphs
from the "Comic Sans MS" typeface are not available, glyphs
from the "Verdana" typeface are used. If neither "Comic Sans MS" nor "Verdana" have the required glyphs
, the fallback font family of the typeface is used, which is "Global User Interface" by default.
It means that we can add multiple FontFamily
for single control and the application will decide to choose the most suitable font for its Text.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = Fontproerties;
}
FontProperties Fontproerties = new FontProperties();
private void Arial_Click(object sender, RoutedEventArgs e)
{
Fontproerties.ModelBodyColor = "Black";
Fontproerties.ModelBodyFontFamily = @"C:\WINDOWS\Fonts\Arial.TTF";
Fontproerties.FallbackModelBodyFontFamily = "Arial";
http:
Fontproerties.ModelBodyFontFamily = Fontproerties.ModelBodyFontFamily +
"," + Fontproerties.FallbackModelBodyFontFamily;
Fontproerties.ModelBodyFontSize = 30;
Fontproerties.ModelBodyText = "This is Arial Text";
}
}
Now here is one problem – I can't assign non URI value to FontUri
property of Glyphs
. It will throw an Exception. For Arial button click
the ModelBodyFontFamily
value update to (@"C:\WINDOWS\Fonts\Arial.TTF", Arial).
Fallback value Arial is not a URI so it will throw an exception. But this will be work for TextBlock
. So what I did I wrote one FontFamilyConverter
class
which converts the ModelBodyFontFamily
value to only (@"C:\WINDOWS\Fonts\Arial.TTF") for Glyphs
control. So the minor change
in XAML at ModelBodyGlyphsStyle
style -
<Style x:Key="ModelBodyGlyphsStyle" TargetType="Glyphs">
<Setter Property="FontUri"
Value="{Binding ModelBodyFontFamily, Converter={StaticResource
ResourceKey=FontFamilyConverter}, ConverterParameter=Glyphs }">
</Setter>
</Style>
And the FontFamilyConverter
class is:
public class FontFamilyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string result = String.Empty;
if (parameter.ToString().Equals("Glyphs") && value != null)
{
string[] words = value.ToString().Split(',');
result = words[0];
return result;
}
return @"C:\WINDOWS\Fonts\Times.TTF";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
Currently from code behind I only changes the FontFamily
values and remaining all values are same for each events.
Let us try to run the application and perform various operations to see the solution in action.
- Click On Arial Button:
- Click On Verdana Button:
- Click On Times Button:
Points of Interest
In this Tip we have talked about a way to apply same Fonts style to TextBlock
and Glyphs
controls from code behind. I tried to apply
the FontFamily
value for both controls from code behind so that this gives a better understanding about the solution approach. This can very well be implemented
with MVVM
pattern.
History
- 23 September 2013: First version.
- 26 September 2013: Update the screen shots with correct spelling.