Adding one WPF style property kills all other style properties - c#

I've a style for my WPF buttons, defined in the main window:
<Window.Resources>
<Style TargetType="Button">
<Setter Property="Width" Value="Auto" />
<Setter Property="Height" Value="Auto" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Foreground" Value="#FFFFFF" />
<Setter Property="Background" Value="#3fa9f5" />
...
</Style>
</Window.Resources>
In an UserControl, I want to set the content and the background depending on a binding:
<Button.Style>
<Style TargetType="Button">
<Setter Property="Content" Value="Text123" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=myControl, Path=IsHidden}"
Value="true">
<Setter Property="Content" Value="TextABC" />
<Setter Property="Background" Value="#ff1d25" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
The problem: The button in the UserControl looses all other properties it gets from the main window style (color, width, margins, ...).
I tried to let the UserControl button's style know the parent style via
BasedOn="{StaticResource {x:Type Button}}"
but with no result.

Related

UWP Xaml : Container style that applies to children

Let say I want to style a grid background like that :
<Page.Resources>
<Style x:key="MainGridStyle" TargetType="Grid">
<Setter Property="Background" Value="Blue" />
</Style>
</Page.Resources>
How can I make all TextBlocks inside that MainGridStyle Foreground=White through that Style?
Thanks
This works in WPF at least:
<Style x:key="MainGridStyle" TargetType="Grid">
<Setter Property="Background" Value="Blue" />
<Setter Property="TextElement.Foreground" Value="White" />
</Style>

Why can't I override the default BasedOn Style? WPF

I have a default Label Style
<Style x:Key="LabelStyle" TargetType="{x:Type Label}">
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontSize" Value="13.333" />
<Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
</Style>
<Style BasedOn="{StaticResource LabelStyle}" TargetType="{x:Type Label}" />
I then try to use a different style for a single Label
<Style x:Key="HeaderLabelStyle" TargetType="{x:Type Label}">
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="FontSize" Value="16" />
<Setter Property="Foreground" Value="{StaticResource HeaderForegroundBrush}" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
</Style>
<Label Content="Text here" Name="someName" Style="{StaticResource HeaderLabelStyle}"/>
But for some reason the label always gets the default style. Why? Can this be overridden?
Thanks
So I realised that the default (string) template for Label is an indented TextBlock (styles are inherited)
Since I also was defining a global style for TextBlock
<Style x:Key="TextBlockStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
<Setter Property="FontSize" Value="13.333" />
<Setter Property="FontFamily" Value="Segoe UI" />
<Style BasedOn="{StaticResource TextBlockStyle}" TargetType="{x:Type TextBlock}" />
No matter how many types of Label I had I was always bound to use the template for TextBlock
So the solution was to define a dummy TextBlock class
namespace Theme
{
public class HeaderTextBlock : TextBlock
{
}
}
Then assign it its own global style
xmlns:this="clr-namespace:Theme"
<Style x:Key="HeaderTextBlockStyle" TargetType="this:HeaderTextBlock">
<Setter Property="Foreground" Value="{StaticResource HeaderForegroundBrush}" />
<Setter Property="FontSize" Value="13.333" />
<Setter Property="FontFamily" Value="Segoe UI" />
</Style>
<Style BasedOn="{StaticResource HeaderTextBlockStyle}" TargetType="{x:Type this:HeaderTextBlock}" />
And use TextBlocks instead of Labels (haven't figured out how to implement a Label child yet since (Label : TextBlock) = false
xmlns:theme="clr-namespace:Theme;assembly=Theme"
<theme:HeaderTextBlock Text="Some text" Name="titleLabel" Style="{StaticResource HeaderTextBlockStyle}"/>

Bind to Style Setter from a different Style

how do I go about binding the Foreground Colour of one Style setter to the Fill Colour on another Style Setter, it should be the same object type. This is the code I have got below!
Getting these errors:
System.Windows.Data Error: 4 : Cannot find source for binding with
reference 'ElementName=MenuItemPath'. BindingExpression:Path=Fill;
DataItem=null; target element is 'TextBlock' (Name=''); target
property is 'Foreground' (type 'Brush')
<Style x:Key="MenuItemName" TargetType="TextBlock">
<Setter Property="Foreground" Value="{Binding ElementName=MenuItemPath, Path=Fill}" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<ControlTemplate x:Key="MenuItem" TargetType="RadioButton">
<ControlTemplate.Resources>
<Style TargetType="Path" x:Name="MenuItemPath">
<Setter Property="Fill" Value="#FF22252C" />
<Setter Property="Height" Value="25" />
<Setter Property="Width" Value="25" />
<Setter Property="Stretch" Value="Uniform" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type RadioButton}}, Path=IsChecked}" Value="True">
<Setter Property="Fill" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>
</ControlTemplate.Resources>
Personally I would create a separate Resource for storing the brush color, and reference it from both locations.
<SolidColorBrush Color="#FF22252C" x:Key="MenuFillColor" />
<Style x:Key="MenuItemName" TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource MenuFillColor}" />
...
</Style>
<ControlTemplate x:Key="MenuItem" TargetType="RadioButton">
<ControlTemplate.Resources>
<Style TargetType="Path" x:Name="MenuItemPath">
<Setter Property="Fill" Value="{StaticResource MenuFillColor}" />
...
</Style>
</ControlTemplate.Resources>
</ControlTemplate>
That said, I've never actually tried binding to another Style's Setter.Value property... it might be possible assuming everything was the same scope. You look like you may have different scopes since you are using <ControlTemplate.Resources> to limit the scope of your MenuItemPath style to just that ControlTemplate. But personally I would not attempt it, and would assume any requirement that needed something like this could also be done some better way :)
It is not possible to access outer property of another style in wpf and that's why you have got binding error. Rather you can declare a color in your resources and from where you can access it.
I was making it more complicated than need be, I just added a DataTrigger which fixed the issue:
<Style x:Key="MenuItemName" TargetType="TextBlock">
<Setter Property="Foreground" Value="Black" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=MenuItemRadio}" Value="True">
<Setter Property="Foreground" Value="White" />
</DataTrigger>
</Style.Triggers>
</Style>

