WPF DataTrigger Based on Color - c#

I'm trying to change the background of control A based on the background of control B, using a DataTrigger.
I've attempted to do this the conventional way you would change any property in a DataTrigger. Worst case I figure I can just use a converter, but wanted to try this first. Where have I gone astray, or is there simply no way to do this (i.e., bind to a control's background in a DataTrigger)?
<Grid.Style>
<Style TargetType="{x:Type Grid}">
<Style.Triggers>
<DataTrigger Binding="{Binding Background, ElementName=Icon}" Value="Black">
<Setter Property="Background" Value="LimeGreen"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>

Related

Give a toggle button the color "#FF5D0000" in the main window

I want to give mij text on my button a customized color in the MainWindow.xaml.cs
Normally you give the color in the cs file by this way to the command:
ToggleButton.Foreground = Brushes.Green;
But I want to give the hexnumber
I've already tried something like this :
SolidColorBrush Owncolor = (SolidColorBrush)(new BrushConverter().ConvertFrom("#FF5D0000"));
ToggleButton.Foreground = Brushes.Owncolor;
Instead of doing it in code behind (unless you have a very specific reason to do that), you can work on your xaml
<ToggleButton Foreground = "#FF5D0000"/>
if you are doing it based on some condition, also please take a look at this. It's always a better practice to handle graphical stuff in your xaml as much as you can
for instance you can do
<ToggleButton>
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Foreground" Value="Green"/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
Usually in WPF you tend to use styles defined in XAML to change how controls looks. However, using the BrushConverter works if you absolutely have to use the hexadecimal syntax in codebehind. I'd consider building a new SolidColorBrush with Color.FromArgb easier, but that also works.
As for how to use styles and XAML properly, you should probably read some tutorials or books. WPF is quite a different beast than Windows Forms or a lot of older UI frameworks, so there's some re-learning required.
The simplest way of achieving what you want (a different text colour when the button is pressed) would be the following style:
<Style TargetType="ToggleButton">
<Setter Property="Foreground" Value="#FF5D0000"/>
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="Green"/>
</Trigger>
</Style.Triggers>
</Style>
When placed in the Resources of your Window it would apply to all ToggleButtons in that window.

WPF Custom Control That Displays Content Inline or in a Popup

I am creating a custom WPF content control that has a DisplayMode property which can be:
Inline
Popup
When DisplayMode="Inline", my ControlTemplate can use a standard ContentPresenter like normal.
However, when DisplayMode="Popup", I want the Content to be displayed in a Popup control.
How should I solve this problem?
Does it have to happen purely in code when the DisplayMode property changes? How do I move the content of the Content property between a ContentPresenter and the Popup?
It looks like I was trying to make this more complex than it really is.
The solution to this was to create two separate ControlTemplate(s). One that displays inline and one that displays in a Popup control.
Next, all I had to do was create a couple style triggers that change the ControlTemplate based on the value of the DisplayMode property.
It looks like this:
<Style x:Key="MyControlStyle" TargetType="{x:Type my:MyControl}">
<Setter Property="Template" Value="{StaticResource InlineTemplate}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding DisplayMode}" Value="Inline">
<Setter Property="Template" Value="{StaticResource InlineTemplate}"/>
</DataTrigger>
<DataTrigger Binding="{Binding DisplayMode}" Value="Overlay">
<Setter Property="Template" Value="{StaticResource OverlayTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>

Using trigger to change property of many items

