C
Join ServerC#
help
❔ WPF How to change button hover color?
DDawnbomb12/21/2022
It seems there is some default color WPF uses as a highlight when the user mouses over a button, and i can't figure out what it is, where it is, or how to change it. My closest answer is far is maybe its a system brush, that gets the color from...your operating system? (ew).
DDoombox12/21/2022
it's changed via style triggers
ignoring the actual declaration/usage of the style itself
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
ignoring the actual declaration/usage of the style itself
DDoombox12/21/2022
as for the default colour... uhh, I don't actually know, I assume the default style for WPF controls are declared the exact same way as any other style, in which case the colour will just be based on whatever internal document microsoft uses when designing their OS'
AAlexicon12/21/2022
You can do this by applying a style to a button and changing its template. For example with this simple style:
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}">
<ContentPresenter
Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="#FFCBCBCB"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" Value="#FFB8B8B8"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
AAlexicon12/21/2022
Unfortunately I don't think what @Doombox says will work for buttons in particular since the highlight effect is part of the template and cannot be changed on a simple style trigger like other elements. I might be wrong but a quick test I just did seems to suggest that is the case.
DDoombox12/21/2022
<Button Content="Button" HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="50" Height="50" HorizontalContentAlignment="Left" BorderBrush="{x:Null}" Foreground="{x:Null}" Margin="50,0,0,0">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Green"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
should work
DDoombox12/21/2022
though I'm too lazy to spin up Rider to try 

DDoombox12/21/2022
think you might be right though thinking about it
AAlexicon12/21/2022
@Doombox, What you just posted works actually with the style trigger since you are overriding the template. So using what you did I think actually this is the simplest style @Dawnbomb could use that doesn't really change anything else:
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}">
<ContentPresenter
Content="{TemplateBinding Content}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="#FFCBCBCB"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" Value="#FFB8B8B8"/>
</Trigger>
</Style.Triggers>
</Style>
DDoombox12/21/2022
love WPF, making what should be relatively simple very complex
DDoombox12/21/2022
unironically do love it though, just stuff like this is annoying
DDoombox12/21/2022
.button:hover {
background-color:#ffffff;
}
if only...

DDawnbomb12/22/2022
@Alexicon I am losing my mind. I don't understand templates at all, all i get is i can't change hover colors without them, and it just takes a ton of code and makes everything so confusing just to have code that says the content is the content (why is this no assumed / default? WPF is so bad omggg) and it seems regardless if i put a trigger inside data, or data inside a trigger, it just gives me an error anyway. 😡

