WPF Button MouseOver trigger changes background briefly - wpf

I am trying to change the background of a button with the IsMouseOver trigger. I have found many good answers on Stackoverflow but I am having a strange issue that I can't seem to find anyone else having. I have the following style defined
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Purple"/>
</Trigger>
</Style.Triggers>
</Style>
and using it with a button
<Button Content="Some Button"/>
My problem is that when I mouse over the background changes to Purple but then immediately changes to the standard windows blue color with my mouse still over the button. I expect that the background would stay purple until the mouse is no longer over the button. Does anyone know what could be the issue? Thanks.

The standard template for a Button uses a ButtonChrome component, which takes care of rendering the button according to the current Windows theme. Unfortunately, the ButtonChrome is not very customizable (basically it does everything in its OnRender handler), so it you want to make bigger changes to the appearance of the button, you'll have to write a custom template.

Related

Adding an ErrorTemplate to a WPF User Control disables TextBox input

I have a very basic custom control consisting of a Label and a Textbox. I've used my control for sometime without any issues.
I've now come to styling my application and have my style inside a XAML file containing just a ResourceDictionary. I have the following for my UserControl:
<Style TargetType="local:LabelEdit">
<Setter Property="Background" Value="{StaticResource BackgroundBrush}" />
<Setter Property="Foreground" Value="{StaticResource ForegroundBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource BorderBrush}" />
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel>
<AdornedElementPlaceholder />
<Image Source="/AJSoft.Controls;component/Resources/Icons/cross.ico" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Foreground" Value="{StaticResource ErrorForegroundBrush}" />
<Setter Property="Background" Value="{StaticResource ErrorBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource ErrorBorderBrush}" />
</Trigger>
</Style.Triggers>
</Style>
Everything works absolutely fine if I comment out the Setter for Validation.ErrorTemplate. If the ErrorTemplate is left intact, the cross shows (I haven't sorted out placement yet, but that can come later...), but the Textbox component of my UserControl does not show the caret or accept keyboard input. The rest of the controls in my Window work as expected.
Here are some screenies where I've deliberately put in some erroneous text to show how it looks.
The same problem happens even if I change that huge image to be a textblock with a small red "!" - the image is just for effect for now.
What am I doing that's causing the problem? I'm new to Validation in WPF...
EDIT: The image shown (big red cross) is just one example of what I've done. Even if I use a small image shown alongside the UserControl, I still get the same effect.
If you were to look at how error templates usually work, you'd see they apply to a single control.
Part of the issue you have here is you've got a label and textbox in one parent user control.
If you then apply an error template at the usercontrol level, it's on everything in that. Label, textbox, everything in your usercontrol.
The next thing to consider is how your error template ends up visible on top of everything. This happens because your error template generates UI in the adorner layer. That's top of everything ( in the window ).
Add these together and you got a big image on top of the content of your usercontrol.
At risk of over simplifying:
You put a top on your box and you can't now get at what's in that box.
There are several ways you could "fix" this but they all involve some design change or compromise.
Maybe a big X on top of your input control isn't a good idea.
You could kind of make it work.
You could make your image IsHitTestVisible="False".
It'll be visually in the way but you can then likely click on the textbox and type.
Just maybe not see everything.
Probably not ideal.
You could show your cross next to the textbox using a datatrigger rather than error template.
Add an image to your usercontrol so you have label, textbox, CrossImage.
Add a style to that with a setter makes it visible collapsed by default.
Use a trigger in that style to show the CrossImage when the control has errors.
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter ... />
</Trigger>
</Style.Triggers>
You may well find it simplest to use the tag on the usercontrol and set that to visible/collapsed. Bind visibility of the image to that.

xctk:IntegerUpDown custom style to hide ButtonSpinner

On the xctk:IntegerUpDown, I would like the textbox border and the ButtonSpinner to only be visible when focused or mouseover.
It is easy enough to turn the border on/off using a <Style.Triggers> section.
It is also possible to control the ShowButtonSpinner property.
However, the content of the TextBox jumps to the right if I set ShowButtonSpinner=False.
I would like to simply hide the ButtonSpinner without TextBox contents jumping around.
Like this:
How can I get access to the appropriate property?
your question helped me to find ShowButtonSpinner property which I needed to hide up and down buttons
i can suggest a workaround with setting a fixed Padding for content when buttons are hidden. Value 0,0,17,0 seems ok to me (Win7, wpf toolkit version v2.6.0.0)
<xctk:IntegerUpDown.Style>
<Style TargetType="xctk:IntegerUpDown">
<Setter Property="Padding" Value="0,0,17,0"/>
<Setter Property="ShowButtonSpinner" Value="False"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Padding" Value="0"/>
<Setter Property="ShowButtonSpinner" Value="True"/>
</Trigger>
</Style.Triggers>
</Style>
</xctk:IntegerUpDown.Style>
another simple thing is to align text to left side via property
<xctk:IntegerUpDown TextAlignment="Left"/>

ControlTemplate trigger on a subelement

I want to increase the size of the border of a DatePicker when it has focus. In the TextBox style the following works nicely when used with a border BorderBase in the ControlTemplate.
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsFocused" Value="true">
<Setter Property="BorderThickness" TargetName="BorderBase" Value="2"/>
<Setter Property="Padding" TargetName="BorderBase" Value="3"/>
</Trigger>
</ControlTemplate.Triggers>
For DatePicker this does not work since the DatePickerTextBox inside the DatePicker has the actual focus. On the DatePicker style page the visual states are listed. The TextBox does have a Focused state, but the DatePicker only has a Focused state for when the input invalid.
How do you guys suggest I tackle this problem?
What about setting your Trigger on HasKeyboardFocus instead of IsFocused? I think that one will return true if any child element contains focus
How about naming the TextBox and specifying a respective Trigger.SourceName?

WPF Focus on "run" element

I would like to change the background of the Run that has the focus in a FlowDocument in a RichTextBox.
I would like to provide to my users a visual cue as to which Run element they are currently editing and I think a light background would be the best way for my application.
I see that the Run has Focusable (which I set to true), IsFocused, FocusVisualStyle, GotFocus, etc. but none of those properties or events seam to work.
Thank you for any help you can give.
You can use a data trigger to get the effect you want. Here's an example:
<Style TargetType="{x:Type RichTextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="LightGrey" />
</Trigger>
</Style.Triggers>
</Style>

Hover effect for a Control that resides if a ContextMenu is opened

I want to add a hover effect for a WPF-Control.
For this, I created a Style-Trigger that changes the Background-Brush of the control if IsMouseOver is true. This works fine, however if I open a ContextMenu from the control, IsMouseOver becomes false and the hover effect stops until the ContextMenu is closed.
I also tried a combination of MouseEnter and MouseLeave, but with this, there is the same behaviour. If the context menu` is opened, MouseLeave will be fired.
I understand why I can not do it like this, but I don't see a nice way to solve my requirement. Has anyone did already something like this?
The issue can be resolved by the creation of a second trigger, that checks if the attached ContextMenu is opened:
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource Hover_Brush}"/>
</Trigger>
<DataTrigger Binding="{Binding ContextMenu.IsOpen,RelativeSource={RelativeSource Mode=Self}}" Value="True">
<Setter Property="Background" Value="{StaticResource Hover_Brush}"/>
</DataTrigger>
Caveat
The above XAML works fine, but has one issue: If the style is used for more than one item and the controls ContextMenu is shared, the hover effect will be activated on all items if the context menu is opened for a control.
Therefore, the context menu must not be shared. If it is defined in a resource, use the x:Shared="false" property to disable sharing. If it is directly defined under the control, this problem does not occur.

Resources