Silverlight
Resource Dictionaries

A resource dictionary is a concept supported by the ResourceDictionary class. A resource dictionary is a keyed dictionary of objects that can be used both in XAML and in code. XAML is the most common usage, particularly for initially defining objects in a resource dictionary. Resource dictionaries can exist at several positions in an application structure, including as immediate (page) resources, application resources (as part of the Application object) or as XAML files that are kept separate in the application project structure, for later run-time use or use as merged dictionaries. Resource dictionaries commonly support two major Silverlight scenarios: defining templates for controls (as part of styles), and defining storyboards for animated properties.

This topic contains the following sections.

ResourceDictionary for JavaScript API

ResourceDictionary can also be accessed by the JavaScript API for limited scenarios. This topic does not cover those scenarios. See ResourceDictionary.

Objects For ResourceDictionary Usage

Not all classes/objects are suitable for ResourceDictionary usage in Silverlight. In order for an object to be defined in and accessed from a ResourceDictionary, the object must be able to be shared. This is a requirement because ultimately when the object tree for an application is constructed and used at run time, objects cannot exist at multiple locations in the tree without either a sharing mechanism or an indirection mechanism such as a reference. An object deriving from UIElement type is inherently not shareable, unless it is generated from a control template.

Silverlight ResourceDictionary usages support the following for shareable usage:

  • Styles and templates.

  • Brushes and colors.

  • Animation types including storyboards.

  • Transforms.

  • Matrix, Matrix3D, and Point

  • Certain other structures that have settable and constructible properties, such as Thickness and CornerRadius (however, these often require an initialization text usage in XAML in order to declare useful values; see XAML Usage sections for specific structures for more information).

  • Custom types defined in your backing code, then instantiated in XAML as a resource, such as converters for resources.

  • Strings and basic numeric values such as double and int. Note that object element usage in XAML for these system types requires that you map the System namespace and mscorlib assembly where the primitives are structure-defined. The syntax for this is xmlns:sys="clr-namespace:System;assembly=mscorlib". For more information on XAML namespace mapping, see Silverlight XAML Namespaces, and Mapping XAML Namespaces as Prefixes.

Keys and Resources

The items within a ResourceDictionary must each have a key defined. In XAML, you assign the key by providing a value for the x:Key attribute on the object element that is added as ResourceDictionary content. In the Silverlight implementation of the resource dictionary concept, a ResourceDictionary can have x:Name instead of or in addition to an x:Key. If x:Key is not specified, x:Name is used as the key. x:Name / x:Key substitution supports a legacy resource dictionary usage that some applications might still be using.

NoteNote:

Some tools or development environments may give warnings about XAML that contains a ResourceDictionary that has items with x:Name but no x:Key. However, the x:Name / x:Key substitution will be valid for run-time XAML parsing.

If you intend to use keyed resources from XAML markup, you generally map the XAML namespace for the XAML language itself, through an xmlns declaration. This is usually necessary because x:Name and x:Key are defined by the XAML-intrinsics XAML namespace.

NoteNote:

The Silverlight documentation assumes the typical mapping prefix of x: for the XAML intrinsics, therefore references to "Key" in the documentation are typically in the form x:Key, with the assumed x prefix appended. Also, it is typical to map both the default Silverlight namespace and the XAML intrinsics XAML namespace at the root element level.

Resources in a Silverlight ResourceDictionary must use strings for their key names. See XamlName Grammar for string value restrictions on key names. The value used for key names in Silverlight must conform to this grammar.

If you include an item that does not have a usable key in a resource dictionary, a parser exception occurs. If you duplicate a key, a parser exception occurs. In general, if there are problems with keys, with object elements that cannot be created, or with resource lookup, the problems are not detected during code compilation, and are only reported as exceptions when Silverlight attempts to load the XAML at run time.

Immediate and Application Resources

There are two properties that take values of type ResourceDictionary: FrameworkElement..::.Resources, and Application..::.Resources. FrameworkElement..::.Resources provides immediate resources. In XAML, you can reference the keyed resources from FrameworkElement..::.Resources from any element that is connected to the same object tree as the resources exist within. Generally, you define the FrameworkElement..::.Resources value on the root element of a XAML page, and generally for a user application the root element for UI pages is UserControl. Therefore the common usage is to define all immediate resources that might be used by a page as elements within UserControl.Resources.

Application..::.Resources provides application-scoped resources. The resources that are defined by Application..::.Resources are available no matter what page is loaded as the current RootVisual of the application. This might be important if you are loading different possible pages into the RootVisual, and want a way to avoid duplicating the same resources in each possible page. Also, if you are writing values into a resource dictionary at run time, this provides a location where those resources can persist for the application lifetime.

