WPF change dynamicresource in codebehind - wpf

The standard RadioButton does not support setting the color of the ellipse. So, I took a radiobutton template from this location as a basis for a custom RadioButton:
RadioButton Styles and Templates
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="{DynamicResource ControlLightColor}" />
<GradientStop Color="{DynamicResource ControlMediumColor}" Offset="1.0" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
ControlLightColor and ControlMediumColor are defined as:
<Color x:Key="ControlLightColor">#ffff9a</Color>
<Color x:Key="ControlMediumColor">#ffff9a</Color>
Which gives us a yellow-ish ellipse.
How can I alter this color in the codebehind?
Regards,
Michel

Create a style by following this:
Creating a Style in code behind
then assign it to your element.Style
You can also access resources by
Resources["mykey"]

Solution:
<Ellipse x:Name="Border" StrokeThickness="1" Fill="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.RadioButtonColor}">
Public ReadOnly Property RadioButtonColor() As SolidColorBrush
Get
Dim solidColorBrush As SolidColorBrush
If MyBusinessLogic Then
solidColorBrush = _radioButtonNotRequiredBrush
Else
solidColorBrush = _radioButtonRequiredBrush
End If
Return solidColorBrush
End Get
End Property
Thumbs up for JRB for thinking along.

Related

Dont understand why the color binding varies between Fill and GradientStop

I'm trying to get to grips with ControlTemplates in WPF. I noticed that when you try to reference a templated parent's background color - the binding statement seems to be different for elipse Fill and elipse GradientStop. Can any one explain why this is.
This works...
<Ellipse RenderTransformOrigin=".5,.5" Fill="{TemplateBinding Background}">
This works...
<GradientStop Offset="0" Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background.Color}"/>
This doesnt work - why is this?
<GradientStop Offset="0" Color="{TemplatedParent Background}"/>
This produces an error...
<GradientStop Offset="0" Color="{TemplatedParent Background.Color}"/>
This doesnt work...
<Ellipse RenderTransformOrigin=".5,.5" Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background.Color}">
The instance looks like this...
<Button Template="{StaticResource buttonTemplate1}"
Height="100" Width="100" FontSize="40"
Background="Violet" Foreground="Aquamarine"
Padding="0" Margin="6">Button 5</Button>
As mentioned in comments, you need to distinguish between Brush and Color type properties.
Brush-typed properties are used by controls, and include Fill, Stroke, and Background.
The most common use of Color is as a component of a Brush, either the color of a SolidColorBrush, or the color of a GradientStop of a LinearGradientBrush.
There are also some binding syntax errors in the examples you posted.
This doesnt work - why is this?
<GradientStop Offset="0" Color="{TemplatedParent Background}"/>
That's not a valid binding syntax. But assuming you meant TemplateBinding Background, then it's still not valid, because the target Color is a different type than the source Background (Brush).
This produces an error...
<GradientStop Offset="0" Color="{TemplatedParent Background.Color}"/>
Same issue as above, you mean TemplateBinding instead of TemplatedParent. And, I believe that in any case TemplateBinding won't work for a nested property. You would need to write:
<GradientStop Offset="0" Color="{TemplateBinding
RelativeSource={RelativeSource TemplatedParent}, Path=Background.Color}" />
This doesnt work...
<Ellipse RenderTransformOrigin=".5,.5" Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Background.Color}">
The syntax is correct here, but the types don't match -- the target is Brush, and the source is System.Color.

Cannot find governing FrameworkElement or FrameworkContentElement for target element. GradientStop

I have a list box contains Colors and Each Color have 7 Heads it is to choose Print Head for Color. so my Binding variable is when print head is selected , Color box should have this Styles.
<Setter TargetName="colorSelectionRectangle" Property="Fill">
<Setter.Value>
<LinearGradientBrush SpreadMethod="Repeat" StartPoint="0,0" EndPoint="25,25">
<LinearGradientBrush.RelativeTransform>
<ScaleTransform ScaleX="0.01" ScaleY="0.01" />
</LinearGradientBrush.RelativeTransform>
<GradientStop Offset="0" Color="White" />
<GradientStop Offset="0.5" Color="White" />
<GradientStop Offset="0.5" Color="{Binding [0].Item.PrintColor.Argb}" />
<GradientStop Offset="1" Color="{Binding [0].Item.PrintColor.Argb}" />
</LinearGradientBrush>
</Setter.Value>
and My error is :
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=[0].Item.PrintColor.Argb; DataItem=null; target element is 'GradientStop' (HashCode=52327179); target property is 'Color' (type 'Color')
I believe that you have this problem because GradientStop is not a FrameworkElement... from MSDN:
System.Object
System.Windows.Threading.DispatcherObject
System.Windows.DependencyObject
System.Windows.Freezable
System.Windows.Media.Animation.Animatable
System.Windows.Media.GradientStop
If you notice the extended System.Windows.Freezable class above, then you will see that this class is also 'freezable'... this means that it cannot be modified. See the Freezable Objects Overview page at MSDN for more information.

Property path can't find reference

What's the syntax for the property path to find the color property of the second gradientStop?
<Rectangle.Fill>
<RadialGradientBrush>
<GradientStop Color="White" Offset="0" />
<GradientStop Color="#FFD0D0D0" Offset="0.992" />
</RadialGradientBrush>
</Rectangle.Fill>
I tried New PropertyPath("Fill.RadialGradientBrush.GradientStops[1].Color") but it could find the color property.
In this case, the Fill property is the RadialGradientBrush. The brush is not a member of Fill.
Try PropertyPath("Fill.GradientStops[1].Color")
I guess it should be :
(Fill as RadialGradientBrush).GradientStops[1].Color
Because RadialGradientBrush is not a property, but a class

