Constant Silverlight CPU usage? Double check your animations.
I had to fix a problem in a Silverlight application we are building. The problem was that it’s CPU usage was constant, between %20 and %40, and never stopped. I won’t go into the details of how I discovered the problem, but I’ll tell you what the problem was, and how we solved it.
The application
In our application we have dynamic content that is requested asynchronously to a web service. While the request is made, we show a small spinning donut. When the request is done, we remove the spinning donut and replace it with the content we want to show. The spinning donut is a tiny xaml with an animation that loops forever.
The problem
When the donut is removed from the page, the animation keeps looping until the garbage collector reclaims it, and that might take a long time. So the CPU usage was wasted due to that invisible animation which was no longer used.
The solution
Before replacing the spinning donut, we stop the animation. That solved the problem.
Unfortunately, Silverlight controls doesn’t implement IDisposable, so you can’t just stop the animation in a Dispose method. You have to do this manually.
I hope Silverlight makes each DependencyObject or UIElement implement IDisposable in the near future.
Autocomplete in Silverlight
I’ve written a simple class to allow adding autocomplete to a TextBox. An example of how to use it is:
In the XAML file:
<TextBox x:Name="uiText" Width="100" Height="30"
manas:Autocomplete.Suggest="DoSuggest" />
In the class file:
// The texts we want to suggest
private string[] options = new string[]
{
"Al", "Amiko", "Angla", "Anglujo", "Ankaux", "Antaux", "Atomo", "Auxto",
"Bebo", "Bela", "Birdo",
}
// The method we have to implement to offer suggestions
public void DoSuggest(string text, SuggestCallback callback)
{
// Don't suggest if there's no text
if (text.Length == 0)
{
callback(null);
return;
}
var result = new List();
// See which options have as a prefix the text entered by the user
foreach (var option in options)
{
if (option.StartsWith(text, StringComparison.InvariantCultureIgnoreCase))
{
result.Add(new Suggestion() { DisplayString = option,
ReplaceString = option });
}
}
callback(result.ToArray());
}
As in a previous post, I use the technique to specify an action to happen in the XAML, and it’s implementation in the class file, just like an event handler.
Of course, instead of using an hardcoded options array, these could be requested in the DoSuggest method to a web service, or requested from another class.
The suggestions are shown in an unstyled ListBox, but it should be easy to style, and even to improve the code to support icons in the suggestions, or any other control.
For this to work, the RootVisual of your application must be a Canvas, since otherwise you can’t place arbitrary floating elements on top of it.
Here’s the full code in case someone finds it useful.
Embedding YouTube videos in Silverlight
There’s no straight way of embedding YouTube videos in Silverlight. What you can do, however, is to create a floating div over the Silverlight plugin, whose content will be the YouTube video control. For this purpose, I wrote a simple class to make it easier to do this.
The usage is simple:
// ZCcedd9EfHI is the id of the video to show
YouTubePlayer player = new YouTubePlayer("ZCcedd9EfHI")
{
Top = 100,
Left = 200,
Width = 400,
Height = 400
};
player.Embed();
// And, once you want to remove the video from the page...
player.Dispose();
That’s it. Of course, you’ll have to compute the Top, Left, Width and Height values if you want to center the video inside a particular Silverlight control. You can do this computation in the Loaded event of that control.
And the best thing is, you can save a reference to the YouTubePlayer instance and, in case the Silverlight plugin is resized or moved, changing the Top, Left, Width and Height properties will automatically execute javascript code to move/resize the player.
Here’s the full code in case someone finds it useful.
Adding double click support in Silverlight
Silverlight Beta 2 doesn’t support double click, but since I needed it, I implemented it. I’ve created a class named Mouse. You create a Mouse instance that wraps an UIElement. The instance attaches itself to the MouseLeftDownButton and, using a timer, it allows you to recieve events when double click is performed.
Actually, you can detect as many clicks as you wish: the event arguments include the number of clicks performed by the user.
But I don’t want to attach to mouse events in code. I want to do it in XAML, like with MouseLeftButtonDown or Click. But, unfortunately, you can’t use attached properties whose type is an event handler. If you do that, you get an ugly exception.
“What a pity”, I thought, “now I need to remove some of my MouseLeftButtonDown events and replace them by code that creates Mouse instances and then attaching to Mouse events programatically”. But before doing that, I decided to give it another shot. What if I created an attached property whose type is string, and then at runtime I searched the method and invoke it?
The problem with that approach is that the method won’t be declared in the object where you are attaching the event, but probably in some parent control. For example:
<UserControl> <Rectangle manas:Mouse.Click="SomeMethod" /> </UserControl>
SomeMethod is probably declared in our custom UserControl, not in Rectangle. But that poses no problem at all: just go up in the visual hierarchy throught the Parent property until we find a class that declares SomeMethod with the signature of our interest.
But, alas, at the time attached properties are processed by the XAML processor, the object in question is not yet in the visual hierarchy: it doesn’t have a parent. That’s no problem at all: we attach to the Loaded event and do the lookup in that moment, and we are guaranted that we can reach the parent we are interested in.
Once I did that I was really amazed that it worked!
Then, I refactored the code so I could use that trick to support other custom event handlers in XAML as well. Finally, changing the old event handlers to start firing at double clicks instead of single clicks was a matter of seconds.
Here’s the full code in case someone finds it useful.