WPF :Material Design + dragablz tabItem header style

I am working in WPF with the MaterialDesign Toolkit and Dragablz.
I encountered a problem while trying to style a TabablzControl.
I already have style for the windows default TabControl and TabItem header, as shown in the picture:
http://i.imgur.com/2anl5rl.png
But when I change the default tabControl to TabablzControl, it turns into this:
http://i.imgur.com/bhaaMVy.png
Here are the window.resources:
<Style x:Key="mdTabControl" TargetType="TabControl">
<Setter Property="TextElement.Foreground" Value="{DynamicResource MaterialDesignBody}"/>
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}"></Setter>
</Style>
<Style x:Key="mdTabHeader" TargetType="{x:Type TabItem}">
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}"></Setter>
<Setter Property="Foreground" Value="{DynamicResource MaterialDesignBody}"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border" Margin="1,0,1,0" CornerRadius="3 3 0 0">
<ContentPresenter x:Name="ContentSite" VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header" Margin="10,2,10,2"
RecognizesAccessKey="True">
</ContentPresenter>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter TargetName="Border" Property="Background" Value="{StaticResource SecondaryAccentBrush}" />
<Setter Property="Foreground" Value="{StaticResource SecondaryAccentForegroundBrush}"/>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter TargetName="Border" Property="Background" Value="{StaticResource PrimaryHueMidBrush}" />
<Setter Property="Foreground" Value="{StaticResource PrimaryHueMidForegroundBrush}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="{StaticResource PrimaryHueDarkBrush}" />
<Setter Property="Foreground" Value="{StaticResource PrimaryHueDarkForegroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The error appears when I change the mdTabControl style targetType to:
TargetType="dbz:TabablzControl"
I want to keep the style I set to the TabControl, but with the added functionality of the TabablzControl
Any help will be appreciated
First thing to note, which is a general WPF characteristic, you are not using style inheritance correctly.
As you are using Material Design with Dragablz, if you are restyling the tab control itself, you must inherit from the Material Design style in the Dragablz assembly using BasedOn:
<Style x:Key="mdTabControl" TargetType="TabControl" BasedOn="{StaticResource MaterialDesignTabablzControlStyle}">
<Setter Property="TextElement.Foreground" Value="{DynamicResource MaterialDesignBody}"/>
<Setter Property="Background" Value="{DynamicResource MaterialDesignPaper}"></Setter>
</Style>
Again, with the tab header itself, you need to inherit from the relevant style:
<Style x:Key="mdTabHeader" TargetType="{x:Type TabItem}" BasedOn="{StaticResource MaterialDesignDragableTabItemStyle}">
. . .
</Style>
Note, that (depending you your App.xaml setup) you probably need to make sure the correct resource dictionary is included in the same XAML file. For example a more complete XAML might be:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Dragablz;component/Themes/materialdesign.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="NormalTabItemStyle" TargetType="{x:Type dragablz:DragablzItem}" BasedOn="{StaticResource MaterialDesignDragableTabItemStyle}">
<Setter Property="Width" Value="280" />
<Setter Property="Padding" Value="1" />
</Style>
. . .
</ResourceDictionary>
</Window.Resources>
Finally, as you are changing the TabItem style, you either need to the TabablzCOntrol style the correct style, or you could use it where you actually declare the TabablzControl itself:
<dragablz:TabablzControl ItemContainerStyle="{StaticResource mdTabHeader}" />
A good example of all this in action is in the SidePanels project in the demo solution at: https://github.com/ButchersBoy/DragablzSamplez
<Style TargetType="{x:Type dragablz:TabablzControl}" BasedOn="{StaticResource MaterialDesignTabablzControlStyle}"/>

