• Blog
  • Info Support
  • Career
  • Training
  • International Group
  • Info Support
  • Blog
  • Career
  • Training
  • International Group
  • Search
logo InfoSupport
  • Latest blogs
  • Popular blogs
  • Experts
      • All
      • Bloggers
      • Speakers
  • Meet us
  • About us
    • nl
    • en
    • .NET
    • 3D printing
    • Advanced Analytics
    • Agile
    • Akka
    • Alexa
    • Algorithms
    • Api's
    • Architectuur
    • Artificial Intelligence
    • ATDD
    • Augmented Reality
    • AWS
    • Azure
    • Big Data
    • Blockchain
    • Business Intelligence
    • Chatbots
    • Cloud
    • Code Combat
    • Cognitive Services
    • Communicatie
    • Containers
    • Continuous Delivery
    • CQRS
    • Cyber Security
    • Dapr
    • Data
    • Data & Analystics
    • Data Science
    • Data Warehousing
    • Databricks
    • DataOps
    • Developers life
    • DevOps
    • Digital Days
    • Digital Twin
    • Docker
    • eHealth
    • Enterprise Architecture
    • Event Sourcing
    • Hacking
    • Infrastructure & Hosting
    • Innovatie
    • Integration
    • Internet of Things
    • Java
    • Machine Learning
    • Microservices
    • Microsoft
    • Microsoft Bot Framework
    • Microsoft Data Platform
    • Mobile Development
    • Mutation Testing
    • Open source
    • Pepper
    • Power BI
    • Privacy & Ethiek
    • Python
    • Quality Assistance & Test
    • Quality Assurance & Test
    • Requirements Management
    • Scala
    • Scratch
    • Security
    • SharePoint
    • Software Architecture
    • Software development
    • Software Factory
    • SQL Server
    • SSL
    • Start-up
    • Startup thinking
    • Stryker
    • Test Quality
    • Testing
    • TLS
    • TypeScript
    • Various
    • Web Development
    • Web-scale IT
    • Xamarin
    • All
    • Bloggers
    • Speakers