I created a WPF custom control, which works fine.
It has a style which sets some properties and a template.
Now i want to change the control, so it has a 'Active' property.
If this is true it should use the Property 'ActiveBrush' for the Stroke
of some Rectangles in the Template, else it should use 'InactiveBrush'.
I want to use the ActiveBrush as the default Stroke, and change it to InactiveBrush
with a Trigger.
This works fine with one Rectangle when i use this:
<Trigger Property="Active" Value="False">
<Setter TargetName="Rec1" Property="Stroke" Value="{Binding Path=InactiveBrush, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
But since I don't want to set each rectangle with a seperated setter, I am asking myself if it shouldn't be possible to set the property of all Rectangles in the Template with one Setter.
I already tried:
<Trigger Property="Active" Value="False">
<Setter Property="Rectangle.Stroke" Value="{Binding Path=InactiveBrush, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
But this didn't work.
Has anyone a suggestion, how to implement this?
Thanks in advance.
#Robert Rossney - this style will not run since a target type of Rectangle doesn't have a property Active. But that is the right path to go, with a minor change:
<Style TargetType="Rectangle">
<Style.Triggers>
<DataTrigger Binding="{Binding Active, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MyControl}}}" Value="False">
<Setter Property="Stroke" Value="{Binding Path=InactiveBrush, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MyControl}}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
This style should be nested in Style.Resources of the control style or in ControlTemplate.Resources of the ControlTemplate for the control. This way you're localizing this style only to your control. Any Rectangle outside of your control will not be affected.
I'm sure you know this but are just overlooking it: If you want to apply a style to all controls of a type, create a style with a TargetType of that type and put it in your custom control's resource dictionary. If you still need to apply specific styles to individual controls of that type, define those styles using the BasedOn property.
So, in your MyControl.Resources element, you'd put:
<Style TargetType="Rectangle">
<Style.Triggers>
<Trigger Property="Active" Value="False">
<Setter Property="Stroke" Value="{Binding Path=InactiveBrush, RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
<Style>
<Style>
and any Rectangle that needed its own style would start like this:
<Style TargetType="Rectangle" BasedOn="{StaticResource {x:Type Rectangle}}">

Changed Background Color of Element when Disabled

How would I change the background color of a TextBox Control in the Default Style Xaml to be a different color when the control is either Disabled or ReadOnly ?
You can achieve this with triggers in the style:
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsReadOnly" Value="True">
<Setter Property="Background" Value="Green" />
</Trigger>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Im not at a PC at the moment (just mobile) but I think you can edit the template of your control and there are some Visual States for your some controls that define things like disabled states, mouse overs, etc... which you should be able to redefine?
The way I accomplished this was to create a Converter for the control.
When the control is bound to an object it detects if the control is Enabled from this object that it is bound to. Based upon this it sets the background color for the Textbox accordingly.

How do I know whether to use a style or override a control template?

This question is inspired by this recent question and other situations I've encountered in my WPF development. How do I know whether it is enough to set a style on a control to override some default behavior vs creating a new control template?
More concretely, in the question above, the author wants to change the look of a ListBoxItem when it is selected. (See code reprinted below). Everything works, except the Background property. How is one supposed to know that they should override the Control Template for this?
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Content" Value="{Binding Path=Name}"/>
<Setter Property="Margin" Value="2"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Background" Value="Yellow"/>
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
As to whether to use a style or template Ray provided a great response.
As to how to solve your problem without creating a template, maybe I can help.
The background color is being set by the SystemColors. Using Blend and creating a template you can see the exact xaml.
So if NO TEMPLATES! is a requirement you can always change what that resource is.
Example :
<ListBox>
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Yellow" />
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Content" Value="{Binding Path=Name}"/>
<Setter Property="Margin" Value="2"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
<ListBoxItem>Test 1</ListBoxItem>
<ListBoxItem>Test 2</ListBoxItem>
<ListBoxItem>Test 3</ListBoxItem>
</ListBox>
That will give you the background color for that given ListBox and not screw up anything else in the app.
Styles can be thought of very closely to CSS styles in HTML. If all you want to do is change the basic properties of a control such as Background, Foreground or whatever properties it exposes then a Style is exactly what you need. Styles also allow you to apply triggers so for animations, a style is also sufficient.
If you're finding you want to change the intrinsice behaviours / inner workings on a control then a control template is what you want. For example, if you want to change how a button is laid out by adding some sort of grid behaviour, then using a control template is the way forward.
Unfortunately, for your specific example, you don't know unless you try it. Basically you first try it with a Style....and if that doesn't work for whatever reason, then you write a ControlTemplate. You usually only end up writing ControlTemplates for the reasons Ray mentioned.
My guess is that the trigger you're trying to set has also been hardcoded in the ControlTemplate...which is bad design imo because it prevents the Style from overriding it.
By "Background" I take it to mean the "blue" rectangle that surrounds the ListBoxItem when it is selected?
This is actually the FocusVisualStyle property, which is a style that describes what the item should look like when it is focused. The Control explicitly sets this property (described here), so in order to override it, you will have to redefine the Control Template, making sure to use a default Style setter to set it to {x:Null}.

Categories