FindResource replacement and how to change control style more then once in Silverlight 2.0 application
As deeper we’re digging in Silverlight 2.0, we finding more and more WPF things and we’re really missing in Silverlight. One of such things is FindResources.
In WPF I had Visual and Logical tree, so I was able to travel the tree to find resource I need. Let’s see an example of the application. We have one resource defined in App level
<Application.Resources>
<Style TargetType=”Button” x:Key=”green”>
<Setter Property=”Background” Value=”Green”/>
</Style>
</Application.Resources>
Another resources are defined in different levels of Page
<UserControl.Resources>
<Style TargetType=”Button” x:Name=”red”>
<Setter Property=”Background” Value=”Red”/>
</Style>
</UserControl.Resources>
<Grid x:Name=”LayoutRoot” Background=”White”>
<Grid.Resources>
<Style TargetType=”Button” x:Name=”blue”>
<Setter Property=”Background” Value=”Blue”/>
</Style>
</Grid.Resources>
<Button Content=”Click me” Click=”Button_Click”>
<Button.Resources>
<Style TargetType=”Button” x:Name=”yellow”>
<Setter Property=”Background” Value=”#FFFFFF00″/>
</Style>
</Button.Resources>
</Button>
</Grid>
Now I want to call FindResource(“red”) and have my style ready for apply. I should not thing a lot about where the resource exists. There is no such method in Silverlight. If so, let’s see what we have. Looking in debugger I can find all my resources as members of the page.
But how to get them out? In Silverlight FrameworkElement, we have handy method named FindName. That’s exactly what we need. But how to get Application resources? Simple. Just look into it’s collection. Now, I can write small method, that help me to find resources in any level of Silverlight application.
public static object FindResource(string name)
{
if (App.Current.Resources.Contains(name))
{
return App.Current.Resources[name];
}
else
{
FrameworkElement root = App.Current.RootVisual as FrameworkElement;
return root.FindResource(name);
}
}
internal static object FindResource(this FrameworkElement root, string name)
{
if (root != null && root.Resources.Contains(name))
{
return root.Resources[name];
}
else
{
try
{
return root.FindName(name);
}
catch { }
}return null;
Well now we can find all our resources. Let’s apply it to elements
Style s = (Style)Helper.FindResource(“red”);
b.Style=s;
It works perfect. Let’s take another one
Style s = (Style)Helper.FindResource(“blue”);
b.Style = s;
What is it? “Catastrophic failure (Exception from HRESULT: 0×8000FFFF (E_UNEXPECTED))”. Why this happens only after applying second style? Let’s look into MSDN: “Styles are write-once in Silverlight. You can set a style to override a built-in default style, but attempting to set the same style again will result in an exception.”
What to do? We just have to write our own multi-use styling engine. First of all, we should get all setters of the style
foreach (Setter setter in value.Setters)
Then check target type and set values of setters to appropriate properties.
Type targetType = parent.GetValue(setter.Property).GetType();
parent.SetValue(setter.Property, setter.Value);
Another exception. That’s the mess? All values are strings. I need real values and I have no parsers. Fortunately, we have handy .NET method Convert.ChangeType. Let’s use it. Exception. Let’s check if the type is IConvertible (such as int, double, etc)
if(targetType is IConvertible)
{
return Convert.ChangeType(source, targetType, CultureInfo.InvariantCulture);
}
No exception, but also no result. We need SolidColorBrush and we have only Color name, which is string. How to convert such string into Color instance and then into SolidColorBrush? The answer is reflection. We should write our own FromString converter. First of all let’s capitalize the string
static string Capitalize(this string str)
{
if (str.Length > 0)
{
return string.Concat(str.Substring(0, 1).ToUpper(), str.Substring(1, str.Length – 1));
}
return str;
}
Then check whether I have static member with the same name in Colors class (not by hand of cause)
MemberInfo[] infos = typeof(Colors).GetMember(color.Capitalize());
If I have, let’s invoke it
if (infos.Length > 0)
{
return (Color)typeof(Colors).InvokeMember(color.Capitalize(), BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty, null, null, null);
}
Well done. Now we can use strings which have names of colors and convert them into real color. But what to do with not “well known colors”? Parse it
else if (color.IndexOf(‘#’) == 0)
{
return Color.FromArgb(
byte.Parse(color.Substring(1, 2), NumberStyles.HexNumber),
byte.Parse(color.Substring(3, 2), NumberStyles.HexNumber),
byte.Parse(color.Substring(5, 2), NumberStyles.HexNumber),
byte.Parse(color.Substring(7, 2), NumberStyles.HexNumber));
}
We done. Just write another attached method and use in in our converter
internal static Color ParseKnownColor(string color)
{
MemberInfo[] infos = typeof(Colors).GetMember(color.Capitalize());
if (infos.Length > 0)
{
return (Color)typeof(Colors).InvokeMember(color.Capitalize(), BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty, null, null, null);
}
else if (color.IndexOf(‘#’) == 0)
{
return Color.FromArgb(
byte.Parse(color.Substring(1, 2), NumberStyles.HexNumber),
byte.Parse(color.Substring(3, 2), NumberStyles.HexNumber),
byte.Parse(color.Substring(5, 2), NumberStyles.HexNumber),
byte.Parse(color.Substring(7, 2), NumberStyles.HexNumber));
}
return Colors.White;
}
……else if(targetType == typeof(SolidColorBrush))
{
return new SolidColorBrush(ParseKnownColor(source));
}
Now you turn to continue with string to object convention for your own need. Starting today you know how to do it.
Here the result
Have a nice day and be good people
Source code for this article>>
You may also be interested with:
- Real singleton approach in WPF application
- INotifyPropertyChanged auto wiring or how to get rid of redundant code
March 25th, 2008 · Comments (9)
9 Responses to “FindResource replacement and how to change control style more then once in Silverlight 2.0 application”
Leave a Reply
Discover other tags
My tools
- .NET Framework Detector
- Duplicate images finder
- Exchange Security Policy for Windows Mobile Devices Fix
- Gas Price Windows Vista SideBar gadget
- Israel Traffic Information Windows Vista SideBar gadget
- Localization fix for SAP ES Explorer for Visual Studio
- LocTester
- RTL and LTR in Windows Live Writer
- Silverlight controls library
- Snipping tool integration plugin for WLW
- USB FM receiver library
- Vista Battery Saver
- WebCam control for WPF
- Windows Live SkyDrive attachment for Windows Live Writer
- Wireless Migrator
- WPF Virtual Keyboard




January 1st, 2009 at 12:42 am
Thank you
January 1st, 2009 at 12:42 am
Hi,
i have met the same problem as well. The Preporty is always NULL. Is it because of "Styles are write-once in Silverlight".
Can any one help please?
Thanks
January 1st, 2009 at 12:42 am
I met the same problem, why cann’t get the exact property from the setter object, i cann’t understand why…
January 1st, 2009 at 12:42 am
Hi,
Thank you for the code you have developed. When I run the sample application, I am getting an error in the Helper.cs File. [ApplyStyle] function.
In the following line
parent.GetValue(setter.Property).GetType();
The reason behind this is
setter.property is null.
How can I solve it ?
January 1st, 2009 at 12:42 am
Pingback from Setter Helpers goings on » Blog Archive » ’setter helper’ on the web
January 1st, 2009 at 12:42 am
Pingback from Setter Helpers goings on » Blog Archive » What others have been saying about setter helper
January 1st, 2009 at 12:42 am
Pingback from Setter Helpers goings on » Blog Archive » Quick Roundup
January 1st, 2009 at 12:42 am
Pingback from Setter Helpers goings on » Blog Archive » Quick scan of the net – setter helper
October 23rd, 2009 at 3:38 pm
I think that when you are remodeling you want to be around the project as much as possible!
If you can do a lot of it yourself that helps on quality and money.
Usually the best job done is the one you do because you know how you want it done and you
want it done nicely because you’ll be seeing it everyday – the contracter wont!
Thanks for this blog it had a lot of great information!