I’m try to set the Foreground colour on a Hyperlink using a Style object in an ancestor’s Resources, but it’s not having any effect. I even used the BasedOn tip from Changing Hyperlink foreground without losing hover color, but it’s not made any difference – I still get a blue hyperlink that is red on hover.
Here’s the XAML for my controls, including an ItemsControl whose items are shown using a hyperlink:
<StackPanel Background="Red" TextElement.Foreground="White">
<StackPanel.Resources>
<Style TargetType="Hyperlink" BasedOn="{StaticResource {x:Type Hyperlink}}">
<Setter Property="Foreground" Value="Yellow"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock>Data import errors</TextBlock>
<ItemsControl ItemsSource="{Binding Errors}"/>
</StackPanel>
And the items in the ItemsControl are picking up the following DataTemplate:
<DataTemplate DataType="{x:Type Importer:ConversionDetailsMessage}">
<TextBlock>
<Run Text="{Binding Message, Mode=OneTime}"/>
<Hyperlink Command="Common:ImportDataCommands.ExplainConversionMessage" CommandParameter="{Binding}">
<Run Text="{Binding HelpLink.Item2, Mode=OneTime}"/>
</Hyperlink>
</TextBlock>
</DataTemplate>
It’s worth noting, too, that I don’t want to just set the different colours directly on the Hyperlink in the DataTemplate. This is because the template will be used by a number of different ItemsControl objects, most of which will be on a white background and so can use the standard hyperlink colours. (Note that the one in the XAML above, however, has a red background.)
In short, I don’t want the DataTemplate to have to know anything about the control in which it’s being used. The styles for the template’s controls should just filter down to it.
So… can anyone tell me why the style’s not filtering down and what I can do to fix it?
Thanks.
Update:
Since I couldn’t get Pavlo’s answer to work in my production app, I’ve since tried it in a separate test app. The app is a WinForms app, with the main form containing nothing but an ElementHost, which itself contains a simple WPF usercontrol. Here’s its XAML:
<UserControl x:Class="DataTemplateStyling.StylingView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:DataTemplateStyling="clr-namespace:DataTemplateStyling"
x:Name="root" Loaded="StylingViewLoaded">
<UserControl.Resources>
<Style x:Key="MyDefaultHyperlinkStyle" BasedOn="{StaticResource {x:Type Hyperlink}}"/>
<DataTemplate DataType="{x:Type DataTemplateStyling:ImportMessage}">
<DataTemplate.Resources>
<Style TargetType="{x:Type Hyperlink}"
BasedOn="{StaticResource MyDefaultHyperlinkStyle}"/>
</DataTemplate.Resources>
<TextBlock>
<Run Text="{Binding Message, Mode=OneTime}"/>
<Hyperlink NavigateUri="{Binding HelpLink.Item1}">
<Run Text="{Binding HelpLink.Item2, Mode=OneTime}"/>
</Hyperlink>
</TextBlock>
</DataTemplate>
</UserControl.Resources>
<Grid DataContext="{Binding ElementName=root}">
<StackPanel Background="Red" TextElement.Foreground="White">
<StackPanel.Resources>
<Style x:Key="MyDefaultHyperlinkStyle" TargetType="Hyperlink" BasedOn="{StaticResource {x:Type Hyperlink}}">
<Setter Property="Foreground" Value="Yellow"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock>Data import errors</TextBlock>
<ItemsControl ItemsSource="{Binding Messages}"/>
</StackPanel>
</Grid>
</UserControl>
As it stands above, this generates an InvalidOperationException, stating “Can only base on a Style with target type that is base type ‘IFrameworkInputElement’.”
That can be fixed by putting TargetType="Hyperlink" on the Style definition immediately inside the UserControl.Resources element. However, while the messages are being shown, the link part of them still has the default blue hyperlink styling:

In short, it’s not working, so I’d welcome any other suggestions/corrections. 🙁
Update 2:
Thanks to an alternative solution from Pavlo, it now is working. 🙂
After some googling I ran into this post: http://www.11011.net/archives/000692.html.
As it described there, it turns out that elements that are not derived from
Control(likeTextBlockandHyperlink) do not look for implicit styles outside theDataTemplateboundary.Again, as the article says, the possible workaround is to specify the style key explicitly. In your case it might be something like this:
Then, you can add an implicit style for
Hyperlinkthat just references our named style in theDataTemplateresources:And because the data template can be used in different places, there is a possibility that parent container doesn’t define a style with key “MyDefaultHyperlinkStyle”. In this case an exception will be thrown saying that resource “MyDefaultHyperlinkStyle” cannot be found. To address this, you can define a style with such key that will only inherit default style somewhere in App.xaml:
Update:
The code you included in your update will not work because of the nature of static resources, which means that the following resource reference in date template…
… will always point to the following resource (which is the default style):
Static resource references are resolved at compile time, therefore the closest resource in the tree is used.
You might be tempted to use
DynamicResource, but unfortunately it is not supported with theBasedOnproperty.BUT,
Foregroundproperty supports dynamic resources, so we can use the same trick with brushes we use inside our style. Here is your test user control modified to use dynamic brushes:It works as expected, i.e. all links inside
StackPanelwill be Yellow/White, while outside they will be blue.Hope this helps.