NoteNote:

Do not confuse the concepts related to ResourceDictionary with the Resources build action, .resx files, and other "resources" that are discussed in the context of how you might structure the project that produces an application in MSBUILD or a development environment such as Visual Studio. Although the concept of resources for build actions and application structure can overlap with ResourceDictionary usages, the ResourceDictionary can generally be thought of as providing a self-contained resources system that incorporates XAML as its primary definition format.

Referencing Resources from XAML

In XAML, you reference an existing resource by using the StaticResource markup extension. To use the markup extension, you always reference the property you are setting through an attribute usage. For instance, to set the value of the Background property of a Button to be a resource, you would write something similar to the following XAML:

<!--item in a ResourceDictionary-->
<LinearGradientBrush x:Key="fadeBrush">
  <GradientStop Color="Red" Offset="0"/>
  <GradientStop Color="Gray" Offset="1"/>
</LinearGradientBrush>
<!--XAML that defines the actual UI-->
<Button Background="{StaticResource fadeBrush}" .../>

You use attribute syntax for a resource reference even if the property you are setting normally takes an object, and thus would require a property element usage in XAML if you were defining the setting object inline rather than as a resource. For instance, the following is an equivalent property element usage, if the LinearGradientBrush is defined inline:

<Button>
  <Button.Background>
    <LinearGradientBrush>
      <GradientStop Color="Red" Offset="0"/>
      <GradientStop Color="Gray" Offset="1"/>
    </LinearGradientBrush>
  </Button.Background>
</Button>
NoteNote:

You cannot explicitly use a property element usage surrounding StaticResource as object element content. In Silverlight the StaticResource markup extension only supports usage as an attribute value (not as an object element).

Lookup Behavior for StaticResource

The lookup behavior for a StaticResource is that the markup compile pass for XAML will first check whether the object where the actual usage is applied is capable of holding a FrameworkElement..::.Resources value. If so, that ResourceDictionary is checked for an item with that key. This level of lookup is seldom relevant, because you usually do not define then reference a resource on the same object. More relevant is what happens next: the lookup checks the next object tree parent for FrameworkElement..::.Resources and if the property exists there, checks for the key. This continues until the root element of the XAML is reached. Both to take advantage of this behavior and also as a matter of markup style, it is typical to define all the immediate resources at the root level of a page.

If the requested resource is not found in the immediate resources, then the next lookup step is to check Application..::.Resources.

If after this sequence the requested key is still not found, a parser exception occurs.

Based on this lookup behavior, it is possible to deliberately define multiple resources that have the same string value as the key, so long as each such resource is defined at a different element level where there is a FrameworkElement..::.Resources property to maintain key uniqueness. Only the first such object retrieved is used for the StaticResource. You could use this behavior to retrieve the same StaticResource key at various levels of the object tree yet obtain different results.

Merged Resource Dictionaries

As of Silverlight 3, Silverlight supports merged resource dictionaries. A merged resource dictionary enables you to declare the contents of a resource dictionary by referencing an external file. Also, merged resource dictionaries modify two of the characteristics of resource dictionaries: the lookup sequence, and key uniqueness requirements.

To declare a merged resource dictionary, you add a property element for the MergedDictionaries property to an existing ResourceDictionary location (typically FrameworkElement..::.Resources but sometimes Application..::.Resources). You must explicitly declare ResourceDictionary as an object element in order to use a property element within it. The existing ResourceDictionary may have other keyed resources as well as the MergedDictionaries property element. The content of MergedDictionaries is another ResourceDictionary declared as an object element. But this ResourceDictionary should not have further keyed resources as its own content, and it should declare only one attribute: Source. You can specify more than one ResourceDictionary within MergedDictionaries.

For example, the following XAML defines a ResourceDictionary with one keyed resource, as well as a MergedDictionaries collection that references two different resource dictionaries by URI:

<Grid>
  <Grid.Resources>
    <ResourceDictionary>
      <SolidColorBrush Color="#d0157820" x:Key="muddyBrush"/>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/rd1.xaml">
        <ResourceDictionary Source="/rd2.xaml">
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Grid.Resources>
....
<Grid>

In terms of the lookup sequence, a MergedDictionaries dictionary is checked only after checking all the keyed resources of the ResourceDictionary that declared MergedDictionaries. Then, each of the dictionaries within MergedDictionaries is checked, in the inverse of the order that they are declared within the MergedDictionaries property. In other words, the retrieval logic from within the collection of merged resource dictionaries is last in, first out.

