XAML styles - Nested tabcontrols triggering eachother's animations - wpf

I've invented a metro-style tab control which is built to contain two levels of tabs just like the Zune media library does; one large and one smaller below that. When you change tab for the first level, it works fine and animates correctly. Each of the two tabs contains another TabControl using the same template, but when you change the tabs there even the tabstrip animates; like the whole ContentPresenter of the container TabControl animates rather than the ContentPresenter of the child TabControl. If that makes sense :P
Here's the style:
<Style x:Key="MetroTabControl" TargetType="{x:Type TabControl}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Background" Value="White" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<ControlTemplate.Resources>
<Storyboard x:Key="TabSelectionChangedStoryboard">
<DoubleAnimation Storyboard.TargetName="TabControlContent"
Storyboard.TargetProperty="Opacity"
To="100"
From="0"
FillBehavior="HoldEnd"
Duration="0:0:45.0" />
<ThicknessAnimation Storyboard.TargetName="TabControlContent"
Storyboard.TargetProperty="Margin"
From="0,25,0,-25"
To="0,0,0,0"
FillBehavior="HoldEnd"
Duration="0:0:0.3">
</ThicknessAnimation>
</Storyboard>
</ControlTemplate.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border>
<TabPanel
IsItemsHost="True">
</TabPanel>
</Border>
<Border x:Name="BorderPresenter" BorderThickness="0"
Grid.Row="1"
BorderBrush="White"
Background="White">
<ContentPresenter x:Name="TabControlContent" ContentSource="SelectedContent" Margin="0" >
</ContentPresenter>
</Border>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="SelectionChanged">
<BeginStoryboard Storyboard="{StaticResource TabSelectionChangedStoryboard}" />
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

