[WPF]多Resource文件的相互引用与合并问题及其解决方案
2010-02-04 22:51
381 查看
我们都知道在WPF中,所有的控件都有Resources属性,里面可以放Resource。一般比较常用的Resource位置就是Application的Resource和各个Window的Resource。那么这两个Resource的位置,除了作用范围不同之外,还有什么不同呢?
一个不同点就是,Application的Resource会被作用一个全局共享的Resource的来源。这会给Merge Resource Dictionary带来极大的方便,但是这个性质并不像想象中的那么好用。
在实际项目中,通常会对Resource的使用有如下的几点要求。
1. 不要把所有的Resource放在一个文件里。我们常常会把Resource按其功能或是使用对象,分别放置在不同的Resource Dictionary里,这样不仅结构清楚,找起来方便,而且用Blend打开时也会更快,共同开发的冲突也会更少。
2. 使用Resource时,出于性能考虑,要尽量使用StaticResource。这个要求,会间接地要求Resource按顺序定义,就是说,未定义过的Resource是不能使用的。而XAML中又不存在类似C语言中的声明语句或是头文件。这样Resource就必须非常注意其顺序。一不小心就会出现NotFindException.
当把上面的两个要求合并起来之后,问题会变得很复杂。由于Resource放在了不同的Resource文件中,这就要考虑到Resource的跨文件引用问题。这个问题有两个解决方案。
1. 如果Resource文件A,使用了Resource文件B中的Resource,那么就在文件A中,通过ResourceDictionary.MergedResourceDictionaries把Resource文件B合并过来。这个方式的一个问题就是,要为每个文件维护一个依赖文件列表,而且如果有多个Resource文件Merge了同一个Resource文件,会给人一种冗余的感觉。是不是这个被Merge了多次的Resource文件,相当于有了多件拷贝?
2. 另一种方式就是在Application的Resource中把所有的Resource文件都Merge进来。而且要一个一个Merge。这样,下面的MergedResource就可以访问上面的MergedResource里的东西了。而且只有直接在Application的Resource里这样写才有效果。
MergeResource的示例如下。用代码会更直观一些。
Merge Resource
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CommonProperties.xaml"/>
<ResourceDictionary Source="Button.Style.xaml"/>
<ResourceDictionary Source="ComboBox.Style.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
在上面的示例中,如果XXXX.Style.xaml中的Resource以Static的方式使用了CommonProperties.xaml里的Resource有如下图所示的引用关系。
![](http://images.cnblogs.com/cnblogs_com/nankezhishi/WPFResourceReference/ResourceRelationShip.PNG)
图1. Resource间的引用关系示例
那么这样的Merge Resource方式,能否保证XXXX.Style.xaml能够引用到CommonProperties.xaml里的Resource呢?答案是不一定,要看这个MergeResource的代码放置在了什么地方,如果是在App.xaml里,可以;如果不是,则不可以。
如下图所示。
![](http://images.cnblogs.com/cnblogs_com/nankezhishi/WPFResourceReference/MergeResource.PNG)
图2. 可行的Merge方式(直接在Application的Resource里Merge)
![](http://images.cnblogs.com/cnblogs_com/nankezhishi/WPFResourceReference/InvalidMergeResource.PNG)
图3. 不可行的Merge方式。(在单独的一个文件里Merge)
![](http://images.cnblogs.com/cnblogs_com/nankezhishi/WPFResourceReference/InvalidMergeResource2.PNG)
图4. 亦不可行的方案(在Window中Merge)
所以在WPF程序中,应该尽量在App.xaml进行Resource的Merge工作。但是这也造成了一些问题。如DLL封装性的问题——专门存放Resource的DLL,不能通过一个已经Merge好的,单一的Resource文件把这个DLL里的所有Resource暴露给使用者,使用者必须在App.xaml里一个一个地引用DLL中的所有Resource文件,DLL改了,App.xaml的引用也要改,从而破坏了封装性。再一个问题就是如果没有WPF Application(比如在WinForm程序中集成一些WPF的组件),那就可能会没有Application级的Resource,也就没有很好的Merge Resource的解决方案了。可行的方案有四个。
1. 建立一个WPF Application,并Host原来程序中的WinForm部分。而不是在WinForm程序里Host WPF组件。
2. 把所有Resource放在一个文件里,并维护好Resource的前后顺序,这样就没有了文件间的引用问题。
3. 为每个Resource文件都使用MergedResourceDictionary。把它用到的Resource文件Merge进来。这个方案可能会造成Resource重复的问题。
4. 退一步。对于文件间的引用使用DynamicResource。有人认为DynamicResource比StaticResource的性能差,我同意。经过测试,DynamicResource用的时间是StaitcResource的5倍。但是如果Resource不会变,那只不过是在第一次加载时慢些罢了。还是在真正有性能问题的地方下功夫吧。
这个只能在Application里Merge Resource File的事实,也许可以算是一个Bug吧,因为从WPF的使用者的角度而言,总是希望无论这个Merge在什么地方,都可以保证Resource文件的向上引用才好。
一个不同点就是,Application的Resource会被作用一个全局共享的Resource的来源。这会给Merge Resource Dictionary带来极大的方便,但是这个性质并不像想象中的那么好用。
在实际项目中,通常会对Resource的使用有如下的几点要求。
1. 不要把所有的Resource放在一个文件里。我们常常会把Resource按其功能或是使用对象,分别放置在不同的Resource Dictionary里,这样不仅结构清楚,找起来方便,而且用Blend打开时也会更快,共同开发的冲突也会更少。
2. 使用Resource时,出于性能考虑,要尽量使用StaticResource。这个要求,会间接地要求Resource按顺序定义,就是说,未定义过的Resource是不能使用的。而XAML中又不存在类似C语言中的声明语句或是头文件。这样Resource就必须非常注意其顺序。一不小心就会出现NotFindException.
当把上面的两个要求合并起来之后,问题会变得很复杂。由于Resource放在了不同的Resource文件中,这就要考虑到Resource的跨文件引用问题。这个问题有两个解决方案。
1. 如果Resource文件A,使用了Resource文件B中的Resource,那么就在文件A中,通过ResourceDictionary.MergedResourceDictionaries把Resource文件B合并过来。这个方式的一个问题就是,要为每个文件维护一个依赖文件列表,而且如果有多个Resource文件Merge了同一个Resource文件,会给人一种冗余的感觉。是不是这个被Merge了多次的Resource文件,相当于有了多件拷贝?
2. 另一种方式就是在Application的Resource中把所有的Resource文件都Merge进来。而且要一个一个Merge。这样,下面的MergedResource就可以访问上面的MergedResource里的东西了。而且只有直接在Application的Resource里这样写才有效果。
MergeResource的示例如下。用代码会更直观一些。
Merge Resource
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CommonProperties.xaml"/>
<ResourceDictionary Source="Button.Style.xaml"/>
<ResourceDictionary Source="ComboBox.Style.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
在上面的示例中,如果XXXX.Style.xaml中的Resource以Static的方式使用了CommonProperties.xaml里的Resource有如下图所示的引用关系。
图1. Resource间的引用关系示例
那么这样的Merge Resource方式,能否保证XXXX.Style.xaml能够引用到CommonProperties.xaml里的Resource呢?答案是不一定,要看这个MergeResource的代码放置在了什么地方,如果是在App.xaml里,可以;如果不是,则不可以。
如下图所示。
图2. 可行的Merge方式(直接在Application的Resource里Merge)
图3. 不可行的Merge方式。(在单独的一个文件里Merge)
图4. 亦不可行的方案(在Window中Merge)
所以在WPF程序中,应该尽量在App.xaml进行Resource的Merge工作。但是这也造成了一些问题。如DLL封装性的问题——专门存放Resource的DLL,不能通过一个已经Merge好的,单一的Resource文件把这个DLL里的所有Resource暴露给使用者,使用者必须在App.xaml里一个一个地引用DLL中的所有Resource文件,DLL改了,App.xaml的引用也要改,从而破坏了封装性。再一个问题就是如果没有WPF Application(比如在WinForm程序中集成一些WPF的组件),那就可能会没有Application级的Resource,也就没有很好的Merge Resource的解决方案了。可行的方案有四个。
1. 建立一个WPF Application,并Host原来程序中的WinForm部分。而不是在WinForm程序里Host WPF组件。
2. 把所有Resource放在一个文件里,并维护好Resource的前后顺序,这样就没有了文件间的引用问题。
3. 为每个Resource文件都使用MergedResourceDictionary。把它用到的Resource文件Merge进来。这个方案可能会造成Resource重复的问题。
4. 退一步。对于文件间的引用使用DynamicResource。有人认为DynamicResource比StaticResource的性能差,我同意。经过测试,DynamicResource用的时间是StaitcResource的5倍。但是如果Resource不会变,那只不过是在第一次加载时慢些罢了。还是在真正有性能问题的地方下功夫吧。
这个只能在Application里Merge Resource File的事实,也许可以算是一个Bug吧,因为从WPF的使用者的角度而言,总是希望无论这个Merge在什么地方,都可以保证Resource文件的向上引用才好。
相关文章推荐
- Resource文件的相互引用与合并问题及其解决方案
- 多Resource文件的相互引用与合并问题及其解决方案
- 用C#语言在VS2010 WPF中编写的选择文件和选择文件夹的问题及其解决方案
- C/C++字符串,字符数组,字符指针及其相互静态拷贝与追加的安全问题解决方案(2)
- 关于引用js文件中出现乱码问题的解决方案
- ASP.Net 类库引用文件路径问题及解决方案
- WPF-13:资源文件需要手动引用问题
- spring 配置文件的相互引用问题
- Windows 7中,用Visual Studio开发WPF应用程序,实现从Windows Explorer中拖拽文件到应用程序,始终显示“无法拖放”符号问题解决方案
- maven项目中子模块中相互引用问题解决方案
- C++代码段 -- 头文件相互引用问题
- C/C++字符串,字符数组,字符指针及其相互静态拷贝与追加的安全问题解决方案(1)
- php文件之间相互引用路径问题的一般处理方法
- Windows系统kernel32.dll文件出问题的原因及其解决方案
- 新导入的工程出现乱码问题 及其 R文件没有生成 解决方案.
- 两个不同的类相互引用的情况下头文件包含问题
- PHP解决引用路径和重复引用文件已经其中的HTML代码的路径问题的终极解决方案
- 两个不同的类相互引用的情况下头文件包含问题
- Hive优化之小文件问题及其解决方案
- php文件之间相互引用路径问题的一般处理方法