1. 两种资源文件的连接
前面讲了.net中使用资源的通用方法,以及WPF中对UI进行Localization的方法,在实际使用中,经常会同时使用两种方法,我们需要用al.exe这个工具,把两个资源文件链接成一个资源文件:
al /template:WpfLocalizationLocBaml.exe
/embed:de/WpfLocalizationLocBaml.g.de.resources
/embed:../obj/WpfLocalization.Properties.Resources.de.resources
/culture:de /out:de/WpfLocalizationLocBaml.resources.dll
WpfLocalizationLocBaml.g.de.resources是利用LocBaml生成的文件,可以在obj/Debug中找到,或者用LocBaml生成也可以:
LocBaml.exe /generate ../../obj/WpfLocalizationLocBaml.g.de.resources
/trans:../../Res/de.csv
WpfLocalization.Properties.Resources.de.resources 是工程中Properties文件夹下的资源文件。
最终会生成一个WpfLocalizationLocBaml.resources.dll ,要把它放到相应语言的文件夹下,这里是de。
2. 在Xaml中使用.net通用资源
默认的,Visual Studio生成的资源文件对应的cs文件中的类是internal的,不能在xaml中引用到,我们需要改变一下编译资源文件时使用的工具,如下图:
右键资源文件,在属性时把ResXFileCodeGenerator改为PublicResXFileCodeGenerator(在2005的时代,这个工具叫ResXFileCodeGeneratorEx
),这样生成的cs文件的类就是pulic了,最好再检查一下,避免某些误操作把cs文件清空了。
<Window x:Class="WpfLocalization1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WPF_Localize" Height="155" Width="194" xmlns:prop="clr-namespace:WpfLocalization1.Properties"> <Grid> <Button Margin="30,20,35,26" Name="button1" Content="{x:Static prop:Resources.MainButtonText}" /> </Grid> </Window>
在xaml中加入Properties的命名空间,就可以利用StaticExtension得到资源文件中对应的值,如上段代码。
3. 在xaml中定义Resource
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Simple Window"> <Window.Resources> <SolidColorBrush x:Key="backgroundBrush">Yellow</SolidColorBrush> <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>
继承于FrameworkElement的类都有Resource属性,其是个ResourceDictionary 类,也就是基于Hasgtable的键值表。键是用x:Key表示。
可以根据不同需求,把Resource放在不同的级别,比如Application级别(在App.xaml中),windows级别,控件级别。子级别可以引用父级别的Resource,子级别的Resource可以覆盖父级别的Resource,如果父子同时定义了相同的key,则以子级别为主。
可以把Resource放在不同的文件中(Visual Studio中右键增加Resource Dictionary),可以使用MergeredDictionaries把Resource文件合并在一起:
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="file1.xaml"/>
<ResourceDictionary Source="file2.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
有时需要将FrameworkElement或FrameworkContentElement设置resource,可以设置resource的x:Shared = false,这样引用的FrameworkElement实际上是不同的复本。
4. StaticResource与DynamicResource
StaticResource通常在windows或page Load时加载,DynamicResource用到时才加载,DynamicResource比StaticResource开销更大。
DynamicResource只能设置在dependency property上, StaticResource无此限制。
StaticResource要求先声明才能引用,DynamicResource无此限制。
SystemColors, SystemFonts, SystemParameters这些是系统定义的,可以在控制面板中设置,所以要用DynamicResource。
<Button Background="{DynamicResource {x:Static SystemColors.WindowBrush}}"/>
5. C#中使用resource
定义资源:
window.Resources.Add(“backgroundBrush”, new SolidColorBrush(“Yellow”));
window.Resources.Add(“borderBrush”, new SolidColorBrush(“Red”));
StaticResource:
Button button = new Button();
button.Background = (Brush)button.FindResource(“backgroundBrush”);
button.BorderBrush = (Brush)button.FindResource(“borderBrush”);
FindResource没找到会异常,或者用TryFindResource方法,没找到返回null
DynamicResource:
Button button = new Button();
button.SetResourceReference(Button.BackgroundProperty, “backgroundBrush”);
button.SetResourceReference(Button.BorderBrushProperty, “borderBrush”);
从这里可以看到DynamicResource只能在Dependency property上使用。
虽然可以直接使用索引器检索到资源:
Button button = new Button();
button.Background = (Brush)window.Resources[“backgroundBrush”];
button.BorderBrush = (Brush)window.Resources[“borderBrush”];
但是这种方法是不提倡的,因为直接检索Resource dictionary,不遍历逻辑树,某些时候会产生非预期效果,当然不遍历逻辑树,性能上有一点点提升。
6. 引用其他assembly中的资源
定义资源:
<SolidColorBrush
x:Key=”{ComponentResourceKey TypeInTargetAssembly={x:Type local:MyClass},
ResourceId=MyClassBrush}”>Yellow</SolidColorBrush>
Key不能使用string了,要使用ComponentResourceKey这个Markup Extension。
使用资源:
<Button Background="{DynamicResource {ComponentResourceKey TypeInTargetAssembly=
otherAssembly:MyClass, ResourceId=MyClassBrush}}"/>