Making all images be of the same size and margin - wpf

I noticed that I've got a few images in a stack panel and every such has exactly the same size, margin, alignment etc. set to it. I don't want to create a global resource for style. Is it possible to have a local style declared in this specific panel and only for the images (TargetType is enough in this case)?
I'd like something along this solution with the exception that I don't use the global style resource.
<StackPanel.Resources>
<Style TargetType="Image">
<Setter Property="Width" Value="24" />
...
</Style>
</StackPanel.Resources>
<Image Source="{StaticResource Poof}"
VerticalAlignment="Top"
...
Margin="20,20,20,0" />

Just put the style in the resources for the panel, and it will apply to all items of that type, inside the panel.
For example:
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Width" Value="200" />
</Style>
</StackPanel.Resources>
<TextBox Margin="20" />
<TextBox Margin="20" />
<TextBox Margin="20" />
<TextBox Margin="20" />
</StackPanel>
Results in all the text boxes having a width of 200 units.
Unless, you override the style with a setting on the individual items. Perhaps you are doing that?

Try add style inside resources.
<Page.Resources>
<Style TargetType="Image">
<Setter Property="Width" Value="80"/>
<Setter Property="Height" Value="80"/>
</Style>
</Page.Resources>

Related

Is Style Inheritence with nested User Controls Possible In WPF?

I'm pretty sure it's not possible to use BasedOn with regards to a Style declaration in a nested UserControl, and be able to reference a Style declaration made in a parent UserControl - can anyone confirm this?
I've tried BasedOn="{StaticResource}" and BasedOn="{DynamicResource}" and neither work.
(Pseudo code sample below)
<Window>
<UserControl>
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red" />
</Style>
</StackPanel.Resources>
<UserControl2> <!--this will reside in a different .xaml file...-->
<Button Content="Hello World">
<Button.Style>
<Style TargetType="{x:Type Button}" BasedOn="????">
<!--is this possible to inherit the red background?-->
<Setter Property="Padding" Value="10" />
</Style>
</Button.Style>
</Button>
</UserControl2>
</StackPanel>
</UserControl

Override property of custom style

