Here’s an XBAP that dynamically grabs the “styles” available to it from site of origin.
Note: By “styles,” I mean distinct look & feels defined in different ResourceDictionary files, not simply the <Style> class. You could also call these “themes.”
The resulting proof of concept app looks like this:
The app contains a button whose look is determined by the ”style” selected in a combobox. The list of available “styles” (xml file) and the associated ResourceDictionaries (xaml files) are kept up at the site of origin. Right now, the “styles” available to the app are:
- Fish “style” (thanks to Fil Fortes)
- Shiny “style” (thanks to Robert Ingebretsen)
- KevinButton “style (thanks to Robert Ingebretsen and Kevin Moore)
You can grab the xbap code here. Or you can run the RC1 XBAP.
Implementation
The list of available styles are kept in Styles.xaml up at site of origin:
<Styles>
<Style
Name=”fish”
File=”pack://siteoforigin:,,,/Styles/Fish.xaml”/>
<Style
Name=”shiny”
File=”pack://siteoforigin:,,,/Styles/Shiny.xaml”/>
<Style
Name=”kevinbutton”
File=”pack://siteoforigin:,,,/Styles/KevinButton.xaml”/>
</Styles>
In my Page1.xaml, I define a XmlDataProvider for that xml file, providing an XPath query that returns a collection of Style elements. Note that I’m using the pack:// syntax to refer to the site of origin xml file. Ashish Shetty has a great post about the pack:// concept.
<Page.Resources>
<ResourceDictionary>
<XmlDataProvider
Source=”pack://siteoforigin:,,,/Styles.xml”
x:Key=”XmlStyles”
XPath=”/Styles/Style”/>
</ResourceDictionary>
</Page.Resources>
Next, I bind my ComboBox to that XmlDataProvider. I can use the DisplayMemberPath to easily set how visualize the items. In this case, I want to show the value of the Name attribute.
<ComboBox x:Name="StyleComboBox"
SelectionChanged=”OnSelectionChanged”
ItemsSource=”{Binding Source={StaticResource XmlStyles}}”
DisplayMemberPath=”@Name”
FontFamily=”Calibri, Verdana”
Width=”90″
/>
Because the Resources property is not a DependencyProperty, I cannot bind to it. Instead, I write a little bit of code to swap the Grid’s resource dictionary on selection changed:
void OnSelectionChanged(object sender, RoutedEventArgs e)
{
XmlElement styleElement= (XmlElement) this.StyleComboBox.SelectedItem;
String styleFile = (String) styleElement.Attributes["File"].Value;
ResourceDictionary dictionary = new ResourceDictionary();
dictionary.Source = new Uri(styleFile, UriKind.RelativeOrAbsolute);
this.Grid.Resources = dictionary;
}
The overall app architecture looks something like this:
