Lately I’ve ran into situations where I had to change elements or had to request a value in the DOM from Silverlight. jLight, which was introduced in an earlier article, can help with that. jQuery offers great ways to change CSS during runtime. Silverlight can access the DOM, but it isn’t as easy as jQuery. All examples shown in this article can be looked at in this online demo. The code can be downloaded here. Part 1: The easy stuff Selecting and changing properties is pretty straight forward. Setting the text color in all <B> </B> elements can be done using the following code: jQuery.Select("b").Css("color", "red");
The Css() method is an extension method on jQueryObject which is return by the jQuery.Select() method. The Css() method takes to parameters. The first is the Css style property. All properties used in Css can be entered in this string. The second parameter is the value you want to give the property. In this case the property is “color” and it is changed to “red”.
To specify which element you want to select you can add a :selector parameter to the Select() method as shown in the next example.
jQuery.Select("b:first").Css("font-family", "sans-serif");
The “:first” pseudo-class selector selects only the first element. This example changes the “font-family” property of the first <B></B> element to “sans-serif”.
To make use of intellisense in Visual Studio I’ve added a extension methods to help with the pseudo-classes.
In the example below the “font-weight” of every “Even” <LI></LI> is set to “bold”.
jQuery.Select("li".Even()).Css("font-weight", "bold");
Because the Css() extension method returns a jQueryObject it is possible to chain calls to Css(). The following example show setting the “color”, “background-color” and the “font-size” of all headers in one go.
jQuery.Select(":header").Css("color", "#12FF70")
.Css("background-color", "yellow")
.Css("font-size", "25px");
Part 2: More complex stuff
In only a few cases you need to change only one style property. More often you want to change an entire set op style properties all in one go. You could chain a lot of Css() methods together. A better way is to add a class to a stylesheet and define all properties in there. With the AddClass() method you can set a style class to a set of elements. This example shows how to add the “demostyle” class to all <B></B> in the document.
jQuery.Select("b").AddClass("demostyle");
Removing the class works in the same way:
jQuery.Select("b").RemoveClass("demostyle");
jLight is build for interacting with to the DOM from Silverlight using jQuery. A jQueryObjectCss object can be used to define different sets of style properties in Silverlight. The over 60 most common Css style properties are defined in the jQueryObjectCss class. A string indexer can be used to access all style properties ( CssObject1[“background-color”] equals CssObject1.BackgroundColor). In the code below, two jQueryObjectCss objects are defined and instantiated.
private jQueryObjectCss CssObject1;
private jQueryObjectCss CssObject2;
public Demo2()
{
CssObject1 = new jQueryObjectCss
{
BackgroundColor = "Lime",
Color="Black",
FontSize = "12pt",
FontFamily = "sans-serif",
FontWeight = "bold",
MarginLeft = 150,
LineHeight = "28px",
Border = "Solid 1px #880000"
};
CssObject2 = new jQueryObjectCss
{
FontStyle = "Italic",
FontSize = "48",
Color = "#225522"
};
InitializeComponent();
}
Now instead of chaining to set all different properties you can just pass one of the jQueryObjectCss objects to the Css() method. In this case all <LI></LI> elements are set to match this object.
jQuery.Select("li").Css(CssObject1);
When using the jQueryObjectCss objects chaining is still possible. In the following example all headers are given a blue backgroundcolor and the last is set to match CssObject2.
jQuery.Select(":header").Css(new jQueryObjectCss{BackgroundColor = "Blue"})
.Eq(-1).Css(CssObject2);
Part 3: The fun stuff
Having Silverlight call JavaScript and than having JavaScript to call Silverlight requires a lot of plumbing code. Everything has to be registered and strings are passed back and forth to execute the JavaScript. jLight makes this kind of stuff so easy, it becomes fun to use. In a lot of situations jQuery can call a function to decide what to do, setting a style class based on complex expressions for example. jLight can do the same, but the callback methods are defined in Silverlight.
This example calls the function() method for each <LI></LI> element. The callback method has to take a jQueryObject, an integer and a string as parameters. In this case jLight differs a bit from the actual jQuery implementation. jQuery uses only the index and the className parameters. A jQueryObject is added to make it simpler to access the attributes and properties of the element.
If the text of the listitem starts with a ‘D’ or an ‘M’ the class is set. Otherwise null is returned and nothing happens.
private void button1_Click(object sender, RoutedEventArgs e)
{
jQuery.Select("li").AddClass(function);
}
private string function(jQueryObject obj, int index, string className)
{
if (obj.Text[0] == 'D' || obj.Text[0] == 'M')
return "demostyle";
return null;
}
The last thing I would like to demonstrate uses even more Silverlight and less jLight, but demonstrates the power of the combination. Animating a style property using a Storyboard with easing functions. First a dependency property is defined. In this case it is a double named Intensity. By handling the changed event the color is set using jQuery.
public double Intensity
{
get { return (double)GetValue(IntensityProperty); }
set { SetValue(IntensityProperty, value); }
}
public static readonly DependencyProperty IntensityProperty =
DependencyProperty.Register("Intensity", typeof(double), typeof(Demo3),
new PropertyMetadata(0.0, IntensityChanged));
private static void IntensityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var i = (byte)(double)e.NewValue;
jQuery.Select("span").Css("color", string.Format("#{0:X2}{0:X2}{0:X2}", i));
}
An animation has to be created. This code defines a Storyboard with one keyframe that uses a bounce ease as an easing function. The animation is set to target the Intensity dependency property defined earlier.
private Storyboard CreateAnimation(double value)
{
Storyboard storyboard = new Storyboard();
var da = new DoubleAnimationUsingKeyFrames();
var d = new EasingDoubleKeyFrame
{
EasingFunction = new BounceEase(),
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(1.0)),
Value = value
};
da.KeyFrames.Add(d);
Storyboard.SetTarget(da, this);
Storyboard.SetTargetProperty(da, new PropertyPath(Demo3.IntensityProperty));
storyboard.Children.Add(da);
return storyboard;
}
Initially the Intensity is set to 128 which results in a gray color. When one of the buttons is pressed, a new animation is created an played. One to animate to black, and one to animate to white.
public Demo3()
{
InitializeComponent();
Intensity = 128;
}
private void button2_Click(object sender, RoutedEventArgs e)
{
CreateAnimation(255).Begin();
}
private void button3_Click(object sender, RoutedEventArgs e)
{
CreateAnimation(0).Begin();
}
Conclusion
As you can see jLight can make the life of a Silverlight developer a lot easier when accessing the DOM. Almost all jQuery functions that are defined in jLight use the same constructions as described above. I’ve tried to stay as close as possible to the real jQuery. Having JavaScript perform callbacks to Silverlight using jLight will be described in more detail in a future tutorial about AJAX or eventing.