I have Style that applies to all of the buttons of my application:
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse x:Name="StatusButtonCircle" Stroke="Black" StrokeThickness="0" Fill="AliceBlue" Stretch="Uniform">
<Ellipse.Width>
<Binding ElementName="StatusButtonCircle" Path="ActualHeight"/>
</Ellipse.Width>
</Ellipse>
<Ellipse x:Name="StatusButtonCircleHighlight" Margin="4" Stroke="Black" StrokeThickness="2" Stretch="Uniform">
<Ellipse.Width>
<Binding ElementName="StatusButtonCircleHighlight" Path="ActualHeight"/>
</Ellipse.Width>
</Ellipse>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
... some Triggers here
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How can I change properties (e.g. FontWeight, FontSize etc.) in XAML? I tried this:
<Button FontWeight="Bold" FontSize="30" Foreground="Red">
</Button>
In the designer-view, I see the changes. But during runtime those changes are not applied.
After some investigation, I also have a Style for all TextBlock like this:
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="16" />
<Setter Property="FontFamily" Value="Segoe UI Semibold" />
<Setter Property="Foreground" Value="White" />
</Style>
This Style seems to override the TextBlock that is used on the Button. I still can't change the Text Properties in XAML.
Here's what it looks like if I use the Styles above in an empty project:
In the designer, the changes are applied, during runtime the one from the TextBlock are applied. If I assign a x:Key to the TextBlock, it works fine. But then I have to assign this Style to every TextBlock used in the app manually.
You are facing typical style inheritance issue in wpf.
A control looks for its style at the point when it is being initalized. The way the controls look for their style is by moving upwards in logical tree and asking the logical parent if there is appropriate style for them stored in parent's resources dictionary.
In your case, you are using ContentPresenter in button as a default behaviour. and it is using TextBlock to represent text in button by default.
Therefore at the time of initialization, ContentPresenter finding TextBlock style and applying to represent content in button.
If you want to restrict ContentPresenter to look for the style then you have to bind a blank style to content presenter so that it will not look for any further style.
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse x:Name="StatusButtonCircle" Stroke="Black" StrokeThickness="0" Fill="AliceBlue" Stretch="Uniform">
<Ellipse.Width>
<Binding ElementName="StatusButtonCircle" Path="ActualHeight"/>
</Ellipse.Width>
</Ellipse>
<Ellipse x:Name="StatusButtonCircleHighlight" Margin="4" Stroke="Black" StrokeThickness="2" Stretch="Uniform">
<Ellipse.Width>
<Binding ElementName="StatusButtonCircleHighlight" Path="ActualHeight"/>
</Ellipse.Width>
</Ellipse>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center">
<ContentPresenter.Resources>
<Style TargetType="TextBlock" BasedOn="{x:Null}"/>
<!-- Assigned Blank style here therefore it will not search for any further style-->
</ContentPresenter.Resources>
</ContentPresenter>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You can do it with the BasedOn. I show you an example.
<Window.Resources>
<Style TargetType="ToggleButton" BasedOn="{StaticResource DefToggleButton}">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Content" Value="Some Cool Stuff"/>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="More Stuff"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
Here in my resources I have DefToggleButton, now in my xaml file I can set up any Property according to my need (which in this case is the FontWeight and Content Property).
I think if you remove the Template from your Style, then you can do what you want to do, like this:
<Window.Resources>
<Style TargetType="Button" x:Key="stBtn>
<Setter Property="Background" Value="Blue" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontFamily" Value="Segoe UI Semibold" />
</Style>
</Window.Resources>
The Template that you have says, that all Buttons should be shown as a Border with a ContentPresenter inside, which is not what you have asked.
Without the Template, you can define your Buttons like this:
<Button Content="Hi!" Style="{StaticResource stBtn}" Foreground="Red" >
Like this, you have a Blue Button with Red Foreground.
=================
Edit
So what if you define a Template, and use it in you style, like this?
Then, by TemplateBinding you can define that the Foreground and teh Content come later, when the Button is actually defined.
<Window.Resources>
<ControlTemplate x:Key="ctBtn" TargetType="{x:Type Button}">
<Label Background="Green" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}"/>
</ControlTemplate>
<Style x:Key="stBtn2" TargetType="{x:Type Button}">
<Setter Property="Template"
Value="{StaticResource ctBtn}" />
</Style>
<Window.Resources>
Then by defining the Button:
<Button Content="Hi!" Style="{StaticResource stBtn2}" Foreground="Red" >
===============
Edit2
So the general idea is that you can define a TemplateBinding for the properties of the elements in your template. So for example,you have an Ellipse in your template:
<Ellipse Fill="{TemplateBinding BorderBrush}" />
This defines that the Fill property of your Ellipse comes from the BorderBrush of your Button (Assuming that the template is targeting a Button)
Accordingly, you can put a Label in your Template, and set a TemplateBinding for its Forground and FontWeight property.
<Label Foreground="{TemplateBinding Foreground}" />
First, for this issue to be reproduced, Styles need to be set within a ResourceDictionary which is then added to Application.Resources (precisellyTextBlock global style). Setting Styles within for example Window.Resources will not reproduce the issue.
Global TextBlock Style is applied to the TextBlock created by ConentPresenter
As noticed in the question, the issue is that the global (keyless) Style for TextBlock is applied to the TextBlock created by ContentPresenter when it concludes the content to display is a string. For some reason this doesn't happen when that Style is defined within Window.Resources. As it turns out, there is more to this than just "controls are looking for their styles within their parent's resources".
ControlTemplate is a boundary for elements not deriving from Control class
For TextBlock (which doesn't derive from Control class, but from UIElement) within ControlTemplate, it means that wpf will not look for it's implicit Style beyond it's templated parent. So it won't look for implicit Style within it's parent's resources, it will apply application level implicit Style found within Application.Resources.
This is by design (hardcoded into FrameworkElement if you will), and the reason is exactly to prevent issues like this one. Let's say you're creating a specific Button design (as you are) and you want all buttons in your application to use that design, even buttons within other ControlTemplates. Well, they can, as Button does derive from Control. On the other hand, you don't want all controls that use TextBlock to render text, to apply the implicit TextBlock Style. You will hit the same issue with ComboBox, Label... as they all use TextBlock, not just Button.
So the conclusion is: do not define global Style for elements which don't derive from Control class within Application.Resources, unless you are 100% sure that is what you want (move it to Window.Resources for example). Or, to quote a comment I found in source code for MahApps.Metro UI library: "never ever make a default Style for TextBlock in App.xaml!!!". You could use some solution to style the TextBlock within your Button's ControlTemplate, but then you'll have to do it for Label, ComboBox, etc... So, just don't.

How do buttons style optimize in XAML code?

<Style x:Key="ToolBarButton" TargetType="{x:Type Button}">
<Setter Property="Control.Background" Value="#00000000"/>
<Setter Property="Control.Width" Value="25"/>
<Setter Property="Control.Height" Value="25"/>
</Style>
...
<Grid HorizontalAlignment="Left">
<Button Style="{StaticResource ToolBarButton}"/>
<Button Style="{StaticResource ToolBarButton}"/>
<Button Style="{StaticResource ToolBarButton}"/>
<Button Style="{StaticResource ToolBarButton}"/>
<Button Style="{StaticResource ToolBarButton}"/>
<Button Style="{StaticResource ToolBarButton}"/>
</Grid>
I wanna optimize my XAML code. I don't wanna assign a style to each button, but I wish every button to have my style.
Is it possible to do something like this? Only working ... :)
<Grid x:Name="gToolBar" Grid.Row="1" HorizontalAlignment="Left" Style="{StaticResource ToolBarButton}">
<Button/>
<Button/>
<Button/>
<Button/>
<Button/>
<Button/>
</Grid>
I don't use TargetType only, because I have other buttons with different styles.
I think it available, but i don't know how.
Thanks...
As i already said everything that is to be done in the comment, but for further clarification:
I wanna optimize my XAML code. I don't wanna assign a style to each button, but I wish every button to have my style.
Move the Style part to <Application.Resources> in App.xaml file, Like shown below:
<Application.Resources>
<Style TargetType="Button" >
<Setter Property="Control.Background" Value="#00000000"/>
<Setter Property="Control.Width" Value="25"/>
<Setter Property="Control.Height" Value="25"/>
</Style>
</Application.Resources>
Note: I've removed the x:Key part. Now this will apply to all the button's that is in the application.
I don't use TargetType only, because I have other buttons with different styles. I think it available, but i don't know how.
For this you would have to make a custom button as a UserControl, thus making them completely different from a usual Button. Apply styling to them in their own UserControl.Resources. Thus styling mentioned in App.Resources won't affect these custom made UserControls
You can create a default style for buttons within the grid:
<Window ...>
<Window.Resources>
<Style x:Key="ToolBarButton" TargetType="{x:Type Button}">
<Setter Property="Control.Background" Value="#00000000"/>
<Setter Property="Control.Width" Value="25"/>
<Setter Property="Control.Height" Value="25"/>
</Style>
</Window.Resources>
<Grid HorizontalAlignment="Left">
<Grid.Resources>
<Style x:Key="{x:Type Button}" BasedOn="{StaticResource ToolBarButton}" TargetType="{x:Type Button}"></Style>
</Grid.Resources>
<Button />
<Button />
<Button />
<Button />
<Button />
<Button />
</Grid>
</Window>
If you create a resource that uses a control type as key within a container, the style will get applied to all controls of the type within the container. If you want to define the original style somewhere else (for example because you use it in many place) you can base the local style off the global style.
You should use application resources to do that. add this code to there(app.xaml):
<Application.Resources>
<Style TargetType="Button" >
<Setter Property="Control.Background" Value="#00000000"/>
<Setter Property="Control.Width" Value="25"/>
<Setter Property="Control.Height" Value="25"/>
</Style>
</Application.Resources>
UPDATE
Or if you want this style apply just some part of your application such some special 'Grid' or special Window ..., just put it inside Resource of that element like this:
<Grid>
<Grid.Resources>
<Style TargetType="Button" >
<Setter Property="Control.Background" Value="#00000000"/>
<Setter Property="Control.Width" Value="25"/>
<Setter Property="Control.Height" Value="25"/>
</Style>
</Grid.Resources>
... inside code, and your buttons which we eant to apply style for them.
</Grid>