AAlexicon12/22/2022
Ah, so if you want to check for two conditions things become slightly more complicated (I know that's exactly what you want to hear).
What you need to do in this case is use what's called a multi-trigger. This is like using an if statement with 'and' (&&) clauses.
For example, if you want to set the background when the theme is light and the mouse is pressed you would have to do this:
note the slight complexity with getting the 'IsPressed' value, because this is a 'data-trigger' we have to use a relative source to get the property of the button itself. I wont get into those details now but is something you might consider looking into if you continue to use WPF.
I went ahead and made a fully working example of what I think your trying to achieve here, which I recommend looking at: https://github.com/AlexLexicon/Discord.Example.MultiBindings
What you need to do in this case is use what's called a multi-trigger. This is like using an if statement with 'and' (&&) clauses.
For example, if you want to set the background when the theme is light and the mouse is pressed you would have to do this:
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsPressed, RelativeSource={RelativeSource Mode=Self}}" Value="true"/>
<Condition Binding="{Binding Path=Theme, Source={x:Static properties:Settings.Default}}" Value="light"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Background" Value="#FFC5C5C5"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
note the slight complexity with getting the 'IsPressed' value, because this is a 'data-trigger' we have to use a relative source to get the property of the button itself. I wont get into those details now but is something you might consider looking into if you continue to use WPF.
I went ahead and made a fully working example of what I think your trying to achieve here, which I recommend looking at: https://github.com/AlexLexicon/Discord.Example.MultiBindings
AAlexicon12/22/2022
Now additionally something else you can do that makes the xaml slightly easier is making one of your themes the default setters for the style.
What I mean by this is that you can have this in your style:
which will give the button a default look of "light" but then you can use the data-triggers to only apply changes when you want the button to be "dark" or any other themes. Like I said this is only a minor simplification to the xaml but I might recommend it.
You can find a working example of this in the same github repo but on this separate branch: https://github.com/AlexLexicon/Discord.Example.MultiBindings/tree/WithDefaultSetters
What I mean by this is that you can have this in your style:
<!--Default-->
<Setter Property="Background" Value="#FFF4F4F4"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderThickness" Value="0"/>
<Style.Triggers>
<!--Default MouseOver-->
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#FFD7D7D7"/>
</Trigger>
<!--Default Pressed-->
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#FFC5C5C5"/>
</Trigger>
<!--DarkMode Default-->
<DataTrigger Binding="{Binding Path=Theme, Source={x:Static properties:Settings.Default}}" Value="dark">
<Setter Property="Background" Value="#FF606060"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderThickness" Value="0"/>
</DataTrigger>
...
</Style.Triggers>
which will give the button a default look of "light" but then you can use the data-triggers to only apply changes when you want the button to be "dark" or any other themes. Like I said this is only a minor simplification to the xaml but I might recommend it.
You can find a working example of this in the same github repo but on this separate branch: https://github.com/AlexLexicon/Discord.Example.MultiBindings/tree/WithDefaultSetters
DDawnbomb12/22/2022
it...didn't exactly work?
DDawnbomb12/22/2022
oh, it does, just the...order matters...
DDawnbomb12/22/2022
oh my god
DDawnbomb12/22/2022
an is pressed trigger must be after a hover....KJFKLSFKJSDLKFJ
DDawnbomb12/22/2022
why can't it work like normal code....
DDawnbomb12/22/2022
<Style.Triggers>
<!--Light Mode-->
<DataTrigger Binding="{Binding Source={x:Static properties:Settings.Default}, Path=ColorMode}" Value="Light">
<Setter Property="Background" Value="{StaticResource ResourceKey= White}"/>
<Setter Property="Foreground" Value="{StaticResource ResourceKey= Black}"/>
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Mode=Self}}" Value="true"/>
<Condition Binding="{Binding Path=ColorMode, Source={x:Static properties:Settings.Default}}" Value="Light"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Background" Value="#FF715151"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsPressed, RelativeSource={RelativeSource Mode=Self}}" Value="true"/>
<Condition Binding="{Binding Path=ColorMode, Source={x:Static properties:Settings.Default}}" Value="Light"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Background" Value="#FF59C550"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
Is this really the shortest for 1 style?
DDawnbomb12/22/2022
i feel like these walls of text are going to get obscenely massive very quickly
DDawnbomb12/22/2022
instead of winforms just having a color picked in a menu
DDawnbomb12/22/2022
>_>;
DDawnbomb12/22/2022

AAlexicon12/22/2022
Yeah it ends up being a lot thats true, however that is more of a symptom of being a markup language. You can of course always move things into their own files so as to not become overwhelming. (For example you can put this one style in its own resource dictionary file called MyButtonStyle.xaml)
DDawnbomb12/22/2022
next...in no particular order...
where is grid borders, or was that just removed from the property menu to troll me.
Treeview ignores foreground colors?
Dropdown ignores foreground and background colors.
where is grid borders, or was that just removed from the property menu to troll me.
Treeview ignores foreground colors?
Dropdown ignores foreground and background colors.
DDawnbomb12/22/2022
my instinct was its the content of dropdown, but no, those are ofcorse seperatde from the actual dropdown.
DDawnbomb12/22/2022

DDawnbomb12/22/2022
leaving ugly white bars even f i did style every single one
AAlexicon12/22/2022
Lets start with #1, what do you mean by grid borders exactly? I haven't worked with winforms in over five years so if you referencing something from that I don't remember what it was.
DDawnbomb12/22/2022

DDawnbomb12/22/2022
in winforms you can just have a border that appears in the application
DDawnbomb12/22/2022
without writing code
DDawnbomb12/22/2022
(there is a lot of things winforms lets one do without writing code...why am i learning WPF again...?)
AAlexicon12/22/2022
ah gotcha
DDawnbomb12/22/2022
google said i can use a border brush, and conveniently, there is no border brush in properties.
DDawnbomb12/22/2022
my guess is that i must add it as a style
AAlexicon12/22/2022
ok so yeah in wpf some elements do have borders built in and others dont. However the easiest thing to do is just add a border by surrounding the element in a border. like this:
<Border
BorderBrush="Black"
BorderThickness="2">
<Button Content="I now have a border!"/>
</Border>
DDawnbomb12/22/2022
and then if things want diffrent borders, suddenly im mass producing styles
DDawnbomb12/22/2022
what about for a grid
AAlexicon12/22/2022
Same thing
<Border
BorderBrush="Black"
BorderThickness="2">
<Grid>
<!--this grid now has a border-->
</Grid>
</Border>
DDawnbomb12/22/2022
ahh it goes OUTSIDE the grid in XML, omg
AAlexicon12/22/2022
Now you second question was about foreground colors?
DDawnbomb12/22/2022