Home » Silverlight 3: Loading Merged Resource Dictionaries runtime
  • Silverlight 3: Loading Merged Resource Dictionaries runtime

    • By Alex van Beek
    • Various 13 years ago
    • Various 0 comments
    • Various Various
    Silverlight 3: Loading Merged Resource Dictionaries runtime

    To customize the look of our application in Silverlight 3, we organize everything “look related” in Styles and put those styles in ResourceDictionaries. Usually by adding those styles in XAML to the Resources property of the current user control. In Silverlight 2 we would get huge XAML files with huge ResourceDictionaries, because there wasn’t any way to put a ResourceDictionary in its own file. With Silverlight 3 and Merged Resource Dictionaries, we can remedy this problem by putting Styles in a ResourceDictionary which has it’s own .xaml file. That .xaml file needs to have a build action of “Content” or “Resource”. With both of these options the application needs to be recompiled every time you want to change the look of your application. With the solution provided below, you can change the look of your application by changing the .xaml file of the ResourceDictionary and just by pressing F5 (refresh) you will see the changes applied to your Silverlight application.

     

    The sample application

    Before we’re going to take a dive into the code, we’re first going to take a look at the example application:

       1: <UserControl x:Class="RuntimeStyles.MainPage"

       2:     >="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

       3:     >="http://schemas.microsoft.com/winfx/2006/xaml"

       4:     >="http://schemas.microsoft.com/expression/blend/2008" >="http://schemas.openxmlformats.org/markup-compatibility/2006" 

       5:     mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">

       6:   

       7:   <Grid x:Name="LayoutRoot">

       8:         <Grid.ColumnDefinitions>

       9:             <ColumnDefinition/>

      10:             <ColumnDefinition/>

      11:         </Grid.ColumnDefinitions>

      12:         <Ellipse Style="{StaticResource myEllipseStyle}" />

      13:         <Rectangle Style="{StaticResource myRectangleStyle}" Grid.Column="1"/>   

      14:   </Grid>

      15: </UserControl>

    Nothing too fancy here: A rectangle and an ellipse which both have their Style properties set. The interesting part is that both of the styles come out of different .xaml ResourceDictionaries, without merging those dictionaries in the XAML shown above. Below are both of the styles:

       1: <ResourceDictionary

       2:     >="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

       3:     >="http://schemas.microsoft.com/winfx/2006/xaml">

       4:     <Style x:Key="myRectangleStyle" TargetType="Rectangle">

       5:         <Setter Property="Fill">

       6:             <Setter.Value>

       7:                 <SolidColorBrush Color="Blue"/>

       8:             </Setter.Value>

       9:         </Setter>

      10:         <Setter Property="Stroke">

      11:             <Setter.Value>

      12:                 <SolidColorBrush Color="Red"/>

      13:             </Setter.Value>

      14:         </Setter>

      15:     </Style> 

      16: </ResourceDictionary>

       1: <ResourceDictionary

       2:     >="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

       3:     >="http://schemas.microsoft.com/winfx/2006/xaml">

       4:     <Style x:Key="myEllipseStyle" TargetType="Ellipse">

       5:         <Setter Property="Fill">

       6:             <Setter.Value>

       7:                 <SolidColorBrush Color="Red"/>

       8:             </Setter.Value>

       9:         </Setter>

      10:         <Setter Property="Stroke">

      11:             <Setter.Value>

      12:                 <SolidColorBrush Color="Blue"/>

      13:             </Setter.Value>

      14:         </Setter>

      15:     </Style> 

      16: </ResourceDictionary>

    Both of these styles are in their own .xaml files, relative to the location of the .xap file of my Silverlight application. They are not contained in my Silverlight project:

    image

    And a screen shot of the application:

    image

    The StyleLoader class

    It&rsquo;s good OO practice to give each class one responsibility,&nbsp; so I&rsquo;ve put the code to load the styles at runtime in its own class. This class is called “StyleLoader&rdquo; and the source is shown below:

       1: using System;

       2: using System.Net;

       3: using System.Windows;

       4: using System.Windows.Markup;

       5: using System.Collections.Generic;

       6: using System.Linq;

       7: namespace RuntimeStyles

       8: {

       9:     public class StyleLoader

      10:     {      

      11:         public event EventHandler AllStylesLoaded;

      12:         private List<ResourceDictionary> _allReadyLoaded;

      13:         private ResourceDictionary _toMergeWith;

      14:&nbsp; 

      15:         public void LoadStyles(ResourceDictionary toMergeWith, Uri xamlUri, params Uri[] xamlUris)

      16:         {

      17:             if (_allReadyLoaded != null)

      18:             {

      19:                 throw new InvalidOperationException("You have to wait before" +

      20:                 " the previous call has finished!");

      21:             }

      22:             _allReadyLoaded = new List<ResourceDictionary>(xamlUris.Length);

      23:             _toMergeWith = toMergeWith;

      24:&nbsp; 

      25:             DownloadStyle(xamlUri);

      26:             foreach (Uri downloadUri in xamlUris)

      27:             {

      28:                 DownloadStyle(downloadUri);

      29:             }

      30:         }

      31:&nbsp; 

      32:         public void LoadStyles(Uri xamlUri, params Uri[] xamlUris)

      33:         {

      34:             LoadStyles(Application.Current.Resources,xamlUri, xamlUris);

      35:         }

      36:&nbsp; 

      37:         private void DownloadStyle(Uri downloadUri)

      38:         {

      39:             WebClient wc = new WebClient();

      40:             wc.DownloadStringCompleted += ParseAndAddStyles;

      41:             wc.DownloadStringAsync(downloadUri);

      42:         }

      43:&nbsp; 

      44:        private void ParseAndAddStyles(object sender, DownloadStringCompletedEventArgs e)

      45:        {

      46:            if (e.Error == null)

      47:            {

      48:                ResourceDictionary loaded = null;

      49:                try

      50:                {

      51:                    loaded = XamlReader.Load(e.Result) as ResourceDictionary;

      52:                }

      53:                catch

      54:                {

      55:                    CleanUp();

      56:                    throw;

      57:                }

      58:                if (loaded != null)

      59:                {

      60:                    if (_allReadyLoaded.Count == _allReadyLoaded.Capacity)

      61:                    {

      62:                        //This was the last call to complete

      63:                        _toMergeWith.MergedDictionaries.Add(loaded);

      64:                        foreach (ResourceDictionary dic in _allReadyLoaded)

      65:                        {

      66:                            _toMergeWith.MergedDictionaries.Add(dic);

      67:                        }

      68:                        CleanUp();

      69:                        OnAllStylesLoaded(new EventArgs());

      70:                    }

      71:                    else

      72:                    {

      73:                        _allReadyLoaded.Add(loaded);

      74:                    }

      75:                }

      76:                else

      77:                {

      78:                    CleanUp();

      79:                    throw new InvalidOperationException("The loaded xaml was not a resource dictionary!");

      80:                }

      81:            }

      82:            else

      83:            {

      84:                CleanUp();

      85:                throw e.Error;

      86:            }

      87:        }

      88:&nbsp; 

      89:        private void CleanUp()

      90:        {

      91:            _toMergeWith = null;

      92:            _allReadyLoaded = null;

      93:        }

      94:&nbsp; 

      95:         protected virtual void OnAllStylesLoaded(EventArgs args)

      96:         {

      97:             EventHandler temp = AllStylesLoaded;

      98:             if (temp != null)

      99:             {

     100:                 temp(this, new EventArgs());

     101:             }

     102:         }

     103:&nbsp; 

     104:     }

     105: }

    I&rsquo;ll only cover the important parts:

    • Line 15 &ndash;30: This method is the heart of the class. It accepts a resource dictionary to put the loaded styles in and one or more uri&rsquo;s. These uri&rsquo;s are the locations of the .xaml file you wish to load. The method is called LoadStyles, but can actually be used to load any ResourceDictionary. The method calls the DownloadStyle() method for each uri it receives, effectively creating a WebClient object for every uri. This means that all external ResourceDictionaries are downloaded in parallel. I keep track of how how many calls still have to complete by using the_allReadyLoaded list. You can not call this method again until all WebClient objects have completed their calls.
    • Line 32-35: This is just a convenience overload of above method. If you don&rsquo;t want to supply a ResourceDictionary to load the styles in, the ResourceDictionary of the Application is used.
    • Line 44-87: This method is the completed event handler for the WebClient objects. Every time a WebClient call completes, the downloaded XAML string is parsed by using the XamlReader class and the resulting ResourceDictionary is added to the list of already loaded dictionaries. When the _allreadyLoaded list has used all of it&rsquo;s capacity, the last WebClient request has returned and all the loaded dictionaries are merged and the AllStylesLoaded event is fired. I&rsquo;m first gathering all the loaded dictionaries and then adding them in one go. This way, when one of the WebClient requests fail, I can leave the application in a consistent state with none of the resource dictionaries loaded. I thought about putting synchronization logic in this method, because all the WebClient calls are asynchronous, but the completed events of the different WebClient objects all fire on the UI thread. This means that the code in the ParseAndAddStyles method is executed by a single thread and no synchronization is needed.

    &nbsp;&nbsp;

    Using the StyleLoader class

    Below is the source of the MainPage file:

       1: using System;

       2: using System.Windows.Controls;

       3:&nbsp; 

       4: namespace RuntimeStyles

       5: {

       6:     public partial class MainPage : UserControl

       7:     {

       8:         public MainPage()

       9:         {

      10:             StyleLoader sl = new StyleLoader();

      11:             sl.AllStylesLoaded += new EventHandler(sl_AllStylesLoaded);

      12:             sl.LoadStyles(new Uri("Styles/MyEllipseStyles.xaml",UriKind.Relative),

      13:                 new Uri("Styles/MyRectangleStyles.xaml", UriKind.Relative));

      14:         }

      15:&nbsp; 

      16:         private void sl_AllStylesLoaded(object sender, EventArgs e)

      17:         {

      18:             InitializeComponent();

      19:         }

      20:&nbsp; 

      21:     }

      22: }

    The one thing that&rsquo;s really important is that the call to load the styles must happen before the InitializeComponent() call. This is very important because in the InitializeComponent() call all components execute their bindings. These will of course fail because no resource dictionaries have been loaded if InitializeComponent() is called before the StyleLoader raises it&rsquo;s AllStylesLoaded event. You can find the full application here. Go ahead and change some of the styles in the ResourceDictionary .xaml files in the web project. You only have to press F5 (refresh) and you will see your changes applied to your Silverlight application without recompiling.

    Share this

