WPF Button Style Template IsEnabled - c#

i based my application on this
example
i need my own button-style (without mouseover animations etc.), so i made this in the app.xaml:
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="Border"
CornerRadius="2" BorderThickness="1"
Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" />
<Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
my button: <Button IsEnabled="true"/>
now if i change the button to <Button IsEnabled="false"/> my app crashes at the start with an error like: "{DependencyProperty.UnsetValue}" is not a valid value for property "BorderBrush".
what am i doing wrong?

It has to do with your static reference.
In particular, XAML parsing is very touchy on order - you have to make sure that a brush with x:Key="DisabledForegroundBrush" is referenced before the parser gets to the line in the above style - even if your style above is in the same file as the DisabledForegroundBrush.
If you don't have a brush yet for the DisabledForegroundBrush, you can either remove the line referencing it in the above code if you don't require it, or, if you want it, you can create one as follows:
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="Red" />
Where you can choose the color as appropriate. Alternatively, you can choose some other kind of brush here: http://msdn.microsoft.com/en-us/library/aa970904(v=vs.110).aspx
If you have a brush you'd like to use already, then if you could provide a little more information as to where the brush is in the code base (eg is it in a resource dictionary?) and where the DisabledForegroundBrush brush is, this might help me pinpoint an actual solution / best way of ensuring the brush is referenced.
Note: an alternative if you can't ensure that DisabledForegroundBrush is parsed first is to change the StaticResource to a DynamicResource, but this isn't recommended unless the resource's link might actually change at run time (see What's the difference between StaticResource and DynamicResource in WPF? )
An easier solution:
If you just want to hard-code the style in, instead of reference the foreground brush externally, then you could change the line:
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
to:
<Setter Property="Foreground" Value="[SOME COLOR]"/>
To get rid of the need to create a separate brush object for your font.

Related

How can I change Button color via a trigger in the button?

Whats wrong with this trigger? I found it here: http://www.wpf-tutorial.com/styles/trigger-datatrigger-event-trigger/ and ive seen similar setups on SO
<Button x:Name="ColorPickerButton" Background="{Binding SelectedColor}">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Im trying to break down my spaghetti XAML and make it more readable. This is my old implementation which does work. I dont like it because it overwrites the button content and overlays a border which seems unnecessary. Also its massive
<Button x:Name="ColorPickerButton" Background="{Binding SelectedColor}">
<Button.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="Bd"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="true">
<GridViewRowPresenter/>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="BorderBrush" Value="{StaticResource ColorPickerButton.MouseOver.Border}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Resources>
</Button>
Your Trigger does not work because the default Template of the button has its own trigger that changes the background brush of the root border when the IsMouseOver Property is set. This means: As long as the mouse is on top of the button, the Background-property of the button control will be ignored by its template.
The easiest way to check out the default style of your button is to: right-click at the button in the visual studio wpf designer. Click 'Edit template' -> 'Edit a copy' and select a location.
A copy of the default style is created at the specified location. You will see a trigger like this:
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
</Trigger>
On top of designer created style definition it also created the brushes that are used within the style:
<SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
<SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
You can either change these brushes or the Value property of the setters above to change the background when the mouse is over.
Or you create your own Template like you did in your old implementation.

White frame around listbox Item selection on Windows8

I am getting complaints from Windows8 users about a strange frame around the SelectedItem on ListBoxes
In Windows7 this issue does not exists and so far I have found no way to get rid of this white frame.
As far as I can tell Windows8 listboxes now use ControlBrushKey instead of HighlightBrushKey but setting that to Transparent has no affect.
I have no Windows8 development environment at the moment so all fixes I have tried are pure guess work.
ListBox Resources:
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="Transparent" />
<Style TargetType="ListBoxItem">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="Transparent" />
</Style>
</ListBox.Resources>
The entire Xaml can be found here: https://github.com/saddam213/MPDisplay/blob/master/GUIFramework/GUI/Controls/GUIList.xaml
Image of the frame: (white box around selection)
If anyone has a clue how to get rid of this it would be great.
In a comment in your original post, you said:
I am not going to rebuild a control just because of a brush that needs to be overridden, I just will not support Windows8 if I need to override a entire ListBox template to remove a selection color, it will be simple once I install Win8 to find the brush using snoop
However, it is not painfully difficult to "rebuild" the ListBoxItem. It may, in fact, be simpler than forcing brushes, as you do not need to worry about overriding every UX change between Windows versions. One particular app I am building right now has the requirement that it run on every OS from XP to 8.1; I achieved a uniform look across all OSes by customizing everything down to the window borders.
Your best bet would be to style every aspect of the ListBoxItem by creating a template, something like the following:
<Style TargetType="ListBoxItem">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Green" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Blue" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Obviously, you would need to modify the styles to get the exact behavior you want.
i think this may be helpful for you. use Trigger property for isSelected.
<ListBox Name="lst">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True" >
<Setter Property="BorderBrush" Value="Wheat"/>
<Setter Property="BorderThickness" Value="0"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Yes, the last answer really helps.
This is how I get rid of the white frames around ListBoxItem:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Setters>
<Setter Property="BorderBrush" Value="Gray"/>
<Setter Property="BorderThickness" Value="0,0,0,1"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Background" Value="Black"/>
</Style.Setters>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Background="Black"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>

