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.

image

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;

image

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>>

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DotNetKicks
  • DZone
  • Live
  • Reddit
  • TwitThis
  • email
  • Slashdot
  • StumbleUpon

You may also be interested with:

  1. Real singleton approach in WPF application
  2. INotifyPropertyChanged auto wiring or how to get rid of redundant code

9 Responses to “FindResource replacement and how to change control style more then once in Silverlight 2.0 application”

  1. Anatoly Says:

    Thank you

  2. Brandon Truong Says:

    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

  3. richard Says:

    I met the same problem, why cann’t get the exact property from the setter object, i cann’t understand why…

  4. Neal Gabriel Says:

    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 ?

  5. Setter Helpers goings on » Blog Archive » ’setter helper’ on the web Says:

    Pingback from  Setter Helpers goings on  &raquo; Blog Archive   &raquo; &#8217;setter helper&#8217; on the web

  6. Setter Helpers goings on » Blog Archive » What others have been saying about setter helper Says:

    Pingback from  Setter Helpers goings on  &raquo; Blog Archive   &raquo; What others have been saying about setter helper

  7. Setter Helpers goings on » Blog Archive » Quick Roundup Says:

    Pingback from  Setter Helpers goings on  &raquo; Blog Archive   &raquo; Quick Roundup

  8. Setter Helpers goings on » Blog Archive » Quick scan of the net - setter helper Says:

    Pingback from  Setter Helpers goings on  &raquo; Blog Archive   &raquo; Quick scan of the net – setter helper

  9. Remodeling Contractors Palatine Says:

    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!

Leave a Reply

Recommended

 


Sponsor


Partners

WPF Disciples
Dreamhost
Code Project
Switched to Better Place

Together