UserControl Custom Properties for Triggers - wpf

I am writing a custom user control, called MyUserControl. I have many DependecyProperties for it, which I use in the MainWindow where several MyUserControl are defined multiple times. What I would like to know is how can I create custom Properties that the Triggers/Properties for a style would fire?
For example, if I have a custom property BOOL IsGoing and a custom property MyBackgroung(the background of the UserControl), both defined as :
public bool IsGoing
{
get { return (bool)this.GetValue(IsGoingProperty); }
set { this.SetValue(IsGoingProperty, value); }
}
public static readonly DependencyProperty IsGoingProperty = DependencyProperty.RegisterAttached(
"IsGoing", typeof(bool), typeof(MyUserControl), new PropertyMetadata(false));
public Brush MyBackground
{
get { return (Brush)this.GetValue(MyBackgroundProperty); }
set { this.SetValue(MyBackgroundProperty, value); }
}
public static readonly DependencyProperty MyBackgroundProperty = DependencyProperty.Register(
"MyBackground", typeof(Brush), typeof(MyUserControl), new PropertyMetadata(Brushes.Red));
and if I define my UserControl in MainWindow.xaml, how can I access the Triggers and set MyBackground, depending on whether or not the IsGoing property is true/false?
I tried many things, but in essence, I'm trying to achieve something like:
<custom:MyUserControl MyBackground="Green" x:Name="myUC1" Margin="120.433,0,0,65.5" Height="50" Width="250" VerticalAlignment="Bottom" HorizontalAlignment="Left" >
<Style>
<Style.Triggers>
<Trigger Property="IsGoing" Value="True">
<Setter Property="MyBackground" Value="Yellow"/>
</Trigger>
</Style.Triggers>
</Style>
</custom:MyUserControl>
I hope my explanation is good enough for you to understand. I've been working on this for a couple of days now, and I can't seem to find the solution.
Thanks for the help!!!
Adrian

Your style should just need to be used as UserControl.Style and have the correct TargetType, also default values you intend to change via trigger need to be moved into the style due to precedence:
<custom:MyUserControl.Style>
<Style TargetType="custom:MyUserControl">
<Setter Property="MyBackground" Value="Green"/>
<Style.Triggers>
<Trigger Property="IsGoing" Value="True">
<Setter Property="MyBackground" Value="Yellow"/>
</Trigger>
</Style.Triggers>
</Style>
</custom:MyUserControl.Style>
Whether this actually does anything depends on how you use the properties in the control definition.

Related

User control parameter in wpf mvvm

I want to create a user control with a bool parameter that defines a dynamic behavior, using MVVM pattern, so I can use the user control in another view that way :
<local:MyUserControl BoolParam={Binding aBoolBinding} />
About the coding of the user control, the xaml should use the value of BoolParam to do something like this :
...
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Trigger>
<DataTrigger Binding="{referenceToBoolParam}" Value="False" >
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
...
Am I supposed to define a property
public bool BoolParam { get; set; }
in the code-behind of the user control, and to code the logic associated to this parameter in the ViewModel of the user control ?
Actually I am a bit confused about it, what is the good practice ?
BoolParam should be a dependency property for you to be able to bind something to it. You define this in the code-behind of MyUserControl:
public bool BoolParam
{
get { return (bool)this.GetValue(BoolParamProperty); }
set { this.SetValue(BoolParamProperty, value); }
}
public static readonly DependencyProperty BoolParamProperty = DependencyProperty.Register(
"BoolParam", typeof(bool), typeof(MyUserControl), new PropertyMetadata(false));
You could then set the DataContext of the UserControl to an instance of a view model that contains a public bool property called aBoolBinding and bind to this one as usual.
View Model:
private bool _b;
public bool aBoolBinding
{
get
{
return _b;
}
set
{
_b = value;
NotifyPropertyChanged();
}
}
View:
<local:MyUserControl BoolParam="{Binding aBoolBinding}" />
This is how data binding works. A target property in the views is bound to a source property of a view model.
Edit:
This binds to the BoolParam property of the UserControl from a TextBox style defined in the UserControl:
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding BoolParam, RelativeSource={RelativeSource AncestorType=UserControl}}" Value="False" >
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>

Trigger for custom dependency properties in Style

The problem
I defined a reusable control, MyControl, that extends a TextBox.
I want to set a Trigger to one of its dependency properties.
So I added a style to it, with Triggers.
But if I set the TargetType of the Style to MyControl, I get a XAML warning that 'MyControl' TargetType does not match type of element 'TextBlock'.
And if I set it to TextBlock, I get a compilation error that The member "MyDependencyProperty" is not recognized or is not accessible..
How can I define this style with the triggers?
Sample
C# code-behind
namespace UserControls.Local
{
public partial class MyControl : TextBlock
{
#region Trogdor
public static readonly DependencyProperty TrogdorProperty = DependencyProperty.Register(
"Trogdor", typeof (bool), typeof (MyControl), new PropertyMetadata(default(bool)));
public bool Trogdor
{
get { return (bool) GetValue(TrogdorProperty); }
set { SetValue(TrogdorProperty, value); }
}
#endregion
public MyControl()
{
InitializeComponent();
}
}
}
XAML
<TextBlock
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:UserControls.Local"
mc:Ignorable="d"
Text="BOOP!"
x:Class="UserControls.Local.MyControl">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Blue"/>
<Style.Triggers>
<Trigger Property="Trogdor" Value="True">
<Setter Property="Foreground" Value="DeepPink"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
The solution I found was to "fully qualify" the dependency property on the binding:
<Trigger Property="local:MyControl.Trogdor" Value="True">
Not sure if you are still looking for a solution, but the answer in this thread worked for me, while yours didn't.
It uses a DataTrigger with a binding on the root element, instead of a Trigger:
<DataTrigger Binding="{Binding Path=Highlight, RelativeSource={RelativeSource AncestorType={x:Type Elements:DataElement}}}" Value="True">
<Setter Property="Control.Background" Value="{DynamicResource EntryBoxHighlightBackground}"/>
</DataTrigger>
With your solution, I press the button and the value of the variable changes but the style trigger doesn't apply the changes, like it was not informed of the change in the variable.

