WPF Remove Butto DropShadowEffect on click by ControlTemplate - wpf

In a Button ControlTemplate I need to access the IsPressed event. How do I do that?
Background: I added a drop DropShadowEffect to a Button Style but got blurry text. This fix solved the blurry text issue. However this added a new issue. I wanted to remove the DropShadowEffect when the user clicks on the button. Figured I would do it like this;
<Style x:Key="DropShadowButtons" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Border Background="{TemplateBinding Background}">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="Border.Effect">
<Setter.Value>
<DropShadowEffect Color="Black" Opacity="0.5" />
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Button.IsPressed" Value="False">
<Setter Property="Border.Effect">
<Setter.Value>
<DropShadowEffect Color="Black" Direction="320" ShadowDepth="0" BlurRadius="0" Opacity="0" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,2,5,0"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
Then figured out that Button.IsPressed would not fire being part of the Border. So how does the ControlTemplate access the event IsPressed of the Button?

You just need the trigger on the ControlTemplate instead of the Border's Style. For the Setter to target the Border, you'll need to give the Border a name, and you'll need to give the Setter a TargetName:
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Border x:Name="BackgroundBorder" Background="{TemplateBinding Background}">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="Border.Effect">
<Setter.Value>
<DropShadowEffect Color="Black" Opacity="0.5" />
</Setter.Value>
</Setter>
</Style>
</Border.Style>
</Border>
<Border Background="{TemplateBinding Background}">
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="5,2,5,0"
/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="BackgroundBorder" Property="Effect">
<Setter.Value>
<DropShadowEffect
Color="Black"
Direction="320"
ShadowDepth="0"
BlurRadius="0"
Opacity="0"
/>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

Related

Need help overriding a WPF button style background color.

I have the below code set for a custom button. But I want to change the background for a single button.
<Style x:Key="myButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="rectangle" Fill="#FF2F2FEA" Stroke="Black">
<Rectangle.Effect>
<DropShadowEffect ShadowDepth="3"/>
</Rectangle.Effect>
</Rectangle>
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Bottom" Margin="2.833,0,2.5,1.162" RenderTransformOrigin="0.5,0.5" Width="69.667"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
The code below is meant to override the background color but doesn't. What am I missing? Thanks
<Style x:Key="SpecialButton" TargetType="Button" BasedOn="{StaticResource myButtonStyle}">
<Setter Property="Background" Value="PaleGreen" />
<Setter Property="Height" Value="19.96" />
</Style>
Add <Setter Property="Background" Value="#FF2F2FEA" /> to the myButtonStyle. And change the Fill on the Rectangle to Fill="{TemplateBinding Background}"
<Style x:Key="myButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="#FF2F2FEA" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="rectangle" Fill="{TemplateBinding Background}" Stroke="Black">
<Rectangle.Effect>
<DropShadowEffect ShadowDepth="3"/>
</Rectangle.Effect>
</Rectangle>
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="Bottom"
Margin="2.833,0,2.5,1.162"
RenderTransformOrigin="0.5,0.5" Width="69.667"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
After this, the two Buttons should show up properly.
<StackPanel>
<Button Content="BASE" Style="{StaticResource myButtonStyle}"></Button>
<Button Content="DERIVED" Style="{StaticResource SpecialButton}"></Button>
</StackPanel>
Result:
Explanation: if you change the Template of a Control you have to "wire-up" its properties (like Background, Foreground, HorizontalContentAlignment etc) to properties of elements in the ControlTemplate. After all you want to give the ability to end users of the control to modify the color, alignment etc, and not just have a Control with a static visual tree.

How to change the background of a GridSplitter when focused/dragged in XAML (with a border)?

I found it weird that there's no GridSplitter property like "DragBackground" or something alike.
This seems to work though:
<UserControl.Resources>
<Style x:Key="CustomGridSplitterStyle" TargetType="GridSplitter">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridSplitter">
<Grid x:Name="Root" >
<!-- Background -->
<Rectangle Fill="White" StrokeThickness="0" />
<!-- Focus Visual -->
<Rectangle x:Name="FocusVisual" Stroke="White" StrokeThickness="1" Opacity="0" IsHitTestVisible="false" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
 
GridSplitter Style="{StaticResource CustomGridSplitterStyle}" Grid.Column="1" Width="6" HorizontalAlignment="Stretch"
BorderThickness="2,0,0,0" BorderBrush="Blue" />
My problem with this solution however is that I'd like to set a border on the left side of the GridSplitter (see above), which doesn't work when using the custom GridSplitter style.
Does anybody know how to get this working ?
If you want to use BorderBrush and BorderThickness in your Template you can use TemplateBinding on some Border. You can also use Setter in your Style to define some default value.
<Style x:Key="CustomGridSplitterStyle" TargetType="{x:Type GridSplitter}">
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="White"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridSplitter">
<Border
x:Name="FocusVisual"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"/>
<ControlTemplate.Triggers>
<Trigger Property="IsDragging" Value="True">
<Setter TargetName="FocusVisual" Property="..." Value="..." />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Also since GridSplitter is a Thumb and as such has IsDragging property so you can create Trigger to do something when it is true as in the example above

Wpf vertical progress bar styling

