Proper way to override style values in WPF - c#

I want to edit a the cell style of a DataGrid in WPF. So using Expression Blend I right go to - Objects and Timeline>>DataGrid>>Edit Additional Templates>>Edit CellStyle>>Edit a Copy
Here's what what appears on the page:
<SolidColorBrush x:Key="{x:Static DataGrid.FocusBorderBrushKey}" Color="#FF000000"/>
<Style x:Key="DataGridCellStyle1" TargetType="{x:Type DataGridCell}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
</Trigger>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static DataGrid.FocusBorderBrushKey}}"/>
</Trigger>
</Style.Triggers>
</Style>
But I only want to change the padding and background. Instead it has given me 25 lines of code, including the cell template! Am I missing something, is there a better way of styling items like this without having to bring so much extra unnecessary code when I only want to change two items?

Check out the "BasedOn" attribute for Styles...
For example the following style takes everything from DataGridColumnHeader and only overrides the HorizontalContentAlignment property:
<Style x:Key="CenterAlignedColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}"
BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>

Overriding control templates in WPF requires you to completely replace the template. You may have wanted to change just the one aspect of the template but the result of that is Expression dumping a copy of the rest of the template so that it can be overridden. Make sure you're overriding the cell in the proper way (I'm not sure there's another way). Some controls (ListView comes to mind) will let you swap out data templates without overriding the entire control template, but I'm not sure that's what you want, or if it can be done with DataGrid.
See the answer to this: Replace part of default template in WPF

To do what you want to do, you would usually just set the background and Padding properties in a style:
<Style TargetType="DataGridCell">
<Setter Property="Padding" Value="10" />
<Setter Property="Background" Value="Green" />
</Style>
However in this case it seems that the default control template for DataGridCell ignores the padding value, so you will need to replace it with an implementation that doesn't. The following is based on the default template that you posted:
<Style TargetType="DataGridCell">
<Setter Property="Padding" Value="10" />
<Setter Property="Background" Value="Green" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<ContentPresenter
Margin="{TemplateBinding Padding}" <!-- this bit does the padding -->
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Related

How can I change Button color via a trigger in the button?

Whats wrong with this trigger? I found it here: http://www.wpf-tutorial.com/styles/trigger-datatrigger-event-trigger/ and ive seen similar setups on SO
<Button x:Name="ColorPickerButton" Background="{Binding SelectedColor}">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Im trying to break down my spaghetti XAML and make it more readable. This is my old implementation which does work. I dont like it because it overwrites the button content and overlays a border which seems unnecessary. Also its massive
<Button x:Name="ColorPickerButton" Background="{Binding SelectedColor}">
<Button.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Bd"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="true">
<GridViewRowPresenter/>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="BorderBrush" Value="{StaticResource ColorPickerButton.MouseOver.Border}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Resources>
</Button>
Your Trigger does not work because the default Template of the button has its own trigger that changes the background brush of the root border when the IsMouseOver Property is set. This means: As long as the mouse is on top of the button, the Background-property of the button control will be ignored by its template.
The easiest way to check out the default style of your button is to: right-click at the button in the visual studio wpf designer. Click 'Edit template' -> 'Edit a copy' and select a location.
A copy of the default style is created at the specified location. You will see a trigger like this:
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
</Trigger>
On top of designer created style definition it also created the brushes that are used within the style:
<SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
<SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
You can either change these brushes or the Value property of the setters above to change the background when the mouse is over.
Or you create your own Template like you did in your old implementation.

How to apply my template in XAML button style while keeping background color?

I have the following style in a Styles.xaml file:
<Style x:Key="MainViewButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<SymbolIcon Symbol="{TemplateBinding Content}" Foreground="#FFF7F7F7" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="#FF55677F"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Height" Value="40"/>
</Style>
When I launch my project, the template is applied, as the buttons contain their Content SymbolIcon, but they don't have any background color even thought it is specified in the style after the template. They just are transparent. How come?
Your control template overrides any styles you set. If your ControlTemplate does not respect the styles, you don't get anything you set.
You can put the Setters for background and others above the Template setter and then use TemplateBinding to set the properties inside your SymbolIcon. If your SymbolIcon does not have any background property, alas, you can't do it.
You can, however, use a Border and put SymbolIconIn it. Here's how I would do it:
<Style x:Key="MainViewButton" TargetType="Button">
<Setter Property="Background" Value="#FF55677F"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Height" Value="40"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}" Height="{TemplateBinding Height}">
<SymbolIcon Symbol="{TemplateBinding Content}" Foreground="#FFF7F7F7" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Basic WPF ToggleButton Template

