WPF buttons (image & label) shadowing - wpf

I want to create buttons which have a image and a text included and get a nice shadowing. Particularly, I want the image and label have a light grey shadowing, but when moving the mouse over the button I'd like a kind of blue shadowing. Moving away sets it back to light grey. I would need some help as I just can't figure out how to achive it (I'm new to WPF).
The Buttons looks like ...
<Button>
<Button.Content>
<StackPanel Orientation="Vertical">
<Image Source="Images/preferences-system.png" />
<Label HorizontalAlignment="Center">Settings</Label>
</StackPanel>
</Button.Content>
</Button>
The Canvas goes ...
<Canvas DockPanel.Dock="Left" Background="#FF349EBC">
<Canvas.Resources>
<DropShadowEffect x:Key="dropMouseOverShadow" Color="#FFD9EDF3" Opacity="80" Direction="270" />
<DropShadowEffect x:Key="dropLightShadow" Color="LightGrey" Opacity="10" Direction="270" BlurRadius="20" />
<Style TargetType="{x:Type Button}">
<Style.Setters>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Foreground" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" CornerRadius="2">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Effect" Value="{StaticResource dropMouseOverShadow}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
<Style TargetType="{x:Type Image}">
<Style.Setters>
<Setter Property="Effect" Value="{StaticResource dropLightShadow}" />
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Effect" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type Label}">
<Style.Setters>
<Setter Property="FontSize" Value="18" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontFamily" Value="Gill Sans MT" />
<Setter Property="Effect" Value="{StaticResource dropLightShadow}" />
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Effect" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
</Canvas.Resources>
What I get is a light grey shadowing on image and labels on begin. Moving the mouse over the button the grey and light blue get mixed. When moving further on the image it gets the light blue only. The same goes for the label.
How can I achive switching the shadowning to light blue when I mouse over the button and not the image and label itself? Anyone an idea or an completly other approach?

Apply the LightGray Effect to the ContentPresenter. Then on the IsMouseOver Trigger, set the Effect property of the ContentPresenter to the blue Effect.
NOTE: Accomplish this by setting the x:Name attribute of the ContentPresenter, then accessing the ContentPresenter by name via the Setter using TargetName.
NOTE: Remove the various other Effect settings in the styles of the child elements. Applying the Effect to the ContentPresenter causes the child elements to inherit the Effect.
<Canvas DockPanel.Dock="Left" Background="#FF349EBC">
<Canvas.Resources>
<DropShadowEffect x:Key="dropMouseOverShadow" Color="#FFD9EDF3" Opacity="80" Direction="270" />
<DropShadowEffect x:Key="dropLightShadow" Color="LightGrey" Opacity="10" Direction="270" BlurRadius="20" />
<Style TargetType="{x:Type Button}">
<Style.Setters>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Foreground" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" CornerRadius="2">
<ContentPresenter x:Name="cp" Effect="{StaticResource dropLightShadow}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="cp" Property="Effect" Value="{StaticResource dropMouseOverShadow}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
<Style TargetType="{x:Type Label}">
<Style.Setters>
<Setter Property="FontSize" Value="18" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontFamily" Value="Gill Sans MT" />
</Style.Setters>
</Style>

Related

How to set WPF Button TextBlock style from another resource?

I'm setting in a WPF application the style of a button with this:
<Style TargetType="{x:Type Button}">
<Setter Property="ToolTipService.InitialShowDelay" Value="0"/>
<Setter Property="Height" Value="22" />
<Setter Property="Margin" Value="1" />
<Setter Property="Padding" Value="0" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
Padding="{TemplateBinding Padding}"
BorderThickness="1">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="1 -1 1 0"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="{StaticResource NotSelectedButton}" />
<Setter Property="Foreground" Value="{StaticResource ActiveFg}" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource Selected}" />
<Setter Property="Foreground" Value="{StaticResource SelectedFg}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="{StaticResource NotSelectedButton}" />
<Setter Property="Foreground" Value="{StaticResource ActiveFg}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{StaticResource NotSelectedButton}" />
<Setter Property="Foreground" Value="{StaticResource InactiveFg}" />
<!--<Setter Property="Foreground" Value="{StaticResource NotSelected}" />-->
</Trigger>
</Style.Triggers>
</Style>
However I want the TextBlock in the ContentPresenter to use a named TextBlock style defined as such:
<Style x:Key="ButtonText" TargetType="{x:Type TextBlock}">
<Setter Property="ToolTipService.InitialShowDelay" Value="0"/>
<Setter Property="Width" Value="auto" />
<Setter Property="MinWidth" Value="20" />
<Setter Property="TextAlignment" Value="Left" />
<Setter Property="Padding" Value="0 0 0 0" />
<Setter Property="Margin" Value="1 0 0 0" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
To test this style, just a Button in a UserControl or Window suffices: <Button>, and the style definitions can go in a resource dictionary (of UserControl or Window).
How can I do this ?
Trivial Solution via Direct Assignment
You can set the style directly by assigning a TextBlock as Content of each Button.
<Button>
<TextBlock Text="Test" Style="{StaticResource ButtonText}"/>
</Button>
Support Text As Content Only
If you are sure that you only put strings as content into your button, you can assign a ContentTemplate that contains a TextBlock to the ContentPresenter. This will not work for other content types in the sense that it would not display them as usual, but just their type name in the TextBlock.
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="1 -1 1 0">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource ButtonText}" Text="{Binding}"/>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
Support All Content Types
If you want to support any content type as content of your button, you can define the data template from above in the ContentPresenter.Resources. Then, the ContentPresenter will only apply it, if the Content is a string. For all other content types it will work as usual.
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="1 -1 1 0">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type system:String}">
<TextBlock Style="{StaticResource ButtonText}" Text="{Binding}"/>
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>

