C# 在WPF中共享应用程序资源

C# 在WPF中共享应用程序资源,c#,wpf,nested-resources,C#,Wpf,Nested Resources,从中,我读到: 如果应用程序使用自定义控件并在ResourceDictionary(或XAML resources节点)中定义资源,建议您在应用程序或窗口对象级别定义资源,或在自定义控件的默认主题中定义资源。在自定义控件的ResourceDictionary中定义资源会对该控件的每个实例施加性能影响 好的。。。现在,我有一个UserControl,它定义了以下资源: <UserControl ...> <UserControl.Resources>

从中,我读到:

如果应用程序使用自定义控件并在ResourceDictionary(或XAML resources节点)中定义资源,建议您在应用程序或窗口对象级别定义资源,或在自定义控件的默认主题中定义资源。在自定义控件的ResourceDictionary中定义资源会对该控件的每个实例施加性能影响

好的。。。现在,我有一个UserControl,它定义了以下资源:

<UserControl ...>
    <UserControl.Resources>
        <Namespace:ImagesConverter x:Key="ImagesConverter" ...
        <Storyboard x:Key="AnimationHide" ...
    </UserControl.Resources>
我应该如何修改它以反映这些更改?我应该如何修改下面的UserControl XAML代码段

Source="{Binding Source={x:Static Properties:Resources.MyImage}, Converter={StaticResource ImagesConverter}}"

就我个人而言,我更喜欢使用
App.xaml
或单独使用
ResourceDictionary
,而不是将它们全部添加到
窗口中。Resources
,这样可以消除
窗口中的混乱

这还允许您轻松地为应用程序创建
主题
,因为它们都位于一个位置,因此您可以复制现有的
资源字典
更改笔刷颜色等,您可以选择要加载的
资源字典
,并轻松地更改应用程序的整个外观

至于访问
Usercontrol
中的
resources
在xaml端没有区别,您将继续使用
{StaticResource resourceKey}
,就像调用
StaticResource
时,它搜索
资源
层次结构以查找
资源

因此,如果将资源从
UserControl.Resources
移动到
Window.Resources
Application.Resources
,则无需更改通过
{StaticResource resourceKey}
访问的xaml代码中的任何内容

至于代码隐藏中的访问,您将使用
FindResource(“resourceKey”)
而不是
Resources[“resourceKey”]
,因为
FindResource
将像xaml中的
StaticResource
一样在层次结构中搜索
资源

例如:

m_AnimationHide = (Storyboard)FindResource("AnimationHide");
如果要修改特定控件中的任何资源,并且这些资源已冻结,则只需为该实例创建一个副本即可

范例

var animation = FindResource("AnimationHide") as Storyboard;

m_AnimationHide = animation.Clone();
m_AnimationHide.Completed += m_AnimationHide_Completed;
您还可以设置
x:Shared=“false”
这将每次从资源返回一个新的动画实例,如果您有一个复杂的资源需要更改其中的值,这将在整个应用程序中保存复制/粘贴相同的动画

<Storyboard x:Key="AnimationHide" x:Shared="false" />


然后您就可以在本地修改资源了。

我想详细介绍一下将资源移出控制xaml的原因

正如您在MSDN库中所读到的,将任何内容提升到更高级别的唯一技术原因是为了节约资源(即内存)。ResourceDictionary中的每个条目在运行时创建为对象(=实例!),占用内存,初始化需要几个CPU周期

现在,像故事板这样的捕获:必须为它应该驱动的控件的每个实例创建一个对象,该对象存储与控件的特定实例(如正在执行的动画实例)相关甚至连接的数据。除非希望所有控件都以相同的方式并行设置动画


对我来说,在代码中使用
Clone
,而不是一开始就把它放到xaml中,没有多大意义。xaml方法需要一点复制/粘贴,因此意味着在多个位置修改动画(如果您甚至可以跨控件重复使用类似的内容)但是它将删除代码要求,并且仍然执行相同的操作:为控件的每个实例创建一个
情节提要的实例。

我按照您所说的做了,但出现了一些问题。我的UserControl中有一段代码如下:
animation.Completed+=handler。每当我到达那里。我的应用程序崩溃,告诉我:
DoubleAnimation必须将isfreeze设置为false才能修改
。这些动画必须在完成时触发它们的UserControl上执行某些操作。如何修复它?因为您不能将静态资源修改为冻结资源,所以我在回答中添加了一个解决方法谢谢!我尝试了第一种方法(全部进入应用程序),效果很好。现在我正在尝试第二个(全部进入主窗口)。。。但每当我尝试将MainWindow资源引用到自定义UserControl中时,就会出现未解决的资源错误。为什么?因为不能保证
用户控件
将被放置在该
窗口
中,并且可以访问其
资源
,所以您将使用
{staticResourceKey}
而不是
{dynamicResourceKey}
。这将在运行时解决。资源的层次结构是:本地对象->可视化树,直到根(承载控件的窗口)->应用程序资源。因此,如果将控件放在主窗口中,它应该可以工作。如果控件托管在另一个窗口中,将找不到资源。克隆
或使用
x:Shared
(克隆的xaml版本)是有意义的,因为如果您有一个
主题化的
应用程序,您将如何在多个位置轻松复制/粘贴
资源。使用xaml或代码克隆,您只需更改主题录音带中的资源,而不必考虑整个应用程序。
<Storyboard x:Key="AnimationHide" x:Shared="false" />