Flat button in WPF - trigger not firing

I wanted to restyle my buttons to be more flat so I have created two styles; first for ToggleButton that derives from ToolBar.ToggleButtonStyleKey and second for Buttonthat derives from ToolBar.ButtonStyleKey.
It worked great - the buttons are now toolbar-like and flat. Second thing I wanted is to have Background property to be transparent when user hovers the cursor over the control. So to achieve that I defined a simple trigger that sets the Background to Transparent on IsMouseOver event. It worked for ToggleButton, however, the same trigger didn't work for Button(the background was not affected at all).
Does anyone know why this trigger works great for ToggleButton and does not work for Button? I did expect the same behavior since both styles are from the same family.
Below is the full code.
<Window x:Class="WpfButtonsTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style x:Key="FlatToggleButton" TargetType="ToggleButton"
BasedOn="{StaticResource {x:Static ToolBar.ToggleButtonStyleKey}}">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Transparent"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="FlatButton" TargetType="Button"
BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Transparent"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<StackPanel>
<ToggleButton Style="{StaticResource FlatToggleButton}">
I am Toggle Button
</ToggleButton>
<Button Style="{StaticResource FlatButton}">
I am Button
</Button>
</StackPanel>
</Grid>
</Window>
I had a look using Snoop (a very handy program for inspecting WPF ) and it looks like the template which you're using as a basis, ToolBar.ButtonStyleKey, has a trigger which selects a solid Brush for the background of a Border element within the Button (in thise case when IsMouseOver is true).
Your local style trigger is successfully setting the background of the Button element to transparent (or rather, keeping it transparent), but the Border background is unaffected, so you'll still see the highlighting behaviour.
Border Background:
Button Background:
I think you'll have to define a ControlTemplate to get the button you're after, I've grabbed this from one of the ToolBar samples included in Kaxaml (a nice XAML editor). It's a reasonable facsimile of the Toolbar bas button style, with a few bits removed, it may behave as you want, or you might need to tweak it depending on your desired behaviour.
I've left the IsPressed trigger in place, you may want to remove it, or add additional triggers.
<Style x:Key="ToolBarButtonBaseStyle" TargetType="{x:Type ButtonBase}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<Border
x:Name="Border"
BorderThickness="1"
Background="Transparent"
BorderBrush="Transparent">
<ContentPresenter
Margin="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<!-- Additional triggers removed, e.g "IsMouseOver" -->
<!-- You may not want any at all -->
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="Border" Property="Background" Value="#E0E0E0" />
<Setter TargetName="Border" Property="BorderBrush" Value="#606060" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I see that the both FlatToggleButton and FlatButton styles already have Background as Transparent
<Setter Property="Background" Value="Transparent"/>
When the triggers is fired on IsMouseOver and set the Background again to Transparent you will not see any difference
So what you need to do is one of these options :
Change both styles so that the Background is something else than Transparent
Change the trigger so it sets the Background to something else than Transparent

How can I change WPF Button Image in Setter

I have a very strange problem trying to change the controltemplate for a button in WPF (c#).
I now have the following code:
<Window.Resources>
<Style x:Key="ButtonFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="Black" StrokeThickness="1" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MacOSX-Close" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="Black" BorderThickness="0">
<Image x:Name="bgimg" Source="bin/debug/Ressources/Images/GUI/frame-btn-defaulted.png"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#ADADAD"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="bgimg" Property="Source" Value="bin/debug/Ressources/Images/GUI/frame-btn-defaulted.png"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
So this isn't working. It says
"{DependencyProperty.UnsetValue}" is no valid value for property "System.Windows.Controls.Image.Source" on a setter.
And when I tried using multiple images in a grid (because you can only set one child) and modified the "visibility" property, the button didn't show up at all!!! No button, no image. And, yes, I am sure the image exists.
But the source is relative to the solution root, not to the compiled program... does this matter? Please help me :) I'm gettin' little desperate here... :(
Best regards ;)
And please ask if somethin's not clear to you.
Create folder like say Resources in your project and put image in your resources folder and their build action should be set to Resource. Then you can set Source = "/Resources/frame-btn-defaulted.png"

Abstract border and text block into another style/template in WPF

First of all, I would like to add customized text blocks to my GUI with the least possible overhead. For instance: <TextBlock style={StaticRessources myTextBlock}>Text</TextBlock>
For now I have the following border style:
<Style x:Key="greenBox" TargetType="Border">
<Setter Property="Background" Value="#00FF00"/>
<Setter Property="CornerRadius" Value="10"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Height" Value="40"/>
<Setter Property="Width" Value="100"/>
</Style>
And I apply it in the following way:
<Border Style="{StaticResource greenBox}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Custom Text</TextBlock>
</Border>
My problem is, it needs 2 Tags and the properties set in the TextBlock will be redunant. I cannot figure out how to abstract both definitions into a single element.
that's where Label comes into play:
<Style TargetType="Label" x:Key="greenLabel">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Label">
<Border Style="{StaticResource greenBox}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Label Style="{StaticResource greenLabel}">Custom Text</Label>
(in accordance with your other question: if this is the only place you use that borderstyle you can of course include these directly in that border not using an extra style)
You would need to create a custom control as described here. Or you could create a UserControl as well.

Categories