Silverlight Tip: Enumerating embedded resources
Today I’ve got a “Call for Help” from one of Silverlight MVPs – Bill Reiss. The mail said:
“I would like to enumerate all items that were marked as Content or Resource in the main XAP file.
If I can’t do both I’d settle for one. Any sample code for this would be greatly appreciated.
Bill”
I decided to help with embedded resources, because I did something like this in WPF.
I’ve created sample application, which will display a list of resources in list box – from here it is very easy to use them by name. My sample will load the resource as image.
For application I’ve added 3 sample images and marked them “Resource” in properties:
The application UI:
XAML for sample:
<StackPanel x:Name="LayoutRoot" Background="White" Orientation="Vertical">
<StackPanel Orientation="Horizontal" Margin="5">
<Button Content="Embedded Resources" Padding="5" Margin="5" x:Name="btnEmbedded" Click="btnEmbedded_Click"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5">
<StackPanel Orientation="Vertical" Margin="5">
<TextBlock Text="Embedded Resources:" Margin="5,0"/>
<ListBox x:Name="lstEmbedded" SelectionChanged="lstEmbedded_SelectionChanged" Margin="5"/>
<Image x:Name="imgEmbedded" Stretch="Uniform" Width="150" Height="150" Margin="5,0"/>
</StackPanel>
</StackPanel>
</StackPanel
At code behind I have 2 event handler functions. First – to handle button click and get the resources.
First of all I have to open XAP file as a resource:
WebClient wc = new WebClient();
wc.OpenReadCompleted += (s, args) =>
{
if (args.Error == null)
{
//rest will be here
}
};
wc.OpenReadAsync(new Uri("SL_Resources_Test.xap", UriKind.RelativeOrAbsolute));
When the OpenRead completes, first I have to get the list of assembly parts in XAP using application manifest.
XmlReader reader = XmlReader.Create(Application.GetResourceStream(new StreamResourceInfo(args.Result, null),
new Uri("AppManifest.xaml", UriKind.Relative)).Stream);
AssemblyPartCollection parts = new AssemblyPartCollection();
if (reader.Read())
{
reader.ReadStartElement();
if (reader.ReadToNextSibling("Deployment.Parts"))
{
while (reader.ReadToFollowing("AssemblyPart"))
{
parts.Add(new AssemblyPart() { Source = reader.GetAttribute("Source") });
}
}
}
Now, when I have a list of all parts (DLLs which could have embedded resources) I will get resources from each one of the DLLs:
List<string> embeddedResources = new List<string>(); //Will use this list as source for ListBox later in code
foreach (var part in parts)
{
Assembly assy = part.Load(Application.GetResourceStream(new StreamResourceInfo(args.Result, null),
new Uri(part.Source, UriKind.Relative)).Stream); //Load current assembly
string[] resources = assy.GetManifestResourceNames(); //Get embedded resource names
foreach (var resource in resources)
{
ResourceManager rm = new ResourceManager(resource.Replace(".resources",""), assy); //All resources has “.resources” in the name – so I have to get rid of it
Stream DUMMY = rm.GetStream("app.xaml"); //Seems like some issue here, but without getting any real stream next statement doesn't work....
ResourceSet rs = rm.GetResourceSet(Thread.CurrentThread.CurrentUICulture, false, true);
//to get the actual values - create the table
//Dictionary<string, object> table = new Dictionary<string, object>();
IDictionaryEnumerator enumerator = rs.GetEnumerator();
while (enumerator.MoveNext())
{
embeddedResources.Add((string)enumerator.Key);
//It is also possible to get the value and key instead of just key
//object obj2 = enumerator.Value;
//table.Add((string)enumerator.Key, obj2);
}
}
}
lstEmbedded.ItemsSource = embeddedResources; //Use prepared list as a source for ListBox
Now my embedded resources enumerated.
Second part – use the resource by name when selection changed in the list box:
private void lstEmbedded_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Uri uri = new Uri(lstEmbedded.SelectedItem.ToString(), UriKind.RelativeOrAbsolute);
BitmapImage img = new BitmapImage(uri);
imgEmbedded.Source = img;
}
Running application:
Sample source here.
Stay tuned for more posts and news to come from PDC09.
See you at PDC09 and SDP!
Alex