Binding Failure on ToolBar Dragging

I have have a ToolBar which I am styling using the code shown below. I have come across three problems with the my ToolBar styling:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<Style x:Key="ToolBarToggleButton" TargetType="{x:Type ToggleButton}"
BasedOn="{StaticResource {x:Static ToolBar.ToggleButtonStyleKey}}">
<Setter Property="Icon" Value="{Binding Icon}"/>
<Setter Property="ToolTip" Value="{Binding FullToolTip}" />
<Setter Property="ToolTipService.IsEnabled" Value="{Binding HasToolTip}" />
<Setter Property="IsChecked" Value="{Binding IsChecked}" />
<Setter Property="cal:Action.Target" Value="{Binding}" />
<Setter Property="cal:Message.Attach" Value="{Binding ActionText}" />
</Style>
...
First:
The tool bar images are currently getting used as a single static instance. Even with the property x:Shared="False" moving the ToolBar one over another will cause a rendering failure.
Solution:
In the ToolTip Styles.xaml, include the image source as a ContentTemplate
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<Style x:Key="ToolBarToggleButton" TargetType="{x:Type ToggleButton}"
BasedOn="{StaticResource {x:Static ToolBar.ToggleButtonStyleKey}}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image x:Shared="false" Source="{Binding Icon}">
<Image.Style>
<Style TargetType="Image">
<Setter Property="Width" Value="16" />
<Setter Property="Height" Value="16" />
<Setter Property="Stretch" Value="Fill" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ToolTip" Value="{Binding FullToolTip}" />
<Setter Property="ToolTipService.IsEnabled" Value="{Binding HasToolTip}" />
<Setter Property="IsChecked" Value="{Binding IsChecked}" />
<Setter Property="cal:Action.Target" Value="{Binding}" />
<Setter Property="cal:Message.Attach" Value="{Binding ActionText}" />
</Style>
<Style x:Key="ToolBarButton" TargetType="{x:Type Button}"
BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image x:Shared="false" Source="{Binding Icon}">
<Image.Style>
<Style TargetType="Image">
<Setter Property="Width" Value="16" />
<Setter Property="Height" Value="16" />
<Setter Property="Stretch" Value="Fill" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ToolTip" Value="{Binding FullToolTip}" />
<Setter Property="ToolTipService.IsEnabled" Value="{Binding HasToolTip}" />
<Setter Property="cal:Action.Target" Value="{Binding}" />
<Setter Property="cal:Message.Attach" Value="{Binding ActionText}" />
</Style>
</ResourceDictionary>
Now we have:
No other changes required.
Second:
The same dragging procedure the ToolTip and ToolTipService bindings also get corrupted - at this stage I am not sure of the underlying reason. The quick solution is to do what I have done with the image above and add the ToolTip to the Image. However, this causes the ToolTip only to show when over the Image and not when hovering over the very edge of the button.
Partial Solution:
Add the ToolTip to the Image. However, this is not ideal as then the tool tips do not show when on the very edge of the button.
Third:
When the drag operation shown above occurs, this also breaks the Caliburn property bindings
<Setter Property="cal:Action.Target" Value="{Binding}" />
<Setter Property="cal:Message.Attach" Value="{Binding ActionText}" />
Questions: (Second and Third Problem)
How to fix the problem with the ToolTip rendering?
How to fix the problem with the Caliburn property binding?
Thanks for your time.
Solution:
"I've finally fixed this. As near as I can tell, when you initiate a drag on a toolbar, any toolbar items on other toolbars which are covered by the toolbar you're dragging get removed from their current position in the visual tree, and then (presumably) added back when they're made visible again.
When they're removed from the visual tree (again, that's what I think is happening), they also lose access to the ToolBarToggleButton and ToolBarButton styles, because those are defined in the Styles.xaml resource dictionary which is added in ToolBarsView.xaml.
However, if you define those same styles globally, then it works - presumably, even though they're no longer children of ToolBarsView, they still have access to the global resources.
So... I've added a new property, IModule.GlobalResourceDictionaries, which allows each module to declare any resource dictionaries that should be added at the global scope. The ToolBars module makes use of this."
https://github.com/tgjones/gemini/issues/67#issuecomment-60040008
Try to re-assign the tooltips as a style trigger for the mouse over event such as:
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="ToolTip" Value="{Binding FullToolTip}" />
<Setter Property="ToolTipService.IsEnabled" Value="{Binding HasToolTip}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="ToolTip" Value="{Binding FullToolTip}" />
<Setter Property="ToolTipService.IsEnabled" Value="{Binding HasToolTip}" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>

Categories

Resources