Within the scope of the ResourceDictionary, the dictionaries are checked for key uniqueness. However, that scope does not extend across MergedDictionaries boundaries. For instance, you could define the same string key of muddyBrush for different resources if you declared the key once in the outer ResourceDictionary, and then again within any of the resource dictionaries that the same ResourceDictionary references by source as merged resource dictionaries. Within MergedDictionaries , if the key is found in the primary resource dictionary, the lookup stops there. Otherwise, each subsequently declared dictionary in MergedDictionaries is checked, with the last added merged dictionary checked first. If this also fails, then lookup falls through to the next FrameworkElement..::.Resources scope up toward the XAML root of the page, and thence to Application..::.Resources.

You can use the combination of the lookup sequence and lack of unique key enforcement across merged dictionary scopes to create a fallback sequence for resources. For instance, you might store user preferences for a particular brush color in the last merged resource dictionary in the sequence. But if no user preferences exist yet, you could define that same keyed resource in the preceding merged resource dictionary, and it could serve as the fallback.

Forward References Within a ResourceDictionary

Static resource references from within any given resource dictionary must reference a resource that has already been defined lexically before the resource reference. Forward references cannot be resolved by a static resource reference. For this reason, if you use static resource references, you must design your resource dictionary structure such that resources intended for further by-resource use are defined at or near the beginning of each respective resource dictionary.

References Between Application and Immediate Resources

Resources defined for the application cannot make references to immediate resources. This is equivalent to attempting a forward reference, because the application resources are actually processed first. However, any immediate resource can make a reference to an application resource, and this can be a useful technique for avoiding forward references.

Resource Dictionaries and XamlReader.Load

You can use a ResourceDictionary as either the root or a part of the XAML input for XamlReader..::.Load. You can also include StaticResource references in that XAML, so long as all such references are entirely self-contained in the XAML. XamlReader..::.Load parses the XAML in a context that is not aware of any other ResourceDictionary objects, not even Application..::.Resources.

StaticResource in Templates

Any StaticResource in a template is evaluated in the context of where the template is defined rather than where the template is applied. Usually this means that a StaticResource reference in a template must come from other items defined lexically previous from it in the same ResourceDictionary or from Application..::.Resources.

Referencing Resources from Code

In code, you can reference a resource by using the indexer (Item). In this indexer case the indexer uses the key, not an integer index. Usually a prerequisite is to retrieve a specific ResourceDictionary, either an immediate ResourceDictionary somewhere in the object tree by getting FrameworkElement..::.Resources, or the application ResourceDictionary by calling Application..::.Current, then Application..::.Resources.

NoteNote:

Silverlight does not implement the FindResource method that exists in the WPF framework.

Run-Time Usages

You can declare a resource dictionary as a discrete XAML file, and load it at run time with Load and load-from-package APIs from application services. In this case, ResourceDictionary is declared as an object element, serving as the root element of the XAML. You must map the appropriate XML namespaces (default for Silverlight and x: for XAML) onto the ResourceDictionary element if you plan to use it as the root element. Then you can add object elements for items that define the resources, each with a key. However, if this ResourceDictionary is intended to provide resources called by StaticResource in XAML, you must attach the ResourceDictionary to an existing Resources property so that it participates in the lookup sequence (for instance you could use Startup to set Application..::.Resources).

Another possible run-time usage is to add items to a ResourceDictionary by calling Add. You could add to either immediate resources or application resources. At run-time, there is little that distinguishes a ResourceDictionary versus a dictionary you could have created yourself, except that a ResourceDictionary is often populated from the initial XAML, and ResourceDictionary is convenient because you can obtain a ResourceDictionary from existing FrameworkElement..::.Resources / Application..::.Resources properties.

The run-time Add call requires a key, which satisfies the requirement that each item in a ResourceDictionary has a key. For anything that is added to a ResourceDictionary at run-time you will be unable to provide a value for x:Name that is accessible to the XAML namescope of the main object tree, because x:Name and the equivalent Name are both only settable from XAML. Although you could call XamlReader..::.Load first to load XAML that included internal x:Name / Name attributes, and then add the created object tree as a resource, this does not solve the names-in-main-namescope problem because Load always creates a discrete XAML namescope. The restriction on setting Name at runtime is generally not a problem, but could become an issue if you are trying to use storyboards to animate properties on objects added to resources at run-time, and need a TargetName. For these cases you can still use a true PropertyPath in order to indirectly target the property by starting the property path from some object in the tree that does have an available name in the main XAML namescope.

Reusing Resources

