What is a resource (in terms on .net)?
A resource is a noncode piece of an application or compnent like bitmaps, fonts, audio / video files, string tables.
WPF supports 2 different types of resources –
Binary Resource
Binary resources are what the rest of the .NET framework conciders as resources and in WPF apps they are traditional items like bitmaps. You might also be surprised to know that XAML is also stored as a binary resource behiend the scenes. Binary resources are packaged in three different ways:
- Embedded inside an assembly
- Loose files that are known to the application at complie time
- Loose files that are not known to the applcation to the compile time.
Now we can also categorize binary resources into Localizable (change depending on the current culture) and Non Localizable (do not change based on culture).
Lets see how can we define access and localize birary resources.
Defining a Binary Resource
As shown in the image below, you select the Build Action property and set it to either Resource or Content.
Define Resource Prop in VS
Select Build Action as Resource when you want to include your resource in the assembly and Select Build Action as Content when you want your resourcfe to be a loose file and only the existence and relative location of the file sould be included in the assembly.
Now if you would have noticed the above image carefully (you can have a look again if you want) then you will see there is another value by the name of Embedded Resource (this also embeds the resource into the assembly just like Resource). The use of this value is not recomended in WPF as this property belongs to old .net and was ment to be used with Windows Forms. Also if you select your resource to an Embedded Resource then you will not be able to access it in XAML (unless you write some custom code for the same).
[highlight]Note – As a rule of thumb you should embed the resource (with the Resource build action) only when the resouce is localizable or you specificly need single binary or resource within binary else you should prefer Content build action.[/highlight]
Accessing a Binary Resource
In WPF you can access a binary resource from code ox XAML through a URI (uniform resource identifier). And a types converter will help us to specify URIs in XAML as simple strings. The code below demonstrates how simple we can access resources whose build action property has been set to either Resource or Content but they have been included in the project
<Image Height=”21” Source=”slideshow.gif”/>
Note – A compiled XAML cannot reference a binary resource in the current directory via its simple filename unless it has been added to the project. For accessing files that are not added into the project either give the full path of the resource or access resource using Site of Origin url.
<Image Height=”21” Source=”C:\\Users\\Adam\\Documents\\slideshow.gif”/>
<Image Height=”21” Source=”pack://siteOfOrigin:,,,/slideshow.gif”/>
Below here is the list present for refernce of how to acces which binary resource.
Resource Type URI Mapping
Accessing Resources from Procedural Code
If you want to access resources from your C# or vb.net code the XAML specific shortcuts will not work but the URIO should be fully qualified. Below is an example for the same:
Image image = new Image();
image.Source = new BitmapImage(new Uri(“pack://application:,,,/logo.jpg”));
So the above lines of code will instantiate a System.Windows.Media.Imaging.BitmapImage object which ultimately derives from the abstract ImageSource type and this will work with popular image formats such as JPEG, PNG, GIF, BMP. The use of pack://application:,,,/ works only with resources belonging to the current project marked as Resource or Content. To reference relative loose files with no relation to the project, the easiest approach is to use a siteOfOrigin-based URI.
Localizing a Binary Resource
If your application contains some binary resources that are specific to certain cultures then we can partition them into satellite assemblies (one for each culture) and get them loaded automatically when appropriate. And if you are having binary resources for localization then there is a very good chance that you have string in your UI for localization. Here we could make use of LocBaml (sample tool in windows SDK) which will make it very easy to manage localization of strings and other items without removing them from XAML and manually apply a level of indirection. Lets have a look as to how can we use LocBaml and Satellite Assemblies. Remember this is just an overview on how you can proceed with it. To specify a default culture for resources and automatically build an appropriate satellite assembly, you must add a UICulture element to the project file. Visual Studio doesn’t have a means to set this within its environment, so you can open the project file in your favorite text editor instead. The UICulture element should be added under any or all PropertyGroup elements corresponding to the build configurations you want to affect (Debug, Release, and so on), or to a property group unrelated to build configuration so it automatically applies to all of them. This setting should look as follows for a default culture of American English:
<Project …>
<PropertyGroup>
<UICulture>en-US</UICulture>
……
If you rebuild your project with this setting in place, you’ll find an en-US folder alongside your assembly, containing the satellite assembly named assemblyName.resources.dll. You should also mark your assembly with the assembly-level NeutralResourcesLanguage custom attribute with a value matching your default UICulture setting, as follows:
[assembly: NeutralResourcesLanguage(“en-US”, UltimateResourceFallbackLocation.Satellite)]
The next step is to apply a Uid directive from the XAML language namespace (x:Uid) to every object element that needs to be localized. The value of each directive should be a unique identifier. This would be extremely tedious to do by hand, but it fortunately can be done automatically by invoking MSBuild from a command prompt, as follows:
msbuild/t:updateuid ProjectName.csproj
Running this gives every object element in every XAML file in the project an x:Uid directive with a unique value. You can add this MSBuild task inside your project before the Build task, although this might produce too much noise if you rebuild often.
After compiling a project that has been enhanced with Uids, you can run the LocBaml tool from the Windows SDK on a .resources file generated by the build process (found in the obj\debug directory), as follows:
LocBaml /parseProjectName.g.en-US.resources /out:en-US.csv
This generates a simple .csv text file containing all the property values you should need to localize. You can edit the contents of this file so it correctly corresponds to a new culture. (There’s no magic in this part of localization!) If you save the file, you can then use LocBaml in the reverse direction to generate a new satellite assembly from the .csv file!
For example, if you changed the contents of the .csv file to match the French Canadian culture, you could save the file as fr-CA.csv and then run LocBaml as follows:
LocBaml /generate ProjectName.resources.dll /trans:fr-CA.csv /cul:fr-CA
This new satellite assembly needs to be copied to a folder alongside the main assembly with a name that matches the culture (fr-CA in this case).
To test a different culture, you can set System.Threading.Thread.CurrentThread.CurrentUICulture (and System.Threading.Thread.CurrentThread.CurrentCulture) to an instance of the desired CultureInfo.
Logical Resource
As you might have gussed logical resources are the ones which are arbitary .NET objects stored in an element’s resources property (meant to be shared by multiple child elements). The base clases of both FrameworkElement and FrameworkContentElement have a Resource Property. The examples of logical resources are
styles,data provides, etc.
Lets see an XAML code for a logical resource which is Brush. The following example shows a simple windows with a row of buttons along the bottom which can be used in a photo gallery user interface. This example shows how to apply custom brush to each Button’s Background and BorderBrush.
<Window xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation“ Title =”Simple Window” Background=”Yellow”>
<DockPanel>
<StackPanel DockPanel.Dock=”Bottom” Orientation=”Horizontal” HorizontalAlignment=”Center”>
<Button Background=”Yellow” BorderBrush=”Red” Margin=”5″>
<Image Height=”21″ Source=”zoom.gif”/>
</Button>
<Button Background=”Yellow” BorderBrush=”Red” Margin=”5″>
<Image Height=”21″ Source=”defaultThumbnailSize.gif”/>
</Button>
<Button Background=”Yellow” BorderBrush=”Red” Margin=”5″>
<Image Height=”21″ Source=”previous.gif”/>
</Button>
<Button Background=”Yellow” BorderBrush=”Red” Margin=”5″>
<Image Height=”21″ Source=”slideshow.gif”/>
</Button>
<Button Background=”Yellow” BorderBrush=”Red” Margin=”5″>
<Image Height=”21″ Source=”next.gif”/>
</Button>
<Button Background=”Yellow” BorderBrush=”Red” Margin=”5″>
<Image Height=”21″ Source=”counterclockwise.gif”/>
</Button>
<Button Background=”Yellow” BorderBrush=”Red” Margin=”5″>
<Image Height=”21″ Source=”clockwise.gif”/>
</Button>
<Button Background=”Yellow” BorderBrush=”Red” Margin=”5″>
<Image Height=”21″ Source=”delete.gif”/>
</Button>
</StackPanel>
<ListBox/>
</DockPanel>
</Window>
Applying Custom Color Brushes Without Using Logical Resources
Now lets implement Logical Resources
<Window xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” Title=”Simple Window”>
<Window.Resources>
<LinearGradientBrush x:Key=”backgroundBrush” StartPoint=”0,0″ EndPoint=”1,1″>
<GradientStop Color=”Blue” Offset=”0″/>
<GradientStop Color=”White” Offset=”0.5″/>
<GradientStop Color=”Red” Offset=”1″/>
</LinearGradientBrush>
<SolidColorBrush x:Key=”borderBrush”>Red</SolidColorBrush>
</Window.Resources>
<Window.Background>
<StaticResource ResourceKey=”backgroundBrush”/>
</Window.Background>
<DockPanel>
<StackPanel DockPanel.Dock=”Bottom” Orientation=”Horizontal” HorizontalAlignment =”Center”>
<Button Background=”{StaticResource backgroundBrush}” BorderBrush=”{StaticResource borderBrush}” Margin=”5″>
<Image Height=”21″ Source=”zoom.gif”/>
</Button>
<Button Background=”{StaticResource backgroundBrush}” BorderBrush=”{StaticResource borderBrush}” Margin=”5″>
<Image Height=”21″ Source=”defaultThumbnailSize.gif”/>
</Button>
<Button Background=”{StaticResource backgroundBrush}” BorderBrush=”{StaticResource borderBrush}” Margin=”5″>
<Image Height=”21″ Source=”previous.gif”/>
</Button>
<Button Background=”{StaticResource backgroundBrush}” BorderBrush=”{StaticResource borderBrush}” Margin=”5″>
<Image Height=”21″ Source=”slideshow.gif”/>
</Button>
<Button Background=”{StaticResource backgroundBrush}” BorderBrush=”{StaticResource borderBrush}” Margin=”5″>
<Image Height=”21″ Source=”next.gif”/>
</Button>
<Button Background=”{StaticResource backgroundBrush}” BorderBrush=”{StaticResource borderBrush}” Margin=”5″>
<Image Height=”21″ Source=”counterclockwise.gif”/>
</Button>
<Button Background=”{StaticResource backgroundBrush}” BorderBrush =”{StaticResource borderBrush}” Margin=”5″>
<Image Height=”21″ Source=”clockwise.gif”/>
</Button>
<Button Background=”{StaticResource backgroundBrush}” BorderBrush =”{StaticResource borderBrush}” Margin=”5″>
<Image Height=”21″ Source=”delete.gif”/>
</Button>
</StackPanel>
<ListBox/>
</DockPanel>
</Window>
Consolidating Color Brushes with Logical Resources