Is it possible to add style to xaml element without editing the element?
for example:
xaml element:
<Grid>
<Grid x:Name="A">content A</Grid>
<Grid x:Name="B">content B</Grid>
</Grid>
and style:
<Style x:Key="StyleForA" TargetName="A" TargetType="{x:Type Grid}" >
<Setter Property="Background" Value="Red"/>
</Style>
<Style x:Key="StyleForB" TargetName="B" TargetType="{x:Type Grid}" >
<Setter Property="Background" Value="Green"/>
</Style>
UPD:
I have a project with a lot of styles (aero, black, etc ).
And if I edit the element Style="{StaticResources StyleForA}" I must edit all styles.
So I need to create local style that affected to named element.
Natively you can't.
But without touching your XAML, you can do it very easily using code :
Grd1.Style = (Style) this.Resources["GridKey"];
Pure XAML approach using Blend behaviors,
<Grid x:Name="Grd1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<ic:ChangePropertyAction PropertyName="Style" Value="{DynamicResource GridKey}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
Yes. I use this style on my App.xaml to add a teplate around all aplication controls with error:
<Style x:Key="BordaTemplate" TargetType="Control">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder Name="myControl"/>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors).CurrentItem.ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource BordaTemplate}" />
<Style TargetType="PasswordBox" BasedOn="{StaticResource BordaTemplate}" />
<Style TargetType="DataGrid" BasedOn="{StaticResource BordaTemplate}" />
<Style TargetType="ListBox" BasedOn="{StaticResource BordaTemplate}" />
<Style TargetType="CheckBox" BasedOn="{StaticResource BordaTemplate}" />
<Style TargetType="ComboBox" BasedOn="{StaticResource BordaTemplate}" />
<Style TargetType="DatePicker" BasedOn="{StaticResource BordaTemplate}" />
Not like as you have defined using target but if you want to apply a style to a specific control. then use below:
<StackPanel>
<Button x:Name="A">
<Button.Resources>
<Style TargetType="{x:Type Button}" >
<Setter Property="Background" Value="Red"/>
</Style>
</Button.Resources>
content A</Button>
<Button x:Name="B">
<Button.Resources>
<Style TargetType="{x:Type Button}" >
<Setter Property="Background" Value="Green"/>
</Style>
</Button.Resources>
content B</Button>
</StackPanel>
Or probably create a base style and then create a BasedOn style for your controls.
Update: If you only want to be concerned about the style at a time and be sure of impacted elements:
<Window.Resources>
<Style TargetType="{x:Type Button}" x:Key="First" >
<Setter Property="Background" Value="Red"/>
</Style>
<Style TargetType="{x:Type Button}" x:Key="Second" >
<Setter Property="Background" Value="Green"/>
</Style>
</Window.Resources>
<StackPanel>
<Button x:Name="A">
<Button.Resources>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource First}" />
</Button.Resources>
content A</Button>
<Button x:Name="B">
<Button.Resources>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource Second}" />
</Button.Resources>
content B</Button>
</StackPanel>
I think you can have a default style and you can override the properties you want on your local style.
<Grid>
<Grid.Resources>
<Style TargetType="Button" x:Key="Default">
<Setter Property="Background" Value="White"></Setter>
<Setter Property="Foreground" Value="Blue"/>
</Style>
<Style x:Key="StyleForA" BasedOn="{StaticResource Default}" TargetType="Button" >
<Setter Property="Background" Value="Red" ></Setter>
</Style>
<Style x:Key="StyleForB" BasedOn="{StaticResource Default}" TargetType="Button" >
<Setter Property="Background" Value="Green" ></Setter>
</Style>
</Grid.Resources>
<StackPanel>
<Button Style="{StaticResource StyleForA}" Width="100" x:Name="A" Click="Button_Click" Height="100">Test A</Button>
<Button Style="{StaticResource StyleForB}" Width="100" x:Name="B" Click="Button_Click" Height="100">Test B</Button>
</StackPanel>
</Grid>
Related
I'm building WPF application and I want to use icons from Font Awesome. I have Font Awesome included in styles, and a font family specified in fields where I want to use it. The problem is icons are showing properly in the design window but change to crossed squares during runtime.
There is my Fonts XAML
<FontFamily x:Key="ArconRegular">pack://application;,,,/Fonts/#Arcon</FontFamily>
<FontFamily x:Key="ArconRounded">pack://application;,,,/Fonts/#Arcon Rounded-</FontFamily>
<FontFamily x:Key="FASolid">pack://application;,,,/Fonts/#Font Awesome 5 Free Solid</FontFamily>
<Style TargetType="{x:Type Control}" x:Key="BaseStyle">
<Setter Property="FontFamily" Value="{StaticResource ArconRegular}"/>
</Style>
<Style TargetType="{x:Type TextBlock}" x:Key="BaseTextBlockStyle">
<Setter Property="FontFamily" Value="{StaticResource ArconRegular}"/>
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource BaseStyle}"/>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource BaseStyle}"/>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource BaseStyle}"/>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BaseTextBlockStyle}"/>
<Style TargetType="{x:Type ListView}" BasedOn="{StaticResource BaseStyle}"/>
<system:String x:Key="FAMinimizeIcon"></system:String>
<system:String x:Key="FAMaximizeIcon"></system:String>
<system:String x:Key="FACloseIcon"></system:String>
The Buttons XAML (I want to use icons on buttons)
<Style TargetType="{x:Type Button}" x:Key="WindowControlButton" BasedOn="{StaticResource BaseStyle}">
<Setter Property="FontFamily" Value="{StaticResource FASolid}"/>
<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="Foreground" Value="{StaticResource ForegroundMainBrush}"/>
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform ScaleX="1.5"/>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{TemplateBinding Content}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource BackgroundLightBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
And finally MainWindow XAML (a part of it where i want to use them)
<!-- Window Buttons -->
<StackPanel Grid.Column="2" Orientation="Horizontal">
<Button Style="{StaticResource WindowControlButton}" Content="{StaticResource FAMinimizeIcon}" Command="{Binding MinimizeCommand}"/>
<Button Style="{StaticResource WindowControlButton}" Content="" Command="{Binding MaximizeCommand}"/>
<Button Style="{StaticResource WindowCloseButton}" Content="" Command="{Binding CloseCommand}"/>
</StackPanel>
As you can see, I tried specifying icon code in separate string and using StaticResource but nothing works.
In my case it was missing FontFamily="{TemplateBinding FontFamily}" in the ControlTemplate
Had a same issue, i.e Showing ok in Design mode but no Runtime. For me it was because fontawesome was not included in the assembly.
Changed (in visual studio) the .otf file's Build Action to "Resource". You may want to check if the file is included in your assembly by decompiler.
I have some buttons -in different windows- that have the same content. But if two windows surfaced together,out of the first window's button content disappears.
Buttons Style is :
<Style TargetType="{x:Type Button}" x:Key="BSaveBtn">
<Setter Property="Padding" Value="5"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Width" Value="70"/>
<Setter Property="Height" Value="68"/>
<Setter Property="Background" Value="{DynamicResource FlatGreen}"/>
<Setter Property="Template" Value="{DynamicResource FlatGreenBtnHover}"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Content">
<Setter.Value>
<StackPanel Orientation="Vertical" FlowDirection="RightToLeft">
<Image Width="30" Source="/login;component/img/buttonpic/save.png"/>
<TextBlock Text="save" FontSize="16" FontFamily="/login;component/fonts/#Droid Arabic Kufi" Foreground="White" HorizontalAlignment="Center"/>
</StackPanel>
</Setter.Value>
</Setter>
</Style>
button Code in windows is :
<Button Style="{DynamicResource BSaveBtn}" Template="{DynamicResource FlatGreenBtnHover}" />
problems occurs only with content -not another style properties- .
Seems to work fine for me when I tested it here.
A few things I noticed though that may help. You don't need them to be DynamicResource, they should really be StaticResource unless you plan on modifying them.
I assume you are declaring these in the Windows.Resource section or repeating them on each window?
If so you should centralize those to a ResourceDictionary.
Create a new Resource Dictionary put your style in there like so:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type Button}" x:Key="BSaveBtn">
<Setter Property="Padding" Value="5"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Width" Value="70"/>
<Setter Property="Height" Value="68"/>
<Setter Property="Background" Value="{DynamicResource FlatGreen}"/>
<Setter Property="Template" Value="{DynamicResource FlatGreenBtnHover}"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Content">
<Setter.Value>
<StackPanel Orientation="Vertical" FlowDirection="RightToLeft">
<Image Width="30" Source="/login;component/img/buttonpic/save.png"/>
<TextBlock Text="save" FontSize="16" FontFamily="/login;component/fonts/#Droid Arabic Kufi" Foreground="White" HorizontalAlignment="Center"/>
</StackPanel>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Then in your App.xaml put the following:
<ResourceDictionary>
<ResourceDictionary Source="MyResources.xaml" />
</ResourceDictionary>
The Image should really be in a dictionary to avoid loading it multiple times. Just add a line in that ResourceDictionary like so:
<BitmapImage UriSource="/login;component/Images/Save.png" x:Key="Save" PresentationOptions:Freeze="True" />
Setting the PresentationOptions:Freeze will also help if the image is never being modified.
Your call to the image would then change to be:
<StackPanel Orientation="Vertical" FlowDirection="RightToLeft">
<Image Width="30" Source="{StaticResource Save}"/>
<TextBlock Text="save" FontSize="16" FontFamily="/login;component/fonts/#Droid Arabic Kufi" Foreground="White" HorizontalAlignment="Center"/>
</StackPanel>
Once your resources are centralized in a ResourceDictionary (or multiple) it makes it easy to apply those same styles anywhere in your application and hopefully will help with your issue. If not please give more info on the problem you have such as sample code to make the issue happen please.
An instance of an element can only appear once in the visual tree. You can set the x:Shared attribute of the Style to False in order for a new instance of the StackPanel to get created for each Button to which you apply the style:
<Style TargetType="{x:Type Button}" x:Key="BSaveBtn" x:Shared="False">
<Setter Property="Padding" Value="5"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Width" Value="70"/>
<Setter Property="Height" Value="68"/>
<Setter Property="Background" Value="{DynamicResource FlatGreen}"/>
<Setter Property="Template" Value="{DynamicResource FlatGreenBtnHover}"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Content">
<Setter.Value>
<StackPanel Orientation="Vertical" FlowDirection="RightToLeft">
<Image Width="30" Source="/login;component/img/buttonpic/save.png"/>
<TextBlock Text="save" FontSize="16" FontFamily="/login;component/fonts/#Droid Arabic Kufi" Foreground="White" HorizontalAlignment="Center"/>
</StackPanel>
</Setter.Value>
</Setter>
</Style>
I'm getting XAML parse exceptions when using a certain GroupBox Style more than once. I'm keeping the style in UserControl.Resources.
Here is an example of a simplified style that does not cause a XAML parse exception:
<Style x:Key="MyGroupBoxStyle" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}">
<Setter Property="BorderThickness" Value="5" />
<Setter Property="Header" Value="Hello World!" />
</Style>
Here is another one that does not cause a problem.
<Style x:Key="MyGroupBoxStyle" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}">
<Setter Property="BorderThickness" Value="5" />
<Setter Property="Header">
<Setter.Value>
Hello World!
</Setter.Value>
</Setter>
</Style>
This one however does cause a problem:
<Style x:Key="MyGroupBoxStyle" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}">
<Setter Property="BorderThickness" Value="5" />
<Setter Property="Header">
<Setter.Value>
<TextBlock Text="Hello World!" />
</Setter.Value>
</Setter>
</Style>
Again, it's only a problem when I use the style on more than one GroupBox. If I use it just once, I don't get the XAML parse exception. And it doesn't have to be just a TextBlock. I think it's any UIElement.
Any ideas? Thanks!
You cannot set the content of the header to another UI control in the style. Try creating a datatemplate.
<Window.Resources>
<Style x:Key="MyGroupBoxStyle" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}">
<Setter Property="BorderThickness" Value="5" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="Hello World!!!!!!"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel>
<GroupBox Style="{StaticResource MyGroupBoxStyle}" Height="200" Width="200"/>
<GroupBox Style="{StaticResource MyGroupBoxStyle}" Height="200" Width="200"/>
</StackPanel>
I'm trying to make a wpf style that will allow me to:
1. Base alternate styles off a base style
2. Have the base style be a default that every control uses when no style is applied.
For example, I have code to make style for a button...
<!--Base Button-->
<Style TargetType="Button" x:Key="BaseButton">
<Setter Property="Width" Value="auto"/>
<Setter Property="MaxWidth" Value="100"/>
<Setter Property="Height" Value="auto"/>
<Setter Property="MaxHeight" Value="50"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Hand"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value=".85"/>
</Trigger>
</Style.Triggers>
</Style>
<!--Apply Base to any Button without a style-->
<Style TargetType="Button" BasedOn="{StaticResource BaseButton}"/>
and here is a style for a specific button...
<Style TargetType="Button" x:Key="DeleteBtn" BasedOn="{StaticResource BaseButton}">
<Setter Property="Width" Value="100"/>
<Setter Property="Height" Value="35"/>
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="(some url)" Height="16" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Label Content="Delete" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
As you can see, I would like to be able to base the "DeleteBtn" Style off of the base, but also have the base be the default for every button placed on the screen that doesn't have a specific style set. This currently only works for buttons and no other control. The above example does work, but I can't seem to do the same thing for labels, textboxes etc. Any thoughts or input would be greatly appreciated :)
Here's an example of one that doesn't work..
<!--Base Icon-->
<Style TargetType="Image" x:Key="BaseIcon">
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="HorizontalAlignment" Value="Right"/>
</Style>
<!--Apply Base to any Icon without a style-->
<Style TargetType="Image" BasedOn="{DynamicResource BaseIcon}"/>
It gives an error: 'DynamicResourceExtension' cannot be set on the 'BasedOn' property of type 'Style'. A 'DynamicResourceExtension' can only be set on a DependencyProperty of a DependencyObject.
Your example only works for Buttons because your "base" style is targeting buttons only.
i.e.
TargetType="Button"
You can try creating a style that targets the parent FrameworkElement instead. Just be warned that not all properties are supported. Some properties are unique to the child control.
It works for me, just tested it.
<Window.Resources>
<Style TargetType="Label" x:Key="BaseLabel">
<Setter Property="Background" Value="Red"/>
<Setter Property="HorizontalContentAlignment" Value="Right"/>
</Style>
<Style TargetType="Label" BasedOn="{StaticResource BaseLabel}"/>
</Window.Resources>
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Bottom" Orientation="Horizontal">
<Label Width="100" Content="TestLabel1"/>
<Label Width="100" Content="TestLabel1" Foreground="White"/>
</StackPanel>
</Grid>
Edit: Added derived right alignment for fun.
I want to write a style for wpf where all buttons in a StatusBar (that has a defined style) have the same style (e.g. width).
Here is what my style looks like:
<Style TargetType="{x:Type StatusBar}"
x:Key="DialogBoxStatusBarStyle">
<Setter Property="Background"
Value="LightGray" />
<Setter Property="Padding"
Value="5" />
...?
</Style>
And the xaml for the elements:
<StatusBar Style="{StaticResource ResourceKey=DialogBoxStatusBarStyle}" Grid.Row="3"
FlowDirection="RightToLeft">
<Button Content="Übernehmen"
Width="100"
HorizontalAlignment="Right" />
<Button Content="Abbrechen"
Width="100"
HorizontalAlignment="Right" />
<Button Content="OK"
Width="100"
HorizontalAlignment="Right" />
</StatusBar>
In the final version I don't want to set width to 100 for all buttons. This should be defined in the style of the StatusBar or better say in the style of the button-childs of the StatusBar.
You could add a default Style for Buttons to the Resources of your DialogBoxStatusBarStyle:
<Style TargetType="StatusBar" x:Key="DialogBoxStatusBarStyle">
<Style.Resources>
<Style TargetType="Button">
<Setter Property="Width" Value="100"/>
</Style>
</Style.Resources>
...
</Style>
To extend on the answer above (#Clemens), you could even do something like this, to reuse a button style independently, and also apply it to children of a specific container.
Styles:
<Style TargetType="{x:Type Button}" x:Key="MyButtonStyle">
<Setter Property="Width" Value="100" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style TargetType="{x:Type StatusBar}" x:Key="DialogBoxStatusBarStyle">
<Setter Property="Background" Value="LightGray" />
<Setter Property="Padding" Value="5" />
<Style.Resources>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MyButtonStyle}" />
</Style.Resources>
...
</Style>