Alex van Beek

View profile

IT Training at Info Support

Which training fits you?

Consultancy

Consultancy

Related blogs

  • Video Conferencing en OBS Studio koppelen: online prese…

    Video Conferencing en OBS Studio koppelen: online prese… Maaike Brouwer - 2 years ago

  • Verantwoordelijkheid pakken in jouw eigen persoonlijke …

    Verantwoordelijkheid pakken in jouw eigen persoonlijke … Stephan Versteegh - 2 years ago

  • Tips voor als je gaat afstuderen

    Tips voor als je gaat afstuderen Bart Renders - 3 years ago

Data Discovery Channel

  • Explainable AI - Break open the blackbox

  • Toekomstvaste microservice data architecturen

  • Modern Data Platform

Nieuwsbrief

* verplichte velden

Contact

  • Head office NL
  • Kruisboog 42
  • 3905 TG Veenendaal
  • T +31 318 552020
  • Call
  • Mail
  • Directions
  • Head office BE
  • Generaal De Wittelaan 17
  • bus 30 2800 Mechelen
  • T +32 15 286370
  • Call
  • Mail
  • Directions

Follow us

  • Twitter
  • Facebook
  • Linkedin
  • Youtube

Newsletter

Sign in

Extra

  • Media Library
  • Disclaimer
  • Algemene voorwaarden
  • ISHBS Webmail
  • Extranet