That happens because SelectionChanged event bubbles up to parent TabControl and triggers its animation. As one possible easy solution you can add SelectionChanged event handler to parent TabControl and check if it is the original source for this event:
<TabControl SelectionChanged="RootTabControl_SelectionChanged">
<TabItem>
<TabControl>
<!-- TabItems here -->
</TabControl>
</TabItem>
</TabControl>
And here`s the code:
private void RootTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender != e.OriginalSource)
e.Handled = true;
}

Related

im trying to slide out and in a menubar with button click WPF

here is what im doing
i have a Buttons.xaml style file for styling my menu button
<!-- Menu button -->
<Style x:Key="MenuButton" TargetType="{x:Type Button}">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="Height" Value="20" />
<Setter Property="Width" Value="50" />
<Setter Property="Margin" Value="0" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="IsHitTestVisible" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border">
<Grid VerticalAlignment="{TemplateBinding VerticalAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}">
<Rectangle x:Name="rectangle" Width="20" Height="2" Fill="{StaticResource DarkGrayBrush}" Margin="0 0 0 0" HorizontalAlignment="Center" VerticalAlignment="Top" RenderTransformOrigin="-0, 0.5" />
<Rectangle x:Name="rectangle1" Width="20" Height="2" Fill="{StaticResource DarkGrayBrush}" Margin="0 5 0 0" HorizontalAlignment="Center" VerticalAlignment="Top" RenderTransformOrigin="-0, 0.5" />
<Rectangle x:Name="rectangle2" Width="20" Height="2" Fill="{StaticResource DarkGrayBrush}" Margin="0 10 0 0" HorizontalAlignment="Center" VerticalAlignment="Top" RenderTransformOrigin="-0, 0.5" />
<ContentPresenter />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" TargetName="border" Value="{StaticResource FaintWhiteBrush}"/>
</Trigger>
<EventTrigger RoutedEvent="Button.Click" SourceName="menuButton">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="gridMenu" Storyboard.TargetProperty="Width" From="0" To="100" Duration="0:0:0.3" />
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="gridMenu" Storyboard.TargetProperty="Width" From="100" To="0" Duration="0:0:0.3" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and here is my usercontrol view file
that has menu button itself with the styling and source name in my style that is supposed to be found by my event trigger when this button is clicked and slide out the grid
but its not finding it
<Grid>
<!-- Menu button -->
<Button x:Name="menuButton" Style="{StaticResource MenuButton}" />
<!-- Menu bar -->
<Grid x:Name="gridMenu" Background="White" Width="0" HorizontalAlignment="Left">
</Grid>
when i run this code above this is the error message i get
InvalidOperationException: Cannot find element 'menuButton' targeted by this EventTrigger.
thanks in advance
Triggers inside ControlTemplates (or DataTemplates) can only reference elements that are inside that template. The template doesn't "know" about anything outside of itself, so it can't interact with anything but its own parts.
If you want menuButton to interact with gridMenu, that has to be set up from a context/scope that knows about both of those things. In your case, this would be the UserControl where they are both declared.
If you wanted to implement something like this using an EventTrigger (with XAML only- no code), it would have to be done in the ControlTemplate of the Control that directly contained those two elements. Something like this:
<Control>
<Control.Template>
<ControlTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Name="menuButton"/>
<Grid Name="gridMenu" Background="Green" Grid.Row="1"/>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger SourceName="menuButton" RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="gridMenu" Storyboard.TargetProperty="Width" From="0" To="100" Duration="0:0:0.3" />
</Storyboard>
</BeginStoryboard>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="gridMenu" Storyboard.TargetProperty="Width" From="100" To="0" Duration="0:0:0.3" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Control.Template>
</Control>
The above is an example showing how to place a trigger in a scope that contains both elements, so that one can affect another. It's not a finished solution, but it should give you an idea of what I mean.
Keep in mind that I've just copy/pasted your EventTriggers into my code. The triggers as you've written them only grow and then immediately shrink menuGrid, which I'm guessing isn't exactly what you want. You probably want it to grow, stay open, and then shrink at some later point. You'll need to work that out on your own (or ask another question), but assuming you want a second click of menuButton to close menuGrid, try using a ToggleButton instead of a normal Button and using EventTriggers in the Checked and Unchecked events.
One last thought: since you're making a UserControl you might want to consider declaring a Boolean property such as IsOpen and using that to trigger the menuGrid animation (via a DataTrigger) instead of having it triggered directly by Button click. This would let you open/close the menu from the Window that is housing the UserControl. All standard controls that have some sort of popup (such as ComboBox and Expander) have some such property that tells you the current state and allows you to change it from the outside.

How to avoid that a Coloranimation in a ControlTemplate gets applied to every object using the template

I declared ColorAnimations inside a ControlTemplate of a Style.
What it should do:
Whenever the mouse hovers over the object the color of this specific object should be animated.
What it does instead:
Animating the color of EVERY object the style is applied to whenever I hover over one of them, even though the property activating the animation is not changing on all objects.
What I tried before:
I tried using an Eventrigger instead of a normal trigger but the problem persists.
I also tried using the "Name" property not "x:Name" but this didn't help either.
Also not using Storyboard.TargetName but Storyboard.Target and using a binding with RelativeSource to let it find the object.. and still every object using this style gets animated whenever I hover over any of them
It works as intended if I use Setters to change the background instead of Storyboards and ColorAnimations.
The Style
<Style x:Key="Fraction_ScrollViewer_ScrollBar_Thumb" TargetType="{x:Type Thumb}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border
x:Name="Border"
CornerRadius="5"
Background="{TemplateBinding Background}"
BorderThickness="0" />
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard
Name="IsMouseOver_True"
HandoffBehavior="Compose">
<Storyboard>
<ColorAnimation
Storyboard.TargetName="Border"
Storyboard.TargetProperty="Background.(SolidColorBrush.Color)"
To="{StaticResource 'Color_CoolGrey'}"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard
Name="IsMouseOver_False">
<Storyboard>
<ColorAnimation
Storyboard.TargetName="Border"
Storyboard.TargetProperty="Background.(SolidColorBrush.Color)"
To="{StaticResource 'Color_MidGrey'}"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
The Thumb style is used in a Scrollbar style which is used in a ScrollViewer.
The Scrollviewer Style is then used in 2 locations:
1:
<Style x:Key="LabelTreeView" TargetType="{x:Type TreeView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeView}">
<ScrollViewer
Style="{StaticResource ScrollViewer}"
Focusable="False"
CanContentScroll="False"
Padding="4">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
2:
<ScrollViewer
Style="{StaticResource ScrollViewer}"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<ItemsControl
BorderThickness="0"
Background="{StaticResource Brush_Transparent}"
ItemTemplate="{StaticResource CharacterSequenceChar}"
ItemsSource="{Binding DisplayedCharacterSequenceCharacters}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
What is causing this behaviour and how to avoid it with still using animations?
Apparently all Buttons share the same Brush instance in their Background property.
You could explicitly assign a separate Brush for each Border in the Template:
<Border x:Name="Border" ...>
<Border.Background>
<SolidColorBrush Color="{Binding Background.Color,
RelativeSource={RelativeSource TemplatedParent}}"/>
</Border.Background>
</Border>

WPF Something overriding tab content alignment of TabControl

I used this as a starting point to make a style for a TabControl, mine only works with TabStripPlacement="Bottom". I expect that the content I put in the TabItem would fill the entire area, designated for it, like it does with the default style and the style from microsoft I used as a starting point. But it does not, It starts with its minimal sizes, buttons don't get stretched at all and RichTextBoxes seem stretched only horizontally, if I add text to the RichTextBox it expands. Here is what it looks like:
The orange is the area I expect the content to take (with some margins), the blue is the background of the RichTextBox. The green is the global background. The selected tab has its header's border thickened (red). Don't mind the space between the tab headers and the content area, it is intentional.
I've been poking around a lot, but can't seem to find the cause, however I have found that I don't have this problem if I don't apply the style for the TabItem. And when I inspect the elements with the xaml debugging tools in visual studio I find that PART_SelectedContentHost has its horizontal alignment set to Left and vertical alignment set to Top, happens even if I have explicitly set them to Stretch in the style. I also tried applying "Stretch" to the RichTextBox, it didn't work. Here is the style:
<Style TargetType="{x:Type TabControl}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid KeyboardNavigation.TabNavigation="Local" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Disabled">
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="0" Value="#FFAAAAAA" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<TabPanel x:Name="HeaderPanel"
Grid.Row="2"
Panel.ZIndex="1"
Margin="0"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1"
Background="Transparent" />
<Border x:Name="Border"
Grid.Row="0"
Panel.ZIndex="0"
BorderThickness="0"
CornerRadius="0"
KeyboardNavigation.TabNavigation="Local"
KeyboardNavigation.DirectionalNavigation="Contained"
KeyboardNavigation.TabIndex="2"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch">
<Border.Background>
<SolidColorBrush Color="Orange"/>
</Border.Background>
<ContentPresenter
x:Name="PART_SelectedContentHost"
Margin="4,4,4,4"
ContentSource="SelectedContent"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TabItem}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid x:Name="Root">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected" />
<VisualState x:Name="Selected">
<Storyboard>
<ColorAnimation Storyboard.TargetName="ContentSite"
Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)"
From="White" To="Blue"
Duration="0:0:0.0" AutoReverse="True"/>
<ThicknessAnimationUsingKeyFrames
Storyboard.TargetProperty="(Border.BorderThickness)"
Storyboard.TargetName="Border">
<EasingThicknessKeyFrame KeyTime="0"
Value="1,5,1,5" />
</ThicknessAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver" />
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="Border"
Margin="0,0,0,0"
BorderThickness="1,1,1,1"
CornerRadius="0,0,0,0"
BorderBrush="Red">
<Border.Background>
<SolidColorBrush Color="Black"/>
</Border.Background>
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"
RecognizesAccessKey="True"
TextBlock.Foreground="White"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Panel.ZIndex" Value="100"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
EDIT: For the sake clarity, the style is saved in a xaml file - "TabControlStyleDictionary.xaml" and this is the code of the main window:
<Window x:Class="TabControlStylingTest2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TabControlStylingTest2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="TabControlStyleDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid Background="Green">
<TabControl TabStripPlacement="Bottom">
<TabItem Header="tab1">
<RichTextBox
Foreground="White"
Background="Blue"
AcceptsReturn="True"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"/>
</TabItem>
<TabItem Header="tab2">
<Button
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
some text 123456789
</Button>
</TabItem>
</TabControl>
</Grid>
I had the same issue with overwriting the style. For some reason the HorizontalAlignment and VerticalAlignment properties of the ContentPresenter are set locally on each LayoutUpdate of the PART_SelectedContentHost in the codebehind. In my solution I implement an Attached Behavior for UIElements which calls the ClearValue method on a LayoutUpdate event. This will delete the local value on each occurance of the event. A refrence to System.Windows.Interactivity is required for this.
public class ClearValueOnLayoutUpdateBehavior : Behavior<UIElement>
{
public static readonly DependencyProperty PropertyProperty =
DependencyProperty.Register(nameof(Property), typeof(DependencyProperty), typeof(ClearValueOnLayoutUpdateBehavior), new PropertyMetadata());
public DependencyProperty Property
{
get { return (DependencyProperty)GetValue(PropertyProperty); }
set { SetValue(PropertyProperty, value); }
}
protected override void OnAttached()
{
base.OnAttached();
if(Property != null)
AssociatedObject.LayoutUpdated += AssociatedObject_LayoutUpdated;
}
private void AssociatedObject_LayoutUpdated(object sender, EventArgs e)
{
AssociatedObject.ClearValue(Property);
}
}
In your XAML file you have to add the xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" reference as well. Your ContentPresenter should be changed as following:
<ContentPresenter
x:Name="PART_SelectedContentHost"
ContentSource="SelectedContent"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
<i:Interaction.Behaviors>
<behavior:ClearValueOnLayoutUpdateBehavior Property="{x:Static FrameworkElement.HorizontalAlignmentProperty}" />
<behavior:ClearValueOnLayoutUpdateBehavior Property="{x:Static FrameworkElement.VerticalAlignmentProperty}" />
</i:Interaction.Behaviors>
</ContentPresenter>

Best practice to pipe WPF animation trigger from one ControlTemplate element to another

After reading several SO posts (here, here, and here) I still can't find any way to solve my problem... Basically, I redefined Button layout, and packed it up in a style. The new Button ControlTemplate contains a Rectangle I want to animate on Button click. Which TargetProperty do I have to use in my animation? Following is what I done :
UserControl x:Class="OfficeTourismeBrantome.Views.MainMenuView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="300">
<UserControl.Resources>
<Style x:Key="MenuItemButtonStyle" TargetType="Button">
<Setter Property="FontSize" Value="35" />
<Setter Property="FontFamily" Value="Segoe" />
<Setter Property="Foreground" Value="#FFEBEDEA" />
<!--<Setter Property="Height" Value="{Binding MenuLayout.MenuItemSize.Height}" />-->
<Setter Property="HorizontalContentAlignment" Value="Right" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Canvas HorizontalAlignment="Stretch">
<ContentPresenter Canvas.Left="{Binding MenuLayout.MenuItemLeftMargin}" HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<Rectangle
Name="test"
Width="0"
Height="3"
Fill="Aqua"/>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
<!-- Which targetProperty should I use to animate ControlTemplate Rectangle ?-->
From="0.0"
To="10.0"
Duration="0:0:2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<ItemsControl Name="menuButtonContainer" ItemsSource="{Binding Items}" Margin="{Binding MenuLayout.MenuMargin}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Style="{StaticResource ResourceKey=MenuItemButtonStyle}"
Margin="{Binding ElementName=menuButtonContainer,
Path=DataContext.MenuLayout.MenuItemMargin}"
Height="{Binding ElementName=menuButtonContainer,
Path=DataContext.MenuLayout.MenuItemSize.Height}"
Content="{Binding Text}"
Command="{Binding ElementName=menuButtonContainer,
Path=DataContext.ChangeThemeCommand}"
CommandParameter="{Binding Id}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I may be wrong in my implementation, still trying to understand WPF subtilities... What's the best way to achieve my goal?
Many thanks for your answers !
Which target property you want to animate is the question you have to ask yourself ! Do you want to change the rectangle's Width ? Its Opacity ? ...
Best practice... I don't know, but that's one way to do it :
<ControlTemplate TargetType="Button">
[...]
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard TargetName="test" TargetProperty="Width">
<DoubleAnimation From="0.0" To="10.0" Duration="0:0:2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>

Foreground Color of Custom Button (ControlPresenter)

I am attempting to define a global button style in App.xaml, and it's mostly working as I expect. However, I just cannot figure out how to get the Foreground to work correctly. No matter what I do, I am getting the style of the default TextBlock (which sets the color to White).
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="3, 5" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="FocusVisualStyle"
Value="{StaticResource ButtonFocusVisual}" />
<Setter Property="Foreground" Value="Red" />
<Setter Property="Padding" Value="5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="gridMainButton"
RenderTransformOrigin="0.5, 0.5">
<Grid.RenderTransform>
<ScaleTransform x:Name="scaleTransform"
CenterX="0.5"
CenterY="0.5" />
</Grid.RenderTransform>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates" >
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver" />
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="scaleTransform"
Storyboard.TargetProperty="ScaleX"
Duration="0"
To="0.85" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse x:Name="ellipse"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
StrokeThickness="2"
Stroke="{StaticResource standardBackground}"
Fill="{StaticResource standardBackground}" />
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="4, 8"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I guess I could change the ContentPresenter to a TextBlock, which would be ok for this particular application, but I'm looking for a more generic solution.
Thanks,
wTs
Like Markus Hütter said, the problem is probably that you have an implicit Style for a TextBlock defined and when the Button Content is set to a string, a TextBlock will be created where you have the ContentPresenter in the Template. This TextBlock will pick up the implicit Style and that's why you're getting this problem.
You can disable the implicit Style for a TextBlocks that is created in place for a string by specifying a DataTemplate for string. Add the following to App.xaml
<Application ...>
<Application.Resources>
<DataTemplate xmlns:sys="clr-namespace:System;assembly=mscorlib"
DataType="{x:Type sys:String}">
<TextBlock Text="{Binding}">
<TextBlock.Resources>
<Style TargetType="{x:Type TextBlock}"/>
</TextBlock.Resources>
</TextBlock>
</DataTemplate>
<!--...-->
</Application.Resources>
</Application>
you seem to be using a custom style for textblock (if you say Foreground color is white) lets call this StandardTextBlockStyle.
Within your button style inside the outer grid. include this:
<Grid x:Name="gridMainButton">
<Grid.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource StandardTextBlockStyle}">
<Setter Property="Foreground" Value="Black"/>
</Style>
</Grid.Resources>
<!-- ...-->
</Grid>
this should override the default TextBlock style.
I had similar issue, there was a global TextBlock style and I was not able to override it in other controls where custom color/font was needed.
Based on Fredrik Hedblad & Pavlo Glazkov (from here) responses, the following solution worked for me:
<DataTemplate DataType="{x:Type System:String}">
<TextBlock Text="{Binding}">
<TextBlock.Resources>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type FrameworkElement}}, Path=(TextElement.Foreground),
FallbackValue={StaticResource Colors_ThemeForeground_SCBrush}, TargetNullValue={StaticResource Colors_ThemeForeground_SCBrush}}"/>
</Style>
</TextBlock.Resources>
</TextBlock>
</DataTemplate>
Thanks,
RDV

Resources