Changing the button label foreground on focus with label inside content

I have a button that I need to change the background and foreground color of when the button is in focus. I have the background color change working, but cannot get the foreground color change (on the label) to work.
I want to do this in XAML only.
My Button:
<Button Style="{StaticResource ModButtonWhite}"
Name="btnConnect"
Height="30"
Click="btnConnect_Click"
Width="75"
Margin="0,0,15,0">
<Label Name ="btnConnectLabel" Content="Re-_Connect" />
</Button>
My Style:
<Style TargetType="Button"
x:Key="ModButtonWhite">
<Setter Property="Foreground"
Value="White" />
<Setter Property="Background"
Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
CornerRadius="5"
BorderThickness="1"
BorderBrush="White">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsFocused"
Value="True">
<Setter Property="Background"
Value="White" />
<Setter Property="Foreground"
Value="DeepSkyBlue" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Resources>
<Style TargetType="Label">
<Setter Property="Foreground"
Value="White" />
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Foreground"
Value="DeepSkyBlue" />
</Trigger>
</Style.Triggers>
</Style>
</Style.Resources>
<Style.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="White" />
<Setter Property="Opacity"
Value=".4" />
<Setter Property="Foreground"
Value="DeepSkyBlue" />
</Trigger>
</Style.Triggers>
All you need to do is to bind the Label.Foreground to the Button.Foreground. No need of any additional styles defined in the Style.Resources dictionary. Just the plain style to override the Button.Template:
<Window>
<Window.Resources>
<Style TargetType="Button"
x:Key="ModButtonWhite">
<Setter Property="Foreground"
Value="White" />
<Setter Property="Background"
Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="{TemplateBinding Background}"
CornerRadius="5"
BorderThickness="1"
BorderBrush="White">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsFocused"
Value="True">
<Setter Property="Background"
Value="White" />
<Setter Property="Foreground"
Value="DeepSkyBlue" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Button Style="{StaticResource ModButtonWhite}">
<Label Content="Click me!"
Foreground="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}" />
</Button>
</Window>

How to set a border around listviewitem in WPF

My ListView should have following style:
no border around the whole ListView (achieved)
no highlighting when interacting with ListViewItem (achieved)
border around selected ListViewItem (missing)
My ListView:
<ListView DisplayMemberPath="Name" BorderThickness="0" >
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<!-- get rid of the highlighting -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
<!-- style selected item -->
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontSize" Value="20" />
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
I tried this and this, both doesn't work for me. I guess my problem is the template but I have no idea how to put a border around the selected ListViewItem.
Update
Working solution:
<ListView DisplayMemberPath="Name" BorderThickness="0" >
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<!-- get rid of the highlighting -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border x:Name="Border">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontSize" Value="20" />
<Setter Property="FontWeight" Value="Bold" />
<Setter TargetName="Border" Property="BorderBrush" Value="Black"/>
<Setter TargetName="Border" Property="BorderThickness" Value="2"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Maybe this works. Add a Border around ContentPresenter an use controlTemplate Triggers
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Border x:Name="Border">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontSize" Value="20" />
<Setter Property="FontWeight" Value="Bold" />
<Setter TargetName="Border" Property="BorderBrush" Value="Red"/>
<Setter TargetName="Border" Property="BorderThickness" Value="1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

WPF Datagrid Selected Row Color and Centered Text

I have a simple DataGrid where I want to Style the selected row and center the text. I have tried the following and it does not work:
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Blue" />
<Setter Property="Foreground" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
Why will the above not work together? If I remove the trigger, it will center but the color I want will not be used.
Try add Grid to the ControlTemplate of DataGridCell style:
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter Margin="2"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="White" />
<Setter Property="Background" Value="Blue" />
</Trigger>
</Style.Triggers>
</Style>

How do you change WPF DataGrid cell background while editing the cell?

The following is an example of how to set the background when the cell is selected, but when I actually click inside the cell to edit it the color changes. Is there a trigger property for when a cell is being edited? I'd like the background not to change.
<DataGrid Name="DG1" ItemsSource="{Binding}" SelectionUnit="Cell" >
<DataGrid.CellStyle>
<Style TargetType="DataGridCell" >
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="SeaGreen"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>
</DataGrid>
Answering my own question, it looks like the Cell background color is based off of SystemColors.WindowBrushKey. Overriding that resource like such <SolidColorBrush x:Key="{x:Static SystemColors.WindowBrushKey}" Color="Red" /> did the trick.
`
You can add another trigger into your existing style for the IsEditing state. Then you can set the ControlTemplate for the DataGridCell inside of the trigger.
<Trigger Property="IsEditing" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridCell">
<TextBox Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text, Mode=TwoWay, UpdateSourceTrigger=Default}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Padding="0" BorderThickness="0" Background="SeaGreen"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
This works with DataGridTemplateColumn as well as other types like DataGridTextColumn, DataGridCheckboxColumn and etc.:
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Padding" Value="0" />
<Setter Property="Margin" Value="0" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border x:Name="CellBorder"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<ContentPresenter HorizontalAlignment="Stretch" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEditing" Value="True">
<Setter TargetName="CellBorder" Property="BorderBrush" Value="Green" />
<Setter TargetName="CellBorder" Property="Background" Value="yellow" />
<Setter TargetName="CellBorder" Property="BorderThickness" Value="1" />
<Setter Property="Foreground" Value="Black" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Resources