Beheer cookie toestemming
Deze website maakt gebruik van Functionele en Analytische cookies voor website optimalisatie en statistieken.
Functioneel Always active
De technische opslag of toegang is strikt noodzakelijk voor het legitieme doel het gebruik mogelijk te maken van een specifieke dienst waarom de abonnee of gebruiker uitdrukkelijk heeft gevraagd, of met als enig doel de uitvoering van de transmissie van een communicatie over een elektronisch communicatienetwerk.
Voorkeuren
De technische opslag of toegang is noodzakelijk voor het legitieme doel voorkeuren op te slaan die niet door de abonnee of gebruiker zijn aangevraagd.
Statistieken
De technische opslag of toegang die uitsluitend voor statistische doeleinden wordt gebruikt. De technische opslag of toegang die uitsluitend wordt gebruikt voor anonieme statistische doeleinden. Zonder dagvaarding, vrijwillige naleving door uw Internet Service Provider, of aanvullende gegevens van een derde partij, kan informatie die alleen voor dit doel wordt opgeslagen of opgehaald gewoonlijk niet worden gebruikt om je te identificeren.
Marketing
De technische opslag of toegang is nodig om gebruikersprofielen op te stellen voor het verzenden van reclame, of om de gebruiker op een website of over verschillende websites te volgen voor soortgelijke marketingdoeleinden.
Manage options Manage services Manage vendors Read more about these purposes
Voorkeuren
{title} {title} {title}