I have a problem with a certain WPF style called HeadText
with TargetType = "TextBlock"
. The style defines Foreground
, FontSize
and Effect
. The first time a TextBlock is shown only the Foreground setter is not fired (text color stays black), FontSize and Effect are applied normally. When I remove the TextBlock from parent and return it back, then the foreground is also changed as it should.
Situation:
Presenter.dll assembly
Presenter: Window
, loads and displays my usercontrols.Generic.xaml
- Resource dictionary that contains styles.Presenter.dll
does not directly reference TestPresentable.dll
.TestPresentable.dll assembly
TestPresentable: UserControl
, has a styled TextBlock
.TestPresentable.dll
does not directly reference Presenter.dll
.MainApp.exe
MainWindow
from Presenter.dll
assembly, TestPresentable
from TestPresentable
assembly,MainWindow.ContentHost.Content = testPresentable
Relevant code:
Presenter.dll
// Themes/Generic.xaml
...
<Style TargetType="{x:Type TextBlock}" x:Key="HeadText">
<Setter Property="Foreground" Value="#FFFFFFFF" />
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect ShadowDepth="0" Color="#79000000" BlurRadius="3" Opacity="1" />
</Setter.Value>
</Setter>
<Setter Property="FontSize" Value="24"/>
</Style>
...
// MainWindow.xaml
...
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Presenter.dll;component/Themes/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<ContentPresenter Name="ContentHost"/>
</Grid>
...
TestPresentable.dll
// TestPresentable.xaml
...
<TextBlock Text="{Binding SomeData}" Style="{DynamicResource HeadText}"/>
...
It seems that there is something strange with TextBlock.Foreground in WPF since 3.5, see:
I've came up with a workaround using EventSetters and some codebehind for a ResourceDictionary. It's not pretty but will have to do if I want to have my styles independant of the main app. I'll post it here since it might be useful to someone and I'll keep the question open if someone post the right (or better) answer.
Workaround
In the ResorceDictionary XAML (e.g. Generic.xaml) add a Class property like so:
<!-- Generic.xaml -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Presenter.Themes.Generic">
Then add a codebehind cs file (e.g. Generic.xaml.cs) with the partial class you specified in the Class property of the ResourceDictionary:
// Generic.xaml.cs
partial class Generic { }
In the relevant style of the ResourceDictionary add an EventSetter for the Loaded event:
<!-- Generic.xaml -->
<Style TargetType="{x:Type TextBlock}" x:Key="HeadText">
<EventSetter Event="Loaded" Handler="OnHeadTextLoaded"/>
<Setter .../>
<Setter .../>
<Setter .../>
</Style>
In the Generic.xaml.cs add a handler for the Loaded event and set the desired Foreground
//Generic.xaml.cs
public void OnHeadTextLoaded(object sender, EventArgs args)
{
var textBlock = sender as TextBlock;
if (textBlock == null) return;
textBlock.Foreground = new SolidColorBrush(Colors.White);
}