Custom AppBarButton from image

Step by step, I'm optimizing my xaml to create a custom AppBarButton from an image. I've gone from a complete custom xaml layout to using a few lines using styles, but I know I can simplify this one more step.
Here's what I currently have:
<Style x:Key="PrintAppBarButtonStyle" TargetType="ButtonBase" BasedOn="{StaticResource AppBarButtonStyle}">
<Setter Property="AutomationProperties.AutomationId" Value="PrintAppBarButton"/>
<Setter Property="AutomationProperties.Name" Value="Print"/>
</Style>
<Button Style="{StaticResource PrintAppBarButtonStyle}">
<ContentControl>
<Image Source="/Assets/AppBar/appbar_printer_dark.png"/>
</ContentControl>
</Button>
I know I can move the image source into the style definition, but I haven't been able to get this to work. After reading about the AppBarButton class, I tried to set my TargetType to AppBarButton and then set an Icon property, but was unsuccessful. Something like the following:
<Style x:Key="PrintAppBarButtonStyle" TargetType="AppBarButton" BasedOn="{StaticResource AppBarButtonStyle}">
<Setter Property="AutomationProperties.AutomationId" Value="PrintAppBarButton"/>
<Setter Property="AutomationProperties.Name" Value="Print"/>
<Setter Property="Icon">
<Setter.Value>
// here it's expecting an IconElement
</Setter.Value>
</Setter>
</Style>
<Button Style="{StaticResource PrintAppBarButtonStyle}"/>
Any tips?
The Icon property does not accept an image -- if you need to use an image, stick with the Content property. That can also be styled:
<Style x:Key="PrintAppBarButtonStyle" TargetType="ButtonBase" BasedOn="{StaticResource AppBarButtonStyle}">
<Setter Property="AutomationProperties.AutomationId" Value="PrintAppBarButton"/>
<Setter Property="AutomationProperties.Name" Value="Print"/>
<Setter Property="Content">
<Setter.Value>
<ContentControl>
<Image Source="/Assets/AppBar/appbar_printer_dark.png"/>
</ContentControl>
</Setter.Value>
</Setter>
</Style>
By way of explanation, note that "ContentControl.Content" is the ContentProperty, which means that the child element gets set as "Content". Ie, this:
<Button Style="{StaticResource PrintAppBarButtonStyle}">
<ContentControl>
<Image Source="/Assets/AppBar/appbar_printer_dark.png"/>
</ContentControl>
</Button>
is just shorthand for this:
<Button Style="{StaticResource PrintAppBarButtonStyle}">
<Button.Content>
<ContentControl>
<Image Source="/Assets/AppBar/appbar_printer_dark.png"/>
</ContentControl>
</Button.Content>
</Button>