In some cases you can assign a value that is defined in a resource to more than one object.

  • Templates and styles defined in a ResourceDictionary can always be reused, because the mechanisms that apply templates or set styled properties are designed for that purpose.

  • Value types, such as strings, can be used more than once. Any value type that is reused is just copied. (Including strings and other System defined value types in object element XAML usage such that they can be keyed requires mapping an XML namespace with prefix for System and mscorlib; see Silverlight XAML Namespaces, and Mapping XAML Namespaces as Prefixes).

  • The resource system also supports built-in sharing of certain objects if they are used more than once. These objects are:

Objects that go in a visual tree, such as any UIElement, generally cannot be retrieved from a resource dictionary more than once, and attempting to do so will generate a parser exception if referenced by StaticResource Markup Extension. Attempting to reuse object definitions is a scenario for templates, not a resource dictionary per se. Another possible approach for object definition reuse is to use XAML input for XamlReader..::.Load but call the method multiple times on the same XAML input to return more than one object.

generic.xaml

generic.xaml is a special implementation technique used for controls that generally incorporates a ResourceDictionary. Inside generic.xaml only, both Name / x:Name and x:Key are optional on Style elements if the TargetType attribute is specified. Another aspect that is unique to generic.xaml is that the {x:Type} markup extension is supported when setting TargetType for styles and template resources. This is to support compatibility and migration with WPF, where the {x:Type} markup extension is supported globally. Outside of generic.xaml, the Silverlight XAML parser uses implicit conversion for any property of type Type, and explicit use of {x:Type} is not supported and generates a parser error. For more information on generic.xaml, see Creating a New Control by Creating a ControlTemplate.

ResourceDictionary Implementation Differences from WPF

  • As noted in the "Keys and Resources" section, a Silverlight ResourceDictionary can have x:Name instead of or in addition to an x:Key. WPF always requires x:Key except for certain explicit key cases related to styles and templates.

  • Silverlight does not support a FindResource API (not strictly a ResourceDictionary issue, but relevant to the overall usage).

  • Silverlight does not support {DynamicResource}. If you are migrating XAML from WPF, you can convert these to {StaticResource} and define them in a ResourceDictionary, or you must otherwise replace the references. Again, not strictly a ResourceDictionary issue.

  • In WPF, the base type for templates (FrameworkTemplate) also has a Resources property. The Silverlight version of FrameworkTemplate does not have a Resources property.

  • Silverlight XAML does not support x:Shared or x:Static.

  • Silverlight has a smaller range of shareable types than WPF. Some types that are shareable in WPF, such as Geometry derived types, are not shareable in Silverlight.

  • Silverlight does not support referencing a UIElement as a resource (excepting applied templates, which is a different concept). WPF permits referencing a UIElement as a resource, and using a ResourceDictionary as a refactoring technique in WPF XAML is a valid scenario so long as you only insert that UIElement into the object tree once.

Resource Dictionaries and Localization

Resource dictionaries may contain strings that are intended to be localized, either as sys:String objects or as string values for attributes of specific objects. If you use a purely ResourceDictionary-based technique for localization of UI defined in XAML, it generally requires that each locale requires a separate compile. You thus produce one XAP per locale for your application and handle the deployment distribution issues of these XAML files by specifying Source differently per-locale at the HTML or Silverlight initialization level.

There is an alternative recommended technique for dealing with localizable UI strings from XAML in your Silverlight-based application, which integrates well with the existing Visual Studio resources infrastructure and the project templates for Silverlight. This technique relies on creating a custom resources class for localizable strings, combined with the Silverlight data binding and resource dictionary features. For more information, see "Making XAML Localizable" section of Localizing Silverlight-based Applications.

See Also

Reference

Concepts

Tags :


Community Content

Wolf Schmidt - MSFT
Silverlight 2 does not support everything as shareable resources.

See this thread on the forums for details: http://silverlight.net/forums/p/49639/131671.aspx

Tags :

Wolf Schmidt - MSFT
More about shareable resources

Specifically: the types that can successfully be defined and then referenced by key within a ResourceDictionary in Silverlight is somewhat finite.

The general idea with defining something in a ResourceDictionary is that you intend to reference an item more than once. This in turn implies that if you DO reference the item more than once, it has to be shareable, and thus any type that you put as a keyed ResourceDictionary item needs to have a technique in the background that can share/clone it. If the type in question cannot be shared, the ResourceDictionary construction will be flawed, and you do not discover that until you try to reference the object (either via StaticResource or even by index within the RD in code). What you'll find in these cases is that the resource is "stuck" within the ResourceDictionary and cannot be used elsewhere.

Tags :

Page view tracker