DDawnbomb12/22/2022
treeview ignores forground, and combobox ignores background and foreground
DDawnbomb12/22/2022
they accept them without errors, but ignore them
AAlexicon12/22/2022
lets start with comboboxes as I am more familiar with those. I must admit I am still not quite sure what your seeing. Because for me if I create just a default combobox and set the foreground I see that as the text color, for example:
<ComboBox
Foreground="Red">
<ComboBoxItem Content="Option 1"/>
<ComboBoxItem Content="Option 2"/>
<ComboBoxItem Content="Option 3"/>
</ComboBox>

AAlexicon12/22/2022
sorry the "yo" "whats" "up" i changed to options in my example xaml but didnt when I ran it, just ignore that part. haha
DDawnbomb12/22/2022
i now realize i had assigned a backcolor and forcolor on aixedent
DDawnbomb12/22/2022
but
DDawnbomb12/22/2022
its still not obeying very much / fully

AAlexicon12/22/2022
Can you paste the xaml and tell me what you expect it to look like, then maybe I can point out the issue
DDawnbomb12/22/2022
oh i
DDawnbomb12/22/2022

DDawnbomb12/22/2022
<ComboBox Style="{DynamicResource ComboBoxBasic}" HorizontalAlignment="Left" Margin="289,107,0,0" VerticalAlignment="Top" Width="120">
<ComboBoxItem Content="PC" />
<ComboBoxItem Content="Nintendo NES / Famicom" Background="#FF400000" />
<ComboBoxItem Content="Nintendo SNES / Super Famicom" Background="#FF400000" />
<ComboBoxItem Content="Nintendo 64"/>
<ComboBoxItem Content="Nintendo Gamecube"/>
</ComboBox>
DDawnbomb12/22/2022
and
DDawnbomb12/22/2022
<Style TargetType="{x:Type ComboBox}" x:Key="ComboBoxBasic">
<Style.Triggers>
<!--Light Mode-->
<DataTrigger Binding="{Binding Source={x:Static properties:Settings.Default}, Path=ColorMode}" Value="Light">
<Setter Property="Background" Value="{StaticResource ResourceKey= White}"/>
<Setter Property="Foreground" Value="{StaticResource ResourceKey= Black}"/>
</DataTrigger>
<!--Dark Mode-->
<DataTrigger Binding="{Binding Source={x:Static properties:Settings.Default}, Path=ColorMode}" Value="Dark">
<Setter Property="Background" Value="{StaticResource ResourceKey= Dark}"/>
<Setter Property="Foreground" Value="{StaticResource ResourceKey= Light}"/>
<!--<Setter Property="BorderThickness" Value="4,1,1,1"/>-->
</DataTrigger>
</Style.Triggers>
</Style>
DDawnbomb12/22/2022
the items other then ones i set manual colors to ignore the combobox color, but even before that...
DDawnbomb12/22/2022

