Style Triggers not working when object is bound to other object - wpf

I am having a problem with the style of a few items that are bound to a set of radio buttons. Basically, I have the following code for my styles:
<Window.Resources>
<Style x:Key="boxStyle" TargetType="TextBox">
<Setter Property="Background" Value="Black"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="Blue"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
Then I have two radio buttons as shown here:
<RadioButton Name="optionA" IsChecked="True">Option A</RadioButton>
<RadioButton Name="optionB'>Option B</RadioButton>
And two text boxes as shown here:
<TextBox Style="{StaticResource boxStyle}" IsEnabled="{Binding ElementName=optionA, Path=IsChecked}"/>
<TextBox Style="{StaticResource boxStyle}" IsEnabled="{Binding ElementName=optionB, Path=IsChecked}"/>
The binding works correctly (when Option A it checked, one box is enabled and the other is not). However, when either of the boxes becomes disabled, it does not follow the style defined above. The background goes to white no matter what I change the style color to.
Anyone have any ideas? Thanks.

The color used when disabled is hard-coded in the template as far as i know, you cannot easily change it unless it references a system-color in which case you can override.
The default Aero theme uses a ListBoxChrome control, not sure if that can be made to change its background accordingly, it has no template so it might be hard to modify it. You could of course throw it out and use whatever you want (which you can modify).

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.

WPF disabled checkbox background color

How do I remove the light gray color that appears behind the text of the disabled checkboxes? Thanks in advance!
I have changed ALL system colors:
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.ActiveBorderBrushKey}" Color="Transparent"/>
...
</Style.Resources>
but the background color behind text (when checkbox is Disabled) remains unchanged.
Setting Focusable="False" and IsHitTestVisible="False" will "disable" the checkbox without changing the appearance of it.
Not sure what you mean by "behind the text." The text itself becomes gray, but you can easily change the behavior using a Trigger:
<CheckBox Content="CheckBox" IsEnabled="False">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
Obviously a very simplified example here.
I know this is a really old question, but googling still finds it as one of the top results.
In this situation, you can just set IsHitTestVisible = false instead of IsEnabled = false.
This will display the checkbox as enabled while preventing any clicks within it.

Changing the content of button using a style