could you please help with styling vertical progress bar with solid color?
I've been able to create this style
<Style TargetType="{x:Type ProgressBar}" x:Key="{x:Type ProgressBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ProgressBar}">
<Grid>
<Rectangle Name="PART_Track" StrokeThickness="1" >
<Rectangle.Fill>
<SolidColorBrush Color="#FF00FF00"></SolidColorBrush>
</Rectangle.Fill>
</Rectangle>
<DockPanel Margin="1">
<Rectangle Name="PART_Indicator">
</Rectangle>
<Rectangle Name="Mask" MinWidth="{TemplateBinding Width}" Fill="#C0C0C0"/>
</DockPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But it still is oriented horizontally and I don't know how to change it.
There is a ControlTemplate.Triggers in the default Template. This trigger rotates the angle by -90°.
If you add
<ControlTemplate.Triggers>
<Trigger Property="Orientation" Value="Vertical">
<Setter Property="LayoutTransform" TargetName="TemplateRoot">
<Setter.Value>
<RotateTransform Angle="-90"/>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
to your control and name the parenting grid "TemplateRoot" you can set the orientation.
Here's your template
<Style TargetType="{x:Type ProgressBar}" x:Key="{x:Type ProgressBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ProgressBar}">
<Grid x:Name="TemplateRoot">
<Rectangle Name="PART_Track" StrokeThickness="1" >
<Rectangle.Fill>
<SolidColorBrush Color="#FF00FF00"></SolidColorBrush>
</Rectangle.Fill>
</Rectangle>
<DockPanel Margin="1">
<Rectangle Name="PART_Indicator">
</Rectangle>
<Rectangle Name="Mask" MinWidth="{TemplateBinding Width}" Fill="#C0C0C0"/>
</DockPanel>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Orientation" Value="Vertical">
<Setter Property="LayoutTransform" TargetName="TemplateRoot">
<Setter.Value>
<RotateTransform Angle="-90"/>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

wpf mouseover fill rectangle

I have Grid in wpf. When I do mouseover on rectangle, I can see color change. But when I do mouseover on content, I see original color of rectangle.
What should I write to apply same mouseover effect on ContentPresenter or is there any way to change rectangle background color on mouse over of content presenter.
<Grid Background="{TemplateBinding Background}" x:Name="dgColumnHeader">
<Border x:Name="border" BorderBrush="Black" BorderThickness="0,0,1,1" Grid.ColumnSpan="1">
<Rectangle Width="116" Margin="3,3,3,3" HorizontalAlignment="Center" RadiusX="7" RadiusY="7">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="{DynamicResource ContentOutofFocusBrush}"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Fill" Value="{DynamicResource ActiveItemBrush}" />
</Trigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</Border>
<ContentPresenter x:Name="content" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}" />
</Grid>
Thanks
Dee
If the grid is part of your control template then it is better to move the rectangle style trigger into ControlTemplate.Triggers:
<Window x:Class="Presentation2.MouseOverRectangleWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MouseOverRectangleWindow" Height="300" Width="300">
<Window.Resources>
<SolidColorBrush x:Key="ContentOutofFocusBrush" Color="Orange"/>
<SolidColorBrush x:Key="ActiveItemBrush" Color="Blue" />
<Style x:Key="MouseOverContentControlStyle" TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Grid Background="{TemplateBinding Background}" x:Name="dgColumnHeader">
<Border x:Name="border" BorderBrush="Black" BorderThickness="0,0,1,1" Grid.ColumnSpan="1">
<Rectangle x:Name="PART_Rectangle" Width="116" Margin="3,3,3,3" HorizontalAlignment="Center" RadiusX="7" RadiusY="7">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="{DynamicResource ContentOutofFocusBrush}"></Setter>
</Style>
</Rectangle.Style>
</Rectangle>
</Border>
<ContentPresenter x:Name="content" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="PART_Rectangle" Property="Fill" Value="{DynamicResource ActiveItemBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<ContentControl Style="{StaticResource MouseOverContentControlStyle}">
<TextBlock Text="Hello World!" />
</ContentControl>
</Grid>
</Window>
you don't need a rectangle inside your Border. Change the Background of the Border, you ll have same result. Then put the ContentPresenter inside that Border, and set the MouseOver handler on the Border, it should work fine.

Buttons are disabled in Custom control

I have made a custom control in wpf however I am having an issue with the button that forms a part of the item control (the x in each item element in the attached picture is the button) basically the button is disabled, but I am not disabling it!
If I just place one of the inner items (MultiSelectionItem) into a grid by itself then the button works fine, so it must have something to do with my usage of the ItemsControl element in the Template for the outer control (MultiSelectionBox)
Image:
<Style TargetType="{x:Type local:MultipleSelectionBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MultipleSelectionBox}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ItemsControl ItemsSource="{Binding multipleSelectionItems}">
<ItemsControl.Template>
<ControlTemplate>
<WrapPanel IsItemsHost="True"/>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type local:MultipleSelectionItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MultipleSelectionItem}">
<Border BorderBrush="#FFC0CBD9" BorderThickness="1" Margin="0,0,2,2" CornerRadius="0">
<Border.Style>
<Style TargetType="Border">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFDFE9F5" Offset="0" />
<GradientStop Color="#FFEEF3FC" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Command="{x:Static local:MultipleSelectionItemCommands.RemoveCommand}" IsEnabled="True">
<Button.Template>
<ControlTemplate>
<Image Source="/CustomFormResearch;component/Images/x_no_hover.jpg" Margin="2,0,0,0" Height="11" Width="11">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="/CustomFormResearch;component/Images/x_no_hover.jpg" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Source" Value="/CustomFormResearch;component/Images/x_with_hover.jpg" />
</Trigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ControlTemplate>
</Button.Template>
</Button>
<TextBlock Text="{Binding DisplayData}" VerticalAlignment="Stretch" Margin="5,0,5,0" Grid.Column="1" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My first guess is that since your button is bound to a Command, the CanExecute of the command should return false.
This is the principle and benefit of a Command: When the can execute returns false it automaticaly disable the associated button.
Check this links for more about commands and MVVM :
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
http://msdn.microsoft.com/fr-fr/magazine/cc785480.aspx#id0190094

Resources