WPF: DataGridRow IsMouseOver True trigger should set background on complete row and disable backgrounds set on individual cells temporarily

I use DataGridTextColumns which set the background of cells using an IValueConverter. Next to these I have
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="DodgerBlue"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
The backgrounds set on the individual columns take precedence on the background set on the row on MouseOver.
How can I make sure the cell backgrounds are disabled temporarily if the mouse hovers over the row?
I assume you set the value for the background manually. If that is the case that value takes precedence as you already noticed.
Instead you have to bring the "default" values you want to set into the style as setters as well and then overwrite them inside your trigger like you already do.
Without more code I can't give you a better explanation, but this will get you onto the right track.
Here is a rough example:
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Background" Value="Green"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="DodgerBlue"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
Disclaimer: I haven't tried this.
If you're using MVVM, you could use an AttachedBehavior to set a flag in your object on mouse over, that you could reference in your columns to shut off their color.
Here's an example behavior from https://znite.wordpress.com/2010/02/20/mvvm-mouseover-binding/
public static partial class Behaviours
{
private static readonly List<FrameworkElement> _wiredUpElements = new List<FrameworkElement>();
private static readonly object _wiredUpElementsLock = new object();
public static readonly DependencyProperty MouseOverProperty
= DependencyProperty.RegisterAttached(
"MouseOver",
typeof(object),
typeof(Behaviours),
new FrameworkPropertyMetadata(false,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
MouseOverBindingPropertyChanged));
public static void SetMouseOver(FrameworkElement element, object value)
{
element.SetValue(MouseOverProperty, value);
}
private static void MouseOverBindingPropertyChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var element = d as FrameworkElement;
if (element == null || _wiredUpElements.Contains(element))
{
return;
}
lock (_wiredUpElementsLock)
{
if (_wiredUpElements.Contains(element))
{
return;
}
_wiredUpElements.Add(element);
element.MouseEnter += (sender, args) =>
{
var e = (FrameworkElement) sender;
SetMouseOver(e, e.DataContext);
};
}
}
}

WPF Bind to DependenyProperty

I have a DependenyProperty:
public static readonly DependencyProperty SelectedBackgroundProperty = DependencyProperty.Register("SelectedBackground", typeof(Brush), typeof(CustomizedMetroTabItem), new UIPropertyMetadata(null));
public Brush SelectedBackground
{
get { return (Brush)GetValue(SelectedBackgroundProperty); }
set { SetValue(SelectedBackgroundProperty, value); }
}
I want to bind my Background property to the value of the SelectedBackgroud DependenyProperty
so I did the following:
<Setter Property="Background" Value="{Binding SelectedBackground, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
I also tried
<Setter Property="Background" Value="{TemplateBinding SelectedBackground}"/>
But it doesnt work, why is that? (Ofcourse I set the SelectedBackground from the XAML)
Since a setter isn't part of the template, TemplatedParent won't work.
Use RelativeSource={RelativeSource Mode=Self} to access the current object from a style setter.

Style Trigger on Attached Property

I have created my own Attached Property like this:
public static class LabelExtension
{
public static bool GetSelectable(DependencyObject obj)
{
return (bool)obj.GetValue(SelectableProperty);
}
public static void SetSelectable(DependencyObject obj, bool value)
{
obj.SetValue(SelectableProperty, value);
}
// Using a DependencyProperty as the backing store for Selectable. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SelectableProperty =
DependencyProperty.RegisterAttached("Selectable", typeof(bool), typeof(Label), new UIPropertyMetadata(false));
}
And then I'm trying to create a style with a trigger that depends on it:
<!--Label-->
<Style TargetType="{x:Type Label}">
<Style.Triggers>
<Trigger Property="Util:LabelExtension.Selectable" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<TextBox IsReadOnly="True" Text="{TemplateBinding Content}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
But I'm getting a run time exception:
Cannot convert the value in attribute 'Property' to object of type 'System.Windows.DependencyProperty'. Error at object 'System.Windows.Trigger' in markup file
How can I access the value of the attached property in a style trigger? I have tried using a DataTrigger with a RelativeSource binding but it wasn't pulling the value through.
Your trigger declaration is fine, but your attached property declaration has a glitch. The owner type of a dependency property needs to be the type that declares it, not the type you plan to attach it to. So this:
DependencyProperty.RegisterAttached("Selectable", typeof(bool), typeof(Label)...
needs to change to this:
DependencyProperty.RegisterAttached("Selectable", typeof(bool), typeof(LabelExtension)...
^^^^^^^^^^^^^^^^^^^^^^

Resources