I'm creating an application that contains two types of users; staff, admin. Each user has his/her own permissions. For example, an admin can add, edit, delete etc; while the staff can only view. Currently within my app, I use a ListView to display data and then use a DataTemplate where by I set my buttons within, as shown below.
However, I want to change the content of the edit button to show View, rather then edit if the user is a staff user. I tried implementing the following code, but it doesn't seem to change.
<Button Content="Edit" Command="{Binding ShowEditCommand}" Width="50">
<Button.Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MetroButton}">
<Setter Property="Content" Value="View" />
<Style.Triggers>
<DataTrigger Binding="{Binding Role}">
<DataTrigger.Value>
<enum:EnumPermission>Admin</enum:EnumPermission>
</DataTrigger.Value>
<Setter Property="Content" Value="Edit"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I'm not very good with creating styles and therefore would appreciate some guidance in what I am doing wrong and what can be done to change it. Thanks in advance.
Edit:
Originally, as pointed out, I forgot to remove the `Content="Edit" from the button. However, when I remove that, the style still doesn't fully work.
Remove Content="Edit" from Button definition
<Button Content="Edit" ...
Style.Trigger will not be able to overwrite that value according to Dependency Property Setting Precedence List. It's enough that you set default value in Style as
<Setter Property="Content" Value="View" />
first just FYI you should not change the content in the style , you can bind the content to a property and change that property value
to solve this just remove Content="Edit" from the first line

Trouble binding to a property of templatedparent to set the value inside of a style setter in wpf

My problem:
I haven't been able to figure out how I inside the 'Setter.Value' field of a setter for a property A in a style targeting a particular control can do a binding to a property B of that particualr control. More specifically I want to use the Foreground brush value on a graphical element inside the visual tree of the Content property of a Button. this will ensure that the graphical element always has the foreground color set for this button control.
What I try to achive:
I'm working on a WPF-application where I have three button controls:
DefaultButton
SpecialButton
ExtendedSpecialButton
The DefaultButton is where I define the style of buttons in the application through a style with a ControlTemplate.
The SpecialButton introduces a new property not supposed to be used for general buttons. This property will be represented by one visual state that I define through a style setter. Else from that it shall be identical in apperance to the DefaultButton.
I define the style of this SpecialButton by basing it on the style of the DefaultButton. In this style there is no ControlTemplate only a MultiTrigger-response on the basis of a couple of property conditions setting av a couple of visual properties:
<Style x:Key="SpecialButtonStyle" TargetType="{x:Type MyControls:SpecialButton}" BasedOn="{StaticResource DefaultButtonStyle}">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsActive" Value="false"/>
<Condition Property="IsMouseOver" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDisabledBorder}" />
<Setter Property="Background" Value="{DynamicResource ButtonDisabledBg}" />
</MultiTrigger>
</Style.Triggers>
</Style>
All this worked great.
The next step is also no problem:
I wanted to base the ExtendedSpecialButton on the SpecialButton and set a default shape content inside the button.
<Style x:Key="ExtendedSpecialButtonStyle" TargetType="{x:Type MyControls:ExtendedSpecialButton}" BasedOn="{StaticResource SpecialButtonStyle}">
<Setter Property="Content">
<Setter.Value>
<Rectangle Fill="Black" Height="5" Width="15"></Rectangle>
</Setter.Value>
</Setter>
</Style>
The original style of DefaultButton is still present - the added visual state responding to the IsActiveProperty of the SpecialButton is still with us - and the ExtendedSpecialButton also inherited the visual behaviour created by the MultiTrigger of the SpecialButton.
I also successfully displayed a graphical element that this ExtendedSpecialButton should have.
However I wanted the fill of this graphical element to use the Foreground color. This foreground color is originally styled in the DefaultButton and works just fine for the two first buttons.
The code below is how I currently thought such a binding should be done. But this does not work:
<Style x:Key="ExtendedSpecialButtonStyle" TargetType="{x:Type MyControls:ExtendedSpecialButton}" BasedOn="{StaticResource SpecialButtonStyle}">
<Setter Property="Content">
<Setter.Value>
<Rectangle Fill="{Binding RelativeSource={RelativeSource TemplatedParent}}" Height="6" Width="20"></Rectangle>
</Setter.Value>
</Setter>
</Style>
Does anyone know what I could do to set up the binding so that it does what I intended it to do?

WPF ComboBox - showing something different when no items are bound

I have a ComboBox, and i want to change its look when the ItemsSource property is null. When it is in that state, i want to show a TextPanel with the text "Retrieving data" in it, and give it a look kind of similar to the watermarked textbox.
I figure to do this i need a ControlTemplate, and a trigger. I have the ControlTemplate here:
<ControlTemplate x:Key="LoadingComboTemplate" TargetType="{x:Type ComboBox}">
<Grid>
<TextBlock x:Name="textBlock" Opacity="0.345" Text="Retrieving data..." Visibility="Hidden" />
</Grid>
<!--
<ControlTemplate.Triggers>
<Trigger Property="ComboBox.ItemsSource" Value="0">
<Setter Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
-->
</ControlTemplate>
but my issue is how do i set up the trigger to show this when the ItemsSource property is null? I have tried a couple of different ways, and each way has given me the error message "Value 'ItemsSource' cannot be assigned to property 'Property'. Invalid PropertyDescriptor value.". My ComboBox xaml is this (including the attempted trigger):
<ComboBox Margin="112,35,80,0"
Name="MyComboBox"
Height="22.723"
VerticalAlignment="Top"
DisplayMemberPath="FriendlyName"
SelectedValuePath="Path"
TabIndex="160"
>
<Trigger>
<Condition Property="ItemsSource" Value="0" />
<Setter Property="Template" Value="{StaticResource LoadingComboTemplate}" />
</Trigger>
</ComboBox>
now should the trigger go on the ComboBox, or on the ControlTemplate? How do i access the ComboBox's ItemsSource property? Should i even be using a trigger?
Thanks!
Try putting {x:Null} for the value of the condition instead of 0.
Also I got it working by moving the Trigger to a style and modifing it slightly, see below.
<Style TargetType="ComboBox" x:Key="LoadingComboStyle">
<Style.Triggers>
<Trigger Property="ItemsSource" Value="{x:Null}">
<Setter Property="Template" Value="{StaticResource LoadingComboTemplate}" />
</Trigger>
</Style.Triggers>
</Style>
<ComboBox Style="{StaticResource LoadingComboStyle}" .... >
The reason it only works in a style, is that only EventTriggers are allowed in the triggers collection directly on the Framework Element. For property triggers (like above) you need to use a style (I learn something every day).
See FrameworkElement.Triggers
Note that the collection of triggers established on an element only supports EventTrigger, not property triggers (Trigger). If you require property triggers, you must place these within a style or template and then assign that style or template to the element either directly through the Style property, or indirectly through an implicit style reference.

Resources