How to propagate styles to Hyperlinks inside a DataTemplate?

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 (like TextBlock and Hyperlink) do not look for implicit styles outside the DataTemplate boundary.
Again, as the article says, the possible workaround is to specify the style key explicitly. In your case it might be something like this:
<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 Errors}"/>
</StackPanel>
Then, you can add an implicit style for Hyperlink that just references our named style in the DataTemplate resources:
<DataTemplate DataType="{x:Type Importer:ConversionDetailsMessage}">
<DataTemplate.Resources>
<Style TargetType="{x:Type Hyperlink}"
BasedOn="{StaticResource MyDefaultHyperlinkStyle}"/>
</DataTemplate.Resources>
<TextBlock>
<Run Text="{Binding Message, Mode=OneTime}"/>
<Hyperlink Command="Common:ImportDataCommands.ExplainConversionMessage" CommandParameter="{Binding}">
<Run Text="{Binding HelpLink.Item2, Mode=OneTime}"/>
</Hyperlink>
</TextBlock>
</DataTemplate>
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:
<Style x:Key="MyDefaultHyperlinkStyle"
BasedOn="{StaticResource {x:Type Hyperlink}}/>
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...
BasedOn="{StaticResource MyDefaultHyperlinkStyle}"
... will always point to the following resource (which is the default style):
<Style x:Key="MyDefaultHyperlinkStyle" BasedOn="{StaticResource {x:Type Hyperlink}}"/>
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 the BasedOn property.
BUT, Foreground property 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:
<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>
<SolidColorBrush x:Key="HyperlinkForeground"
Color="Blue" />
<SolidColorBrush x:Key="HyperlinkHoverForeground"
Color="Gray" />
<Style x:Key="MyDefaultHyperlinkStyle"
TargetType="Hyperlink"
BasedOn="{StaticResource {x:Type Hyperlink}}">
<Setter Property="Foreground"
Value="{DynamicResource HyperlinkForeground}" />
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Foreground"
Value="{DynamicResource HyperlinkHoverForeground}" />
</Trigger>
</Style.Triggers>
</Style>
<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>
<SolidColorBrush x:Key="HyperlinkForeground"
Color="Yellow" />
<SolidColorBrush x:Key="HyperlinkHoverForeground"
Color="White" />
</StackPanel.Resources>
<TextBlock>Data import errors</TextBlock>
<ItemsControl ItemsSource="{Binding Messages}" />
</StackPanel>
</Grid>
</UserControl>
It works as expected, i.e. all links inside StackPanel will be Yellow/White, while outside they will be blue.
Hope this helps.

Resources