How to correctly create button with images - c#

I want to create an application with multiple buttons. So I want to create a style in my application to define the buttons. Buttons should contain an image and that image should change when mousse is over.
I created resources for images :
<Image x:Key="Open-active" Source="Images/Open-active.png"/>
<Image x:Key="Open-over" Source="Images/Open-over.png"/>
<Image x:Key="Printer-active" Source="Images/Printer-active.png"/>
<Image x:Key="Printer-over" Source="Images/Printer-over.png"/>
I created a Style (but doesn't work with resource type Image):
<Style x:Key="ButtonMain" TargetType="Button"
BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Setter Property="Height" Value="{StaticResource MainButtonHeight}"/>
<Setter Property="Width" Value="{StaticResource MainButtonWidth}"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Foreground" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="???"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="???"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
How can a properly create my Style and how use it ?
I want to use it with something like this :
<Button Style="{StaticResource ButtonMain}"
ImageActive="{StaticResource Open-active}"
ImageOver="{StaticResource Open-over}"">
Thank you for help

You could use style inheritance to achieve what you're trying to do :
Your main style would be :
<Style x:Key="ButtonMain" TargetType="Button"
BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Setter Property="Height" Value="{StaticResource MainButtonHeight}"/>
<Setter Property="Width" Value="{StaticResource MainButtonWidth}"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Foreground" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
One style that would just define the images would look like :
<Style x:Key="ButtonImage1" TargetType="Button"
BasedOn="{StaticResource ButtonMain">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="???"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background">
<Setter.Value>
<ImageBrush ImageSource="???"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
You'd only have to use the style on your button
Concerning the images, it's not the type that you want to use, IIRC, the ImageBrush source can be the path to an image file (check MSDN for that they should have a nice example)

Solve your ImageSource problem with proper binding :
<ImageBrush ImageSource="{Binding Source, Source={StaticResource Open-active}}"/>
For your own properties ImageActive and ImageOver , build your own custom control :
public class MyButton:Button
{ ... }
And depending upon your Binding requirements, these properties can be simple one or DependencyProperties.

Related

Not able to change foreground of label in ListBoxItem [duplicate]

This question already has answers here:
WPF set border background in trigger
(1 answer)
WPF Trigger won't set property if set in Element
(3 answers)
Closed last year.
Below is the sample code of my WPF xaml file. My intention is to change the foreground of the label in the listboxitem to Red colour when the item is selected. However, no changes was seen on the foreground? What mistake had I done?
<UserControl.Resources>
<Style x:Key="WishlistListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="FontFamily" Value="Arial"/>
<Setter Property="Background" Value="#282C2F"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ListBoxItem">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="WishlistBorder" Style="{DynamicResource WishlistBorderContent}">
<ContentPresenter />
</Border>
<ControlTemplate.Resources>
<Style x:Key="WishlistBorderContent" TargetType="Border">
<Setter Property="BorderThickness" Value="0 0 0 2"/>
<Setter Property="BorderBrush" Value="#50D3D3D3"/>
</Style>
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="WishlistBorder" Property="BorderThickness" Value="2"/>
<Setter TargetName="WishlistBorder" Property="BorderBrush" Value="#63C5DA"/>
<Setter Property="Foreground" Value="Red"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="WishlistBorder" Property="Background" Value="#50D3D3D3"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<ListBox ItemsSource="{Binding SymbolList}" SelectedItem="{Binding SelectedSymbol}"
Style="{StaticResource WishlistListBoxStyle}" HorizontalContentAlignment="Stretch" Width="200" Padding="0">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding}" Foreground="White"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

how to set image background in wpf

I am trying to set inactive buttons to have semi-transparent (i.e. greyed out) images. Yet for some reason the images become white/ yellow (as if on a bright background):
As you can see it's light yellow
Possibly better annotated screenshot
Here are the XAML Styles:
<Style x:Key="ToolButton" TargetType="{x:Type Button}" BasedOn="{x:Null}">
<Setter Property="Background" Value="#888"/>
<Setter Property="Padding" Value="10,2"/>
<Setter Property="BorderThickness" Value="0"/>
<Style.Resources>
<Style TargetType="Image">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.5"/>
</Trigger>
</Style.Triggers>
</Style>
</Style.Resources>
</Style>
<Style x:Key="ToolPanel" TargetType="{x:Type StackPanel}">
<Setter Property="Background" Value="#111"/>
<Style.Resources>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource ResourceKey=ToolButton}"/>
</Style.Resources>
</Style>
(StackPanel and buttons are dark for contrast, they are actually mean to be light grey)
What should I do to get the greyed out effect I want?
The problem is the default Button template: it changes its background based on the control's state, and that new background takes precedence over the one you're setting in your style.
In this case, the brush for the 'Disabled' state is something like #F4F4F4, or a very light gray.
The fix would be to declare a new Button template. For example:
<ControlTemplate TargetType="Button">
<!--Optional: Add border brush/thickness if you want a border-->
<Border x:Name="border" Background="{TemplateBinding Background}">
<ContentPresenter x:Name="contentSite" Margin="{TemplateBinding Padding}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<!--Optional: Remove background when disabled-->
<!--Setter TargetName="border" Property="Background" Value="Transparent" /-->
<Setter TargetName="contentSite" Property="Opacity" Value="0.5" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="#AAA" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Background" Value="#333" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Note that with this version, you do not need the Image style to change the Opacity; it's taken care of in the Button template.