DDawnbomb12/22/2022
the combo box isn't inheriting the properties of it's items, so, the text is white on white
DDawnbomb12/22/2022
theres no black or dark background
DDawnbomb12/22/2022
and this item was one of the red background ones, so i know its not just inheriting from item
DDawnbomb12/22/2022
even ignoring styling, if i assign it a background color, its entirely ignored
AAlexicon12/22/2022
ok so yes, now I get what your saying. Unfortunately combo boxes are one of the more annoying elements to style due to the complexity of their use. However I think I have a example I can provide that will solve this, one moment
DDawnbomb12/22/2022
based on time to post, this is gonne be a giant wall of text. x.x
AAlexicon12/22/2022
ok, your going to love this one
AAlexicon12/22/2022
The first thing to keep in mind is that as with all similar elements in wpf children and their containers need to be styled separately so in the following example I will soon post I am only referring to the actual combo box and not the combobox items (however they are much easier anyway)
AAlexicon12/22/2022
When it comes to styling a combobox, it is sort of an all or nothing experience which means you need to modify the template (just like we did with the button) but because a combo box is more complicated, its template is more complication. I went ahead and created based on some things I have done in the past a very basic combobox style that you should be able to customize pretty easily.
AAlexicon12/22/2022
AAlexicon12/22/2022
I made this style to use the following resources which are pretty self explanatory:
Now this style is not taking into consideration your theming design and just has constant colors, however you can use the exact same technique as with the button (multidatatriggers) to get the theming working the same way.
Again here is the same github repo but another branch incase you need to see the full example of this working: https://github.com/AlexLexicon/Discord.Example.MultiBindings/tree/ComboBoxFun
Now as for styling the actual ComboBoxItems give me another minute...
<SolidColorBrush x:Key="MyComboBoxStyle_Background_Normal" Color="#FFF4F4F4"/>
<SolidColorBrush x:Key="MyComboBoxStyle_Background_MouseOver" Color="#FFE5E5E5"/>
<SolidColorBrush x:Key="MyComboBoxStyle_Background_Open" Color="#FFD6D6D6"/>
<!--this includes the arrow-->
<SolidColorBrush x:Key="MyComboBoxStyle_Foreground_Normal" Color="#FF000000"/>
<SolidColorBrush x:Key="MyComboBoxStyle_Foreground_MouseOver" Color="#FF000000"/>
<SolidColorBrush x:Key="MyComboBoxStyle_Foreground_Open" Color="#FF000000"/>
<SolidColorBrush x:Key="MyComboBoxStyle_Border_Brush" Color="#FFBFBFBF"/>
<Thickness x:Key="MyComboBoxStyle_Border_Thickness">1</Thickness>
<Thickness x:Key="MyComboBoxStyle_Padding">4,2</Thickness>
<HorizontalAlignment x:Key="MyComboBoxStyle_HorizontalContentAlignment">Left</HorizontalAlignment>
<VerticalAlignment x:Key="MyComboBoxStyle_VerticalContentAlignment">Center</VerticalAlignment>
Now this style is not taking into consideration your theming design and just has constant colors, however you can use the exact same technique as with the button (multidatatriggers) to get the theming working the same way.
Again here is the same github repo but another branch incase you need to see the full example of this working: https://github.com/AlexLexicon/Discord.Example.MultiBindings/tree/ComboBoxFun
Now as for styling the actual ComboBoxItems give me another minute...
AAlexicon12/22/2022
For the comboboxitem you can do something as simple as say this:
and then you can make it so the combobox style uses this style for its items by adding this to the setters:
<Style x:Key="MyComboxItem" TargetType="{x:Type ComboBoxItem}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border>
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="{StaticResource MyComboBoxStyle_Background_Normal}"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource MyComboBoxStyle_Background_MouseOver}"/>
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
<ContentPresenter Content="{TemplateBinding Content}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and then you can make it so the combobox style uses this style for its items by adding this to the setters:
<Style x:Key="MyComboBoxStyle" TargetType="ComboBox">
...
<Setter Property="ItemContainerStyle" Value="{StaticResource MyComboxItem}"/>
...
</Style>
AAlexicon12/22/2022
I pushed an update to that github branch if you want to see all of it together
DDawnbomb12/22/2022
uh
DDawnbomb12/22/2022
i dont see it on github
DDawnbomb12/22/2022

DDawnbomb12/22/2022
even though i saw an update
DDawnbomb12/22/2022
its just some buttons
AAlexicon12/22/2022
AAlexicon12/22/2022
The branch is called "ComboBoxFun"
DDawnbomb12/22/2022
how do i download a branch?
DDawnbomb12/22/2022
it just keeps giving me the main one
AAlexicon12/22/2022
Oh sorry, you can select the branch from here:

DDawnbomb12/22/2022
but also i am getting so extremely confused
AAlexicon12/22/2022
Then once you select the branch you want you can just download as normal
DDawnbomb12/22/2022
well, how does one download as normal?
AAlexicon12/22/2022
You can do this:

DDawnbomb12/22/2022
thats what i did
DDawnbomb12/22/2022
hmmm
AAlexicon12/22/2022
Are you using visual studio?
DDawnbomb12/22/2022
yes
AAlexicon12/22/2022
Have you used git before or is that new to you?
DDawnbomb12/22/2022
okay, i got it, but i had to download as zip instead of just open with VS
DDawnbomb12/22/2022
i feel like WPF is so convolted i need help with literally every single step of every single thing i do and its infuriating
AAlexicon12/22/2022
yeah it is not simple thats for sure. I felt exactly the same when I started wanting to use it.
DDawnbomb12/22/2022
whoever designed picking a color to need a template and 200+ lines of codes should be assassinated
DDawnbomb12/22/2022
irredeemably evil
AAlexicon12/22/2022
haha, yeah I think they could have made the default templates better thats for sure.
DDawnbomb12/22/2022
this is "so complicated you will quit and pay us to do it for you" tier
DDawnbomb12/22/2022
im going to need a lot of help to understand how to use this in any meaningful way