The situation
I made a custom control
MessageBar that has a style defined in a resource dictionary. This control has a dependency property
Message that, like the name says, will contain a message.
public class MessageBar : Control
{
public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message", typeof(string), typeof(MessageBar),
new FrameworkPropertyMetadata(string.Empty, OnMessageChanged));
static MessageBar()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MessageBar), new FrameworkPropertyMetadata(typeof(MessageBar)));
}
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
private static void OnMessageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MessageBar messageBar = (MessageBar)d;
if (e.NewValue != null && !string.IsNullOrWhiteSpace(e.NewValue.ToString()))
{
messageBar.Visibility = Visibility.Visible;
if (messageBar.textBlock == null)
messageBar.textBlock = messageBar.GetChildOfType<TextBlock>();
// Lots of unnecessary code
}
}
Style
<Style TargetType="{x:Type controls:MessageBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:MessageBar}">
<Border Background="LightYellow"
BorderBrush="Black"
BorderThickness="1,0,1,1"
CornerRadius="0,0,10,10">
<StackPanel VerticalAlignment="Center"
Orientation="Horizontal"
Margin="10,0,10,0">
<!-- Actual text -->
<TextBlock Padding="4,2,4,2"
Margin="5,0,0,0"
x:Name="tbText"
Text="{TemplateBinding Message}"
FontSize="16"
FontWeight="ExtraBold" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When the application starts, the default style is loaded in the merged dictionaries
. After the user logs in, the style that the user chose (this can be different of the default style) is loaded in the merged dictionaries
. Reloading the style happens by clearing the merged dictionaries
and re-adding the correct resource dictionaries
to the merged dictionaries
.
Application.Current.Resources.MergedDictionaries.Clear();
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary()
{
Source = ...
});
// Adding happens a few times.
The new style is correctly loaded and this is also visible in the UI. The UI changes correctly.
The problem
The problem happens when after clearing and re-adding the merged dictionaries, I try to find the child of type TextBlock
in the OnMessageChanged
method.
messageBar.textBlock = messageBar.GetChildOfType<TextBlock>();
I am 100% sure that there is nothing wrong with my GetChildOfType<>()
method. It works correctly when used somewhere else.
When I execute this after re-adding, there are no child elements of MessageBar
. ChildrenCount
is 0.
When the merged dictionaries aren't cleared and re-added, there is a child element of type TextBlock
found. This is what I want.
My guess is that after clearing and re-adding, the MessageBar
doesn't have a correct reference to the style. And because of that, the template isn't applied.
What I already tried
I already tried overriding the ApplyTemplate()
and OnStyleChanged()
methods of the MessageBar
control. But nothing works.
Question
How can I reload the style so that I (the GetChildOfType<TextBlock>()
method) can find the TextBlock
to set my message in the OnMessageChanged
method.
Thanks in advance!
Greetings Loetn.
Try messageBar.ApplyTemplate() before calling GetChildOfType