Tuesday, July 05, 2011

 

Adding a GradientStop Property to a UserControl

Say you have a UserControl that uses a gradient in Silverlight 4. Say you want to be able to modify the colors of the gradient as Properties of that UserControl. How would you do it?

Defining the XAML
First lets define how the GradientStop is setup in the UserControl. There are two places you can put GradientStops in a UserControl, in the contents of the LayoutRoot or as a StaticResource. The first option is best if the gradient is only used once. Just be sure to give the GradientStop an x:Name so nameUsedForGradientStop.Color can be used to set the color in the code-behind.
<Rectangle>
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop x:Name="nameUsedForGradientStop" Offset="0" />
<GradientStop Color="White" Offset="1.0" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
However, if you use the same gradient multiple times you'll want it as a Resource.
<UserControl.Resources>
<LinearGradientBrush x:Key="LGB1">
<GradientStop Offset="0" /><!-- Set via code-behind -->
<GradientStop Color="Black" Offset="1.0" />
</LinearGradientBrush>
</UserControl.Resources>
Using an x:Name for the GradientStop on the resource will turn up Null. A StaticResource needs to be accessed through the resource collection in the code-behind.
GradientStop firstStop = (this.Resources["LGB1"] as LinearGradientBrush).GradientStops[0];
Tying the Gradient stop to a standard Property
With the GradientStop accessiable to the codebehind we can tie the Color to a property of the UserControl. This property can be used to allow the color to be easily changed by anything using this UserControl. One approach to creating such a property is by using a standard property. We can tie it in with the XAML by accessing the GradientStop on the properties setter. if the GradientStop is given the x:Name of "gradientStop" in the XAML contents the following will work.
private Color gradientColor = Color.FromArgb(255, 65, 69, 145); //default color
public Color GradientColor
{
get { return gradientColor; }
set
{
gradientColor = value;
gradientStop.Color = value;
}
}
Note: We can't use XAML databinding for a GradientStop because it is not considered a UI element. For UI elements it is better to take advantage of databinding as described here, stackoverflow.com...binding-silverlight-usercontrol-custom-properties-to-its-elements.

If the XAML hosting this UserControl doesn't set the GradientColor it will default to null instead of the default we set. Changing this requires simply setting it in the UserControls constructor:
public Orb()
{
InitializeComponent();
gradientStop.Color = GradientColor; //sets orb to its default color
}
Using a DependencyProperty
Say you want to bind this property, or animate it, or do something that'd require using a DependencyProperty. Since a DependencyProperty uses SetValue(), you'd no longer want to Set the GradientStops Color in the Setter. This is because the color will not be set when SetValue() is called outside of the property wrapper. The proper way to set the GradientStops color is by using the DependencyProperty PropertyChangedCallback.
private static void TopLeftColor_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Gradient instance = d as Gradient;
if (instance != null)
{
instance.firstStop.Color = (Color)e.NewValue;
}
}
public Color TopLeftColor
{
get { return (Color)GetValue(TopLeftColorProperty); }
set { SetValue(TopLeftColorProperty, value); }
}
public static readonly DependencyProperty TopLeftColorProperty =
DependencyProperty.Register(
"TopLeftColor",
typeof(Color),
typeof(Gradient),
new PropertyMetadata(
Color.FromArgb(255, 255, 0, 0),
TopLeftColor_Changed)
);
Here I added the firstStop as a member to the class because the PropertyChangedCallback is not called when the default value of the DependencyProperty is set. This means the gradient doesn't get any color until the property is changed. The default color can be bound to the GradientStop in the constructor.
private GradientStop firstStop;
public Gradient()
{
InitializeComponent();
firstStop = (this.Resources["LGB1"] as LinearGradientBrush).GradientStops[0];
firstStop.Color = TopLeftColor;
}

Labels: ,


This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]