Multiple styles and content on one button

I have a HomePage with a number of buttons on that I am trying to get to do a couple of things. Firstly, I have a Style in a ResourceDictionary that dictates the overall 'look and feel' of the buttons. It looks like this:
<Style TargetType="Button" x:Key="HomeButton">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="#06658D"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderBrush="White" BorderThickness="1">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="#06658D"/>
</Trigger>
</Style.Triggers>
</Style>
Nothing too complicated, however I want the MouseOver effect to persist after being clicked. So now I am looking at doing something like this:
<Button Grid.Row="0" Style="{StaticResource HomeButton}" Content="Contacts">
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding ContactsClicked}" Value="True">
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="#06658D"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button>
I'll bind the command element of the Button to set ContactsClicked = true and reset this when another button is pressed. However, I get the error saying that Content is set multiple times.
Is it possible to have an overall Style of the Button set, as well as a 'Clickedstyle and to have aTextBlockdisplaying text on the button all at once or am I approaching this wrong? I am trying to not have an individual overall style for every singleButton`as that's a lot of repeated code.
For clarity this is what I am aiming for:
I've managed to find a solution myself, instead of using a Button us a ToggleButton instead:
<Style TargetType="ToggleButton" x:Key="HomeButton">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="#06658D"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Background="{TemplateBinding Background}" BorderBrush="White" BorderThickness="1">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="Black" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="#06658D"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="#06658D"/>
</Trigger>
</Style.Triggers>
</Style>
I would add this as a comment but im not allowed.
If your goal is that the button will stay selected after it is clicked, why not use a RadioButton? A RadioButton has a built-in property called IsChecked but will also remain "Checked" or "Selected" even after multiple clicks.
Of course you can define the behavior and the styles in a similar manner, create a simple Trigger on the property IsChecked.
If more explanation is needed, just say so.

adding eventsetter for datarow not firing

Inside of app.xaml I have datagrid style
and for each window that contains a datagrid, I added an event setter for the datagridrow.
however, when I run it, I can see the style, but when I try to trigger the event nothing happens. if I remove the style from app.xaml. the event works well.
why app.xaml style disable my eventsetter?
here's the datagrid inside the app.xaml:
<Style TargetType="DataGrid">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="GridLinesVisibility" Value="None"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="RowStyle">
<Setter.Value>
<Style TargetType="DataGridRow">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Foreground" Value="White"/>
</Style>
</Setter.Value>
</Setter>
<Setter Property="ColumnHeaderStyle">
<Setter.Value>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Margin" Value="5,0,0,0"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{ x:Type DataGridColumnHeader}">
<Border BorderThickness="2,2,2,0" CornerRadius="5,5,0,0">
<Border.Style>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="White"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}" Value="{x:Null}">
<Setter Property="BorderBrush" Value="Transparent"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<ContentPresenter HorizontalAlignment="Center" Margin="5"></ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
here's the eventsetter inside each window that contains datagrid:
<Style TargetType="DataGridRow">
<EventSetter Event="MouseDoubleClick" Handler="EditItem"/>
</Style>
It seems, that the grid uses the RowStyle from it's property later, than it has been set in window's resources. It will work, if you clear your RowStyle property in grid. Put this to the window's resources:
<Style TargetType="DataGrid" BasedOn="{StaticResource {x:Type DataGrid}}">
<Setter Property="RowStyle" Value="{x:Null}"/>
</Style>
For you can use the style set in app.xaml, you have to move the RowStyle from property to global(in app.xaml):
<Style TargetType="DataGrid">
....
<Setter Property="RowStyle" Value="{x:Null}"/>
...
</Style>
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="Background" Value="Green"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Foreground" Value="White"/>
</Style>
and in window's resources:
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<EventSetter Event="MouseDoubleClick" Handler="PreviewMouseDown"/>
</Style>

Trigger on resource from resource

Is it possible to change a resource from another resource. I like to change the background of StartButtonRed if the mouse is over StartButtonMain.
<ImageBrush x:Key="RedBackgroundActive" ImageSource="/Images/start_red_active.png" Stretch="Fill"/>
<Style x:Key="StartButtonMain" TargetType="{x:Type local:SimpleButton}">
<Style.Resources>
<ImageBrush x:Key="MainBackground" ImageSource="/Images/start_main_normal.png" Stretch="Fill"/>
<ImageBrush x:Key="MainBackgroundActive" ImageSource="/Images/start_main_active.png" Stretch="Fill"/>
</Style.Resources>
<Style.Setters>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Background" Value="{StaticResource MainBackground}"/>
<Setter Property="Visibility" Value="Visible"/>
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource MainBackgroundActive}"/>
// Change the background of StartButtonRed to RedBackgroundActive
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="StartButtonRed" TargetType="{x:Type local:SimpleButton}">
<Style.Resources>
<ImageBrush x:Key="RedBackground" ImageSource="/Images/start_red_normal.png" Stretch="Fill"/>
</Style.Resources>
<Style.Setters>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Background" Value="{StaticResource RedBackground}"/>
<Setter Property="Visibility" Value="Visible"/>
</Style.Setters>
</Style>
You can't do this. Because styles are resources and triggers can only target FrameworkElements from within their own Template or using a Binding to an other actual FrameworkElement, you can't bind to another resource.
You could solve this with UserControl Triggers.

Categories