C# “如何加载WPF应用程序资源”;via Code";(不是“通过XAML”)从单独的组件
我有一个WPF应用程序(称之为启动器),希望通过代码而不是XAML来指定额外的应用程序资源(例如额外的视图、组件和内容)。此外,这些资源由第二个程序集定义(而不是定义C# “如何加载WPF应用程序资源”;via Code";(不是“通过XAML”)从单独的组件,c#,.net,wpf,xaml,app.xaml,C#,.net,Wpf,Xaml,App.xaml,我有一个WPF应用程序(称之为启动器),希望通过代码而不是XAML来指定额外的应用程序资源(例如额外的视图、组件和内容)。此外,这些资源由第二个程序集定义(而不是定义App.xaml的同一个程序集) 目前,我们在App.xaml中对此进行了定义: <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries>
App.xaml
的同一个程序集)
目前,我们在App.xaml
中对此进行了定义:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/GUI;component/Common/ViewResources.xaml" />
<ResourceDictionary Source="/GUI;component/Common/ResourceDictionary.xaml" />
<ResourceDictionary Source="/Components;component/Common/ResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
这是可行的,但这不是我想要做的。要解析这些资源,我需要在URL中指定程序集引用,或在EXE中包含/复制资源(包含App.xaml
的程序集)
是否有办法在GUI端的代码中设置/初始化应用程序资源?
还有其他想法吗?
您必须假设启动程序已经输入了“App::Run”,您必须在该事件发生后加载必要的UI资源,并且必须保持处理中。
有3种明显的解决方案是不可接受的:
一位同事刚刚提出了一个解决方案,其实很简单: 提供属性GUI.Resources,用于设置所有启动器应用程序资源:
public ResourceDictionary Resources
{
get
{
ResourceDictionary resourceGUIView = new ResourceDictionary();
resourceGUIView.Source = new Uri("/GUI;component/Common/ViewResources.xaml", UriKind.RelativeOrAbsolute);
ResourceDictionary resourceGUI = new ResourceDictionary();
resourceGUI.Source = new Uri("/GUI;component/Common/ResourceDictionary.xaml", UriKind.RelativeOrAbsolute);
ResourceDictionary resourceComponent = new ResourceDictionary();
resourceComponent.Source = new Uri("/Component;component/Common/ResourceDictionary.xaml", UriKind.RelativeOrAbsolute);
ResourceDictionary generalResource = new ResourceDictionary();
generalResource.MergedDictionaries.Add(resourceGUIView);
generalResource.MergedDictionaries.Add(resourceGUI);
generalResource.MergedDictionaries.Add(resourceComponent);
return generalResource;
}
}
然后在启动器的App.xaml.cs中调用它:
protected override void OnStartup(StartupEventArgs e)
{
this.Resources = this.context.GUI.Resources;
...
base.OnStartup(e);
}
需要考虑的其他一些方法:
- 要指定程序集引用,这适用于“通过XAML”和“通过代码”两种情况
- 使用
条目创建一个应用程序配置,该条目将目标UI入口点指定为“键入全名”,例如“MyNamespace.InitializerClassName,MyAssemblyName”,然后将其作为参数传递给调用
。此类型的构造函数将执行必要的初始化(或抛出)Activator.CreateInstance()
- 创建一个专门构建的接口,并使用反射来定位另一个程序集的“初始值设定项类型”。然后在该接口上调用一个众所周知的方法来执行UI初始化
- 创建一个专门构建的属性,并使用反射来定位另一个程序集的“初始值设定项方法”。然后调用该方法执行UI初始化
- 创建辅助
并在辅助AppDomain
上下文中的新线程上调用AppDomain
。在调用App.Run()
之前,您可能必须利用App.Run()
执行远程调用以创建线程、处理异常并扩展主机环境。这种方法将允许启动器和目标UI在相同的物理进程空间中共存,允许启动器扩展运行时环境,并允许目标UI在代码中执行初始化MarshallByRefObject
看起来OPs自己的解决方案在编译时与目标程序集紧密耦合(没有配置/发现/反射过程)删除目标UI程序集会破坏构建/编译。在WPF应用程序中启动业务服务有什么问题?我已经把这个问题重读了4遍,但我仍然完全不知道你想实现什么。他试图从一个非UI特定的启动器中动态加载UI。这很难理解,但如果你以前做过,也很明显他想尝试什么。如果你不明白,没有理由否决,有人只需要修改这个问题。为什么这与XAML有什么不同?因为启动程序不需要知道GUI需要哪些资源,就像GUI提供这些资源一样。但基本上我们会有相同的解决方案,只有资源的定义来自GUI,就像我想要的那样。@FábioFerreira作为旁白,您也可以通过在Uri中指定程序集引用从XAML执行此操作。如果已经有一个关于如何做的问题,我不会感到惊讶。