I require a toggle button that has not border when IsChecked = False and has a simple 1pt border of a certain color when IsChecked = True. I have the following style but my border when the button IsChecked = True is being set to Transparent (using Snoop to inspect)
<Style x:Key="InfoToggleButton"
TargetType="{x:Type ToggleButton}">
<Setter Property="Background" Value="#EEEEF2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border CornerRadius="0"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter x:Name="contentPresenter"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="BorderBrush" Value="#007ACC"/>
<Setter Property="BorderThickness" Value="1"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The button works and displays properly, but when I check/click it, the border does not get displayed.
I implement this style like
<ToggleButton Grid.Column="0"
Style="{StaticResource InfoToggleButton}"
IsChecked="{Binding IsDisplayingBetInfo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Content="{Binding BetInfoIconSource}"/>
How can I get a simple toggle button with border?
Thanks for your time.
I've figured out the problem and the solution but don't exactly know why it happens.
Problem: Some value other than {x:Null} must be set as the content of the toggle button.
Solution: However, a blank string can be set as the content.
My reasoning: When no content is set, the ContentPresenter is null and thus cannot be clicked.
The problem can be solved by setting the default content to "" like this:
<Style x:Key="InfoToggleButton"
TargetType="{x:Type ToggleButton}">
<Setter Property="Background" Value="#EEEEF2"/>
<Setter Property="Content" Value=""/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border CornerRadius="0"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter x:Name="contentPresenter"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="BorderBrush" Value="#007ACC"/>
<Setter Property="BorderThickness" Value="1"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
you have to assign a name at the Border tag like in this way
<Border x:Name="MyBorderName"...
then the you have to assign the TargetName at the property.
Example
<Setter TargetName="MyBorderName" Property="BorderBrush" Value="#007ACC"/>
<Setter TargetName="MyBorderName" Property="BorderThickness" Value="1"/>
Otherwise WPF does not know who to assign the Property BorderBrush and BorderThickness

remove blue highlight on buttons wpf

I am making a WPF project. While running the application, as I take my cursor to a button, it gets highlighted by blue color filled inside it.
Now, I want to remove this highlight...
How do I do so?
The link isn't working for me, so I can't see exactly what you are getting at, but I assume that you're trying to change that default blue-ish gradient. You need to override the template for the button in a style, and then you can customize it to look however you want. You can't just set the background color or use triggers to change it without overriding the template, because the default template has some extra stuff in it to show that gradient effect.
Here is an example of a button I have used before that is fairly straightforward. This example uses a trigger to change the foreground color of the button when it is pressed, but will never change the background color.
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="White"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Foreground" Value="{StaticResource BrushBtnText}"/>
<Setter Property="Margin" Value="8,4,8,4"/>
<Setter Property="Padding" Value="6"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="{StaticResource BrushBorderLight}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Margin="{TemplateBinding Margin}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="{StaticResource BrushBtnText}"/>
</Trigger>
</Style.Triggers>
</Style>
Also, if you're interested, here is what the button's default template is:
<Style TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Themes:ButtonChrome x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}" RenderDefaulted="{TemplateBinding IsDefaulted}" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Themes:ButtonChrome>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="RenderDefaulted" TargetName="Chrome" Value="true"/>
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter Property="RenderPressed" TargetName="Chrome" Value="true"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#ADADAD"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Actually, I found the thing where I was going wrong. Whenever my pointer goes to a button, does not change the background of the button or even the foreground of the button, but it changes the background of the border.
So, while overwriting the button style, actually the border of the background has to be overwritten and not the button foreground or the background.
Here is the answer to this question : How to Disable MouseOver Effects

Remove Border around Button

I've been trying to remove the Border around a Button and also change the Colour of the Button's Background when the mouse hovers over it.
Here is what I have:
<Button Name="Home" Content="Home" HorizontalAlignment="Left" Width="75" Click="Button_Click_Home" Background="#FF252525" FontFamily="/VideoManager;component/#Myriad Pro" FontSize="13.333" Foreground="White" BorderThickness="5">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="0"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FF36290A"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
The issue is that regardless of what I set BorderThickness to, the Button disappears. Also the Button is not changing to the colour I specified with the Trigger.
I also tried simply using a Style Setter but found this had no effect on my Button.
<Style TargetType="{x:Type Button}">
<Setter Property="BorderThickness" Value="0"/>
</Style>
You need to define following ControlTemplate and remove Style Trigger.
<ControlTemplate TargetType="{x:Type Button}">
<Border Name="border"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="border"
Property="Background"
Value="#FF36290A" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
I have tried this and this is working.
I have a style that I use to remove the default Windows style from buttons ; I'm sure you can use it or use it to achieve what you want. As it is, it just makes a button with absolutely no border, no background, no margins, nothing, just play with the template to achieve what you want :
<Style x:Key="NoChromeButton" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="Chrome" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#ADADAD"/>
<Setter Property="Opacity" TargetName="Chrome" Value="0.5"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Hand"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
It is not mine but I don't remember where I found it, so sorry if the author come by !
You could also take the default button template from MSDN and tweak it.

Categories