Triggering the style of a WPF button when a dependency property changes

I've created a button control template where I want to change the color of the button depending on the mode of the button (whether its in Go mode or Stop mode). The XAML looks like :
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse x:Name="innerCircle" RenderTransformOrigin=".5,.5">
<Ellipse.RenderTransform>
<ScaleTransform ScaleX=".8" ScaleY=".8"/>
</Ellipse.RenderTransform>
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStopCollection>
<GradientStop Offset="0" Color="Green"/>
<GradientStop Offset="1" Color="Transparent"/>
</GradientStopCollection>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Viewbox>
<ContentPresenter Margin="{TemplateBinding Padding}"/>
</Viewbox>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsGo}" Value="True">
<Setter TargetName="outerCircle" Property="Fill">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStopCollection >
<GradientStop Offset="0" Color="White"/>
<GradientStop Offset="1" Color="Red"/>
</GradientStopCollection>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter TargetName="innerCircle" Property="Fill">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStopCollection>
<GradientStop Offset="0" Color="Red"/>
<GradientStop Offset="1" Color="Transparent"/>
</GradientStopCollection>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Grid.Resources>
<Button Background="Transparent" Content="STOP" Padding="10" Template="{StaticResource buttonTemplate}" Height="84" Width="87" Click="Button_Click"></Button>
</Grid>
In my DataTrigger i have a binding to a IsGo DP property which i have defined in the code behind (of type boolean). I have a click handler which toggles the state of this DP in the code behind :
/// <summary>
/// Interaction logic for GoButton.xaml
/// </summary>
public partial class GoButton
{
public GoButton()
{
InitializeComponent();
}
public static readonly DependencyProperty IsGOProperty = DependencyProperty.Register("IsGo", typeof(Boolean), typeof(GoButton), new PropertyMetadata(false));
public Boolean IsGo
{
get { return (Boolean)GetValue(IsGOProperty); }
set { SetValue(IsGOProperty, value); }
}
private void Button_Click(object sender, RoutedEventArgs e)
{
IsGo = !IsGo;
}
}
However, when i click my button, nothing happens - although the click handler code executes and toggles the DP property, the colour of the button stays green and doesn't change to red. Any ideas what i'm doing wrong ?
thanks
You need to trigger the dependency property to refresh. You can do that by implementing INotifyPropertyChanged, removing IsGOProperty and then implementing IsGo like this:
private bool _isgo = false;
public bool IsGo {
get
{
return _isgo;
}
set
{
_isgo = value;
PropertyChanged(new PropertyChangedEventArgs("IsGo");
}
}
Your TemplatedParent is (I'm guessing) the button you're templating. The codebehind where you've defined your property most likely isn't a control derived from button, so I'm guessing your trigger's binding is incorrect...
If you could post the rest of your XAML and/or confirm which codebehind your property is in, this could be confirmed.
EDIT: Your comment confirms my theory: you're binding to TemplatedParent but the property isn't on TemplatedParent, it's on your usercontrol. The easist solution is to add a x:Name="root" tag to your UserControl's root element, and then change the trigger's binding to {Binding ElementName=root, Path=IsGo}.

Template Binding to background and foreground colors?

I'm building a simple ControlTemplate for a Button. I want to draw a 2 color gradient, and bind the two colors so I don't need to hard code them in the template. But since Background and Foreground are Brushes and not just Colors, I'm not sure this will work.
Can anyone tell me if there is a good way to do this? it seems simple enough. Thanks.
<ControlTemplate x:Key="ElipseButton" TargetType="Button">
<Ellipse>
<Ellipse.Fill>
<RadialGradientBrush RadiusX="1" RadiusY="1" GradientOrigin="0.7,0.8">
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="Black" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</ControlTemplate>
I want to replace the 'Black' and 'White' colors with TemplateBindings.
You can use attached properties to add some new Color properties that you can use on Button:
public class ColorExtensions
{
public static readonly DependencyProperty ColorFrontProperty = DependencyProperty.RegisterAttached(
"ColorFront",
typeof(Color),
typeof(ColorExtensions),
new UIPropertyMetadata(Colors.White));
public static Color GetColorFront(DependencyObject target)
{
return (Color)target.GetValue(ColorFrontProperty);
}
public static void SetColorFront(DependencyObject target, Color value)
{
target.SetValue(ColorFrontProperty, value);
}
public static readonly DependencyProperty ColorBackProperty = DependencyProperty.RegisterAttached(
"ColorBack",
typeof(Color),
typeof(ColorExtensions),
new UIPropertyMetadata(Colors.Black));
public static Color GetColorBack(DependencyObject target)
{
return (Color)target.GetValue(ColorBackProperty);
}
public static void SetColorBack(DependencyObject target, Color value)
{
target.SetValue(ColorBackProperty, value);
}
}
You can then set these on any instance and access them in your template using normal Bindings (TemplateBindings won't work here):
<Button Content="Click Me" local:ColorExtensions.ColorFront="Red">
<Button.Template>
<ControlTemplate TargetType="Button">
<Ellipse>
<Ellipse.Fill>
<RadialGradientBrush RadiusX="1" RadiusY="1" GradientOrigin="0.7,0.8">
<GradientStop Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:ColorExtensions.ColorFront)}" Offset="0"/>
<GradientStop Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:ColorExtensions.ColorBack)}" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</ControlTemplate>
</Button.Template>
</Button>
Personally, I would just put the entire Brush into your template. This gives you much more control, later, as it allows you to change (via template changes) the brush from a radial gradient to a linear gradient, etc.

Resources