组件没有 uri 标识的资源
Posted
技术标签:
【中文标题】组件没有 uri 标识的资源【英文标题】:The component does not have a resource identified by the uri 【发布时间】:2011-11-30 13:44:56 【问题描述】:我想创建一个通用 DataGrid 以在我的所有视图/用户控件上使用。
这是我的结构:
Class Library
叫"Core"
:
Class
叫"ViewBase"
:
public class ViewBase : UserControl
public ViewBase()
//Rest of Methods and Properties
Class Library
叫"Controls"
:
UserControl
调用"GridView"
:
XAML:
<vb:ViewBase x:Class="Controls.GridView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vb="clr-namespace:Core;assembly=Core">
<Grid>
<DataGrid></DataGrid>
</Grid>
</vb:ViewBase>
代码背后:
using Core;
public partial class GridView : ViewBase
public GridView ()
InitializeComponent();
然后是名为“WPFApp”的 WPF 应用程序:
Class
叫"View"
:
using Controls;
public class View : GridView
public View()
InitializeComponent();
我的整个想法是在需要DataGrid
的地方使用GridView
。
当我运行应用程序时出现此错误:
"The component 'WpfApp.View' does not have a resource identified by the URI '/Controls;component/GridView.xaml'."
我做错了什么?
这是正确的方法还是我离题了?
【问题讨论】:
【参考方案1】:@Willem,这对我来说似乎完全没问题。事实上,我试过这个,它在我的情况下有效。我使用ListBox
而不是DataGrid
(但这不重要)。
我所有的命名空间都在一个程序集中。所以我为所有人使用了一个共同的父命名空间,例如
MyWpfApplication.Controls
MyWpfApplciation.GridView
MyWpfApplciation.ViewBase
因为所有这些 Controls
、GridView
、ViewBase
都与现有的基于 System
或 System.Windows.Controls
的命名空间和类声明发生冲突。所以我确保在我的项目中引用了正确的 MyWpfApplication.*
。
【讨论】:
感谢您的回复。事情就是这样,我知道当一切都在一个组件中时它可以工作,但是将它移到我得到的结构中然后它就失败了......我需要它在上述结构中工作。【参考方案2】:我正在做一些非常相似的事情,但结果相同。我有一个 C# 类库,其中包含一个名为 UsageControl 的 WPF 控件(带有随附 xaml.cs 文件的 xaml)。在一个单独的 C# 项目(即单独的 dll)中,我创建了一个 C# class CPUUsageControl,它从 UsageControl继承,但对其进行了自己的调整。当我尝试在我的一个视图上使用 CpuUsageControl 时,我遇到了与您相同的错误。
我在单独的程序集中解决了这个问题,我没有创建一个从基本控件继承的类,而是创建了一个包含基本控件的新 WPF 控件。然后,我将 CpuUsage 类中包含的所有逻辑放入 WpfCpuUsageControl 后面的代码中。我能够使用这个对象是我所有的其他控件都很好。
对于您的控件“GridView”,我将创建一个新的 WPF 用户控件,将其命名为 GridView 并使其包含一个“ViewBase”作为 Grid 控件的内容.Inside ViewBase的内容放在你的DataGrid中,像这样:
<UserControl....>
<Grid>
<ViewBase name="vBase">
<DataGrid name="dGrid" />
</ViewBase>
</Grid>
</UserControl>
我也不清楚您需要 ViewBase 直接从 UserControl 继承。如果您想要的只是让您的控件具有某些属性和方法,为什么不只是创建一个 BaseControl 类(除了对象之外不从任何人继承)并让未来的控件继承自它。也许你需要一个抽象基类或接口。
对于 MVVM WPF 项目,我通常有一个为我实现 INotifyPropertyChanged 的 BaseViewModel,因此我不必在任何地方都执行相同的代码。
祝你好运,我知道这个问题很难解决。异常消息和google最没用!
【讨论】:
感谢 Steven 的回复。有没有办法让它与继承自GridView
的类一起使用?采用这种方法的原因是我们有 100 个需要 DataGrid
的视图。我不想为我需要创建的每个新视图创建一个新的用户控件。我只想从 GridView 继承并设置新的DataContext
。这是我在整个设计背后的想法。你建议我应该做些什么或改变什么来获得这种行为?
您也可以尝试从接口继承 DataGrid 和 IMPLEMENT(其中包含您想要的属性和方法原型)。如果我们在 C# 中有多重继承,你可以从 DataGrid 和一些 BaseControl 继承:\【参考方案3】:
您收到此错误的原因是因为 InitializeComponent 的实现方式(在 VS 2010 中)将始终在派生类的程序集中搜索。
这里是初始化组件:
/// <summary>
/// InitializeComponent
/// </summary>
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "4.0.0.0")]
public void InitializeComponent()
if (_contentLoaded)
return;
_contentLoaded = true;
System.Uri resourceLocater = new System.Uri("/WpfApplication1;component/mainwindow.xaml", System.UriKind.Relative);
#line 1 "..\..\..\MainWindow.xaml"
System.Windows.Application.LoadComponent(this, resourceLocater);
#line default
#line hidden
它查找 XAML 资源的行是 System.Windows.Application.LoadComponent(this, resourceLocator)。这很可能会失败,因为等效于 'this.GetType().Assembly' 用于确定要搜索由相对 Uri 标识的资源的程序集。而'this.GetType()'确实得到了对象的派生类型,而不是实现代码的类的类型。
PS。这是一个错误吗?我不知道...
【讨论】:
【参考方案4】:我通过放置解决了这个问题
myusercontrol = Activator.CreateInstance<myusercontrol>();
在InitializeComponent();
行之前包含用户控件的窗口的构造函数中
【讨论】:
【参考方案5】:令人沮丧的是,我确实遇到了这个错误,并且花了很长时间试图找出原因。对我来说,它曾经可以工作,但后来我对派生控件的 XAML 进行了一些非常小的更改,编译器开始给出该错误消息。 简短的解决方案,减少了数小时的尝试:关闭 Visual Studio 并重新打开它,重新编译,问题神奇地消失了! (这是VS2012 Pro) 只是添加了这个,以防任何阅读者绕着圈子试图找到他们的代码不存在的问题。可能值得先尝试“IT Crowd 解决方案”。
【讨论】:
是的,设计师又搞糊涂了。 与 VS2013 相同 - 只需关闭并重新打开。我不知道其他人,但我只在设计器中得到这个错误,而不是在我运行应用程序时。最初的提问者谈到了运行应用程序,但我猜这个问题的很多访问者在设计时都会收到这个错误 不幸的是,对于这种程序,我觉得“关闭并重新打开”的发生频率太高了。不仅仅是这个问题,还有很多其他问题。 比退出整个 VS 应用程序更快的解决方案就是杀死设计器并重新启动它。在任务管理器中终止 XDesProc 进程,然后单击 VS 中显示的重新加载链接。 刚刚与 VS2015 更新 3 相同。非常感谢!!!!!!你节省了我很多时间和头痛 :-) !【参考方案6】:我也遇到了这个问题,没有任何继承问题。我只是在引用一个包含对话框的 DLL,并尝试创建和显示该对话框。 我有从特定文件夹加载程序集的程序集解析器,事实证明我已经在 VS 中添加了引用并且没有关闭 Copy Local。长话短说:我的进程加载了同一个 DLL 的两个版本。这似乎使 WPF(或运行时)感到困惑。一旦我清除了 Copy Local 并删除了额外的 DLL 副本,它又可以正常工作了。
【讨论】:
【参考方案7】:我在使用 Visual Studio 2013 时收到了同样的错误。
组件没有 uri 标识的资源
试过了: 清理和重建解决方案 - 没有用。 关闭和打开 Visual Studio - 不起作用。
解决方案:
进入项目bin
目录并清除所有文件。
再次运行项目并运行良好。
打开 Package Manager Console,它将在您的解决方案的根目录中打开并运行以下 powershell 命令:
Get-ChildItem -inc bin,obj -recurse | Remove-Item -recurse -force -EA SilentlyContinue
【讨论】:
【参考方案8】: 删除obj
文件夹
删除bin
文件夹
重建解决方案
为我工作!
此外,如果您正在使用 Assembly.LoadFile
加载程序集,请查看 AppDomain.CurrentDomain.GetAssemblies()
以获取当前 AppDomain 中的重复程序集。因为在 WPF UserControl 的自动生成代码中,组件将使用其相对 URI 加载。而且由于当前 AppDomain 中有重复的程序集,应用程序不知道该使用哪一个。
【讨论】:
在我的例子中,我点击了 Build -> Clean Solution,然后是 Build -> Build Solution (F7)【参考方案9】:重命名 xaml 文件后出现此错误。反转重命名解决了这个问题。
此外,我发现 App.xaml 中对 xaml 文件名的引用未更新(StartupUri),但将其重命名为当前名称并不能解决问题(但也许它对您有用)。基本上,我无法重命名 xaml 文件。
仅供参考,对我来说,错误中“抱怨”的组件是 SplitComboBox。
【讨论】:
【参考方案10】:同样的问题。
短版:
复制本地必须设置为False!
长版:
我们开发了一个 WPF 解决方案(MVVM,20 个项目)并实现了一个插件系统。我们的 /bin/Debug 目录包含可执行文件、一些 dll 文件和一个包含插件的插件目录。 有一个项目“DialogLib”(类库,一种对话框)定义了一个窗口(视图)、ViewModel、Model 和一些接口。其中一个插件使用了 DialogLib 的接口之一。窗口本身由主应用程序打开。
要在插件中使用“DialogLib”库的接口,我们必须将 DialogLib 的项目引用添加到插件项目引用中。当应用程序启动时,插件被加载。如果用户随后选择了一个菜单项,则该窗口应该打开。此时,当后面的 windows 代码尝试执行其 InitializeComponent() 时,出现错误“...组件没有 URI 标识的资源...”。
问题出在哪里?
问题是,当我们构建解决方案时,VS 已经正确创建了 DialogLib.dll 并将其复制到 /bin/Debug/。这是因为主应用程序文件要打开窗口。但 DialogLib.dll 也被复制到 /bin/Debug/plugins,因为其中一个插件引用它以使用 DialogLib.dll 中定义的接口之一。那又怎样?
当插件在运行时加载时,它使用 /bin/Debug/plugins/DialogLib.dll 中定义的接口。并且主应用程序文件尝试打开 /bin/Debug/DialogLib.dll 中定义的窗口。尽管文件相同,但 VS 遇到了麻烦。设置插件引用的DialogLib引用属性Copy Local的值,可以避免将DialogLib.dll复制到/bin/Debug/plugins,从而解决问题。
我们在另一个项目中遇到了类似的相同问题(但错误不同),我们想使用在 dll 文件、插件和主应用程序中定义的类型 TypeA。 Copy Local 设置为 true 导致 dll 文件的副本位于 ../bin/Debug/plugins 和 ../bin/Debug/.原来,即使是同一个dll文件,主app文件中的TypeA和插件中的TypeA却被分别视为不同的类型,可以不被交换。
【讨论】:
【参考方案11】:当我在两个解决方案中打开同一个项目时,会发生这种情况。在一个项目中修改基础控件会导致另一个项目出现此问题。如果关闭和打开都不起作用,则删除“C:\Users...\AppData\Local\Microsoft\VisualStudio\12.0\Designer\ShadowCache”中的所有文件夹
【讨论】:
【参考方案12】:比关闭所有 Visual Studio 更快的是在任务管理器中杀死 XDescProc.exe。
XDescProc 是设计者。该过程关闭的那一刻,您将在 Visual Studio 中看到重新加载设计器链接。单击该按钮,XDes 将再次启动,您的“无资源”错误应该消失了。
这是您终止设计器进程后 Visual Studio 显示的链接:
【讨论】:
【参考方案13】:你可以试试这个方法
我创建了自己的InitializeComponent()
,并以这种方式调用
this.LoadViewFromUri("/NameOfProject;component/mainwindow.xaml");
public static void LoadViewFromUri(this Window window, string baseUri)
try
var resourceLocater = new Uri(baseUri, UriKind.Relative);
var exprCa = (PackagePart)typeof(Application).GetMethod("GetResourceOrContentPart", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] resourceLocater );
var stream = exprCa.GetStream();
var uri = new Uri((Uri)typeof(BaseUriHelper).GetProperty("PackAppBaseUri", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null, null), resourceLocater);
var parserContext = new ParserContext
BaseUri = uri
;
typeof(XamlReader).GetMethod("LoadBaml", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] stream, parserContext, window, true );
catch (Exception)
//log
【讨论】:
【参考方案14】:我通过重命名/复制操作意外删除用户控件。当我从版本控制中恢复项目文件和 xaml 文件和 .cs 时,这个错误开始在设计工作室中发生,因为该控件被错误地删除/重命名。
这表明有问题的文件有某种类型的缓存......所以关闭 Visual Studio,删除 bin
目录并重建工作。
【讨论】:
【参考方案15】:这让我头痛了 3 天!我在类库中有一个 XAML UserControl 和一个派生自 .exe 项目中的 UserControl 的类(仅限 C#)。 在我的 MainWindow.xaml 的 xaml 设计器中,在启动应用程序时,我收到错误“组件没有 uri 识别的资源”。 “Juan Carlos Girón”的答案终于让我找到了解决方案:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using System.Reflection;
using System.IO.Packaging;
using System.Windows.Markup;
namespace ClassLibrary1
static class Extension
public static void LoadViewFromUri(this UserControl userControl, string baseUri)
try
var resourceLocater = new Uri(baseUri, UriKind.Relative);
var exprCa = (PackagePart)typeof(Application).GetMethod("GetResourceOrContentPart", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] resourceLocater );
var stream = exprCa.GetStream();
var uri = new Uri((Uri)typeof(BaseUriHelper).GetProperty("PackAppBaseUri", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null, null), resourceLocater);
var parserContext = new ParserContext
BaseUri = uri
;
typeof(XamlReader).GetMethod("LoadBaml", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] stream, parserContext, userControl, true );
catch (Exception)
//log
并通过 UserControl 的 .cs 文件调用它:
namespace ClassLibrary1
public partial class MyUserControl : UserControl
public MyUserControl()
//InitializeComponent();
this.LoadViewFromUri("/ClassLibrary1;component/myusercontrol.xaml");
再次感谢“Juan Carlos Girón”!
【讨论】:
这对我来说是最好的解决方案,不涉及调整我在其中使用此控件的项目..... 这对我来说效果很好。根据我的经验,您必须确保: 1. 基本 UserControl 的构建操作是“Page”和 2. 对 URI 使用“Pack URI”语法(例如 pack://application:,,,/ClassLibrary1;component/myusercontrol. xml)。原因? “Page”项被编译到程序集中(以便以后可以检索它们),“pack”用于检索“Page”项。 docs.microsoft.com/en-us/dotnet/framework/wpf/app-development/… 我花了很多时间试图解决这个问题。谢谢。它并没有立即为我解决问题(我使用的是 VS 2010),所以我关闭了解决方案,删除了.vs
文件夹并删除了 bin 和 obj 文件夹。重新打开解决方案后,我进行了构建,一切看起来都很好。
当 UserControl 在同一个项目中时,它工作得很好。当我将 UserControl 移动到另一个项目然后从中创建一个 nuget 时。在运行项目之前,此控件是不可见的。你知道我能用它做什么吗?【参考方案16】:
关闭和重新打开窗口时也会发生这种情况。所以它也可能与包和/或 dll 无关。 由于 PainElemental 发布的解决方案,我解决了这个问题,恕我直言,它被低估了:
namespace MyNamespace
public partial class MyDialog : Window
public MyDialog(ExcelReference sheetReference)
this.LoadViewFromUri("/MyApp;component/mynamespace/mydialog.xaml");
LoadViewFromUri 是作为扩展实现的,正如 PainElemental 所写。 最疯狂的是,我在同一个项目中也写了其他windows,没有遇到任何问题。 谢谢PainElemental,你结束了我长期的痛苦!
【讨论】:
【参考方案17】:遵循 PainElemental 的解决方案(澄清一下,对于他的代码,ClassLibrary1 对我来说是没有 .dll 扩展名的 .dll 名称),这是我的场景,以防它帮助任何人将他们的特定错误消息与问题联系起来:
我使用 dll 将用户控件加载并运行到主程序中,作为它们自己的弹出窗口。 PainElemental 的解决方案大部分都可以正常工作,但我的“popup .dll”中的 3 个类中有 1 个无法正确加载。我会得到一个带有 2 个内部异常的异常,例如: mscorlib InvokeMethod...; WpfXamlLoader.Load...在...上提供值...StaticResourceExtension...; ResolveBamlType....方法或操作未实现。
在我的例子中,我确认它会加载新的 URI 并在测试中工作,但是当我尝试在我的 Live 环境中运行它时,它会在 LoadViewFromUri() 中出错。
当我进一步测试时,我将问题缩小到无法加载我正在使用的单独的“库 .dll”文件,该文件包含我在失败的类的 .xaml 文件中使用的转换器,并且在进一步的研究中,问题是 Live 环境使用的“库 .dll”版本与我在测试环境中使用的版本不同,即使来自我的“popup .dll”的异常消息没有提及这一点。
作为参考,我使用 Copy Local=True 并没有给我带来问题。为了最好地调试这些类型的问题,了解 .exe 搜索 .dll 文件的位置会很有帮助。据我了解,当您在 VS 中运行项目时,当 Copy Local=True 时,.dll 在构建时被复制到与 .exe 相同的文件夹中。当 .exe 在标准位置运行时,它将搜索 .dlls 与 .exe 相同的文件夹。 .exe 可以查找 .dll 的其他位置可以在 .exe.config 文件的探测元素中设置。在下面的示例中,它还可以在相对于 .exe 位置的“MyDLLs”和“MyDLLs\Core”目录中进行搜索。请注意,它自然不会搜索任何子文件夹,您必须明确指定它们。我相信它也会搜索 GAC,但我目前对 GAC 知之甚少。
<configuration>
...
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="MyDLLs;MyDLLs\Core;"/>
</assemblyBinding>
</runtime>
</configuration>
【讨论】:
【参考方案18】:当我从正在其他计算机上运行的已安装产品中单击特定菜单选项时,我开始一直看到“组件没有 uri 识别的资源”错误。我尝试卸载该产品,确保其文件确实已消失,然后重新启动并重新安装该产品。问题依然存在。我删除了 %TEMP% 目录的内容,问题就解决了。
【讨论】:
【参考方案19】:您好,解决此问题的方法是将 xaml 用户控件重命名为 InitializeComponent() 上的所有小型大写字母...
enter image description here
enter image description here
【讨论】:
而不是发布图像使用您的代码并正确解释您的代码。【参考方案20】:感谢此线程中的所有提示。我认为我自己对这个错误的变体是出于稍微不同的原因,所以我会在这里发布以防万一。
在我的情况下,调用 window.ShowDialog() 时发生错误。更具体地说,我的窗口是在一个单独的类库程序集中定义的(我们称之为 AssemblyA.dll)。
我有多个版本的 AssemblyA,它们用于各种产品,其中一些是插件,有些不是。简而言之,结果是该过程最终可能会加载几个不同的强名称版本的 AssemblyA。因此,正如@VahidN 指出的那样,应用程序域中存在重复的程序集,但它们是严格不同版本的程序集,它们应该存在,并且仅共享相同的 AssemblyShortName。
WPF 为 InitializeComponent() 自动生成的代码如下所示:
public void InitializeComponent()
if (_contentLoaded)
return;
_contentLoaded = true;
System.Uri resourceLocater = new System.Uri("/AssemblyA;component/forms/mywindow.xaml", System.UriKind.Relative);
#line 1 "..\..\..\Forms\MyWindow.xaml"
System.Windows.Application.LoadComponent(this, resourceLocater);
#line default
#line hidden
它只是指 AssemblyA 的简称,而不是指运行 InitializeComponent() 方法的 AssemblyA 的特定版本或公钥令牌。结果是代码似乎只是找到了加载到进程中的第一个 AssemblyA 程序集,搜索 XAML,但找不到它(因为它首先找到了旧版本的程序集),然后引发异常。或者它可能找到 something 但它可能从恰好也被加载的旧版本或新版本的程序集中提取了一个 不同 XAML 资源而不是它应该拥有的资源.
这并不完美,但我咨询了the Pack URI specification,并通过编写我自己的扩展方法来解决这个问题,确保使用适当的版本和公钥令牌找到程序集,而不是简单的 AssemblyShortName。
如果它对其他人有用,这是我最终得到的简化版本。
public static void AssemblySensitive_InitializeComponent(this ContentControl contentControl, string componentString)
// Strictly speaking this check from the generated code should also be
// implemented, but it doesn't fit directly into an extension method.
//if (_contentLoaded)
//
// return;
//
//_contentLoaded = true;
var asm = System.Reflection.Assembly.GetExecutingAssembly();
var shortName = asm.GetName().Name;
var publicKeyToken = GetPublicKeyTokenFromAssembly(asm);
var version = asm.GetName().Version.ToString();
System.Uri resourceLocater = new System.Uri($"/shortName;Vversion;publicKeyToken;componentString", System.UriKind.Relative);
System.Windows.Application.LoadComponent(contentControl, resourceLocater);
/// <summary>
/// Gets a public key token from a provided assembly, and returns it as a string.
/// </summary>
/// <param name="assembly"></param>
/// <returns></returns>
/// <remarks>Adapted from https://***.com/questions/3045033/getting-the-publickeytoken-of-net-assemblies</remarks>
private static string GetPublicKeyTokenFromAssembly(System.Reflection.Assembly assembly)
var bytes = assembly.GetName().GetPublicKeyToken();
if (bytes == null || bytes.Length == 0)
return "None";
var publicKeyToken = string.Empty;
for (int i = 0; i < bytes.GetLength(0); i++)
publicKeyToken += string.Format("0:x2", bytes[i]);
return publicKeyToken;
_contentLoaded 位可能可以通过扩展属性完成,但我需要在 C# 7.3 中编译此库的代码,因此我有一个更长的解决方法,我将其删除以免分散注意力。
然后我像这样从构造函数中调用它:
public MyWindow()
// Don't use the auto-generated initialize, because if multiple different versions
// are loaded into the process, it can try to load the resource from the wrong one.
//InitializeComponent();
AssemblySensitive_InitializeComponent("component/forms/mywindow.xaml");
// ... do more constructor stuff ...
我花了很长时间试图弄清楚发生了什么感到沮丧,所以我希望这对其他人有所帮助。
【讨论】:
【参考方案21】:对我来说,在启动期间尝试在我的应用程序中启动窗口对话框 (window.ShowDialog()) 时,在窗口的类构造函数中的 InitializeComponent 方法中引发了异常。 经过一番摸索后,我发现问题在于在 debug 目录中创建了一个 app.publish 文件夹,该文件夹仅包含应用程序 exe。删除 app.publish 文件夹可解决此异常。请参阅以下文章以防止创建此文件夹: What creates the directory "app.publish" in visual studio 2013?
【讨论】:
【参考方案22】:正如others 在他们的回答中指出的那样,如果您有一个带有关联 XAML 资源的基本控件类,然后在从基本控件继承的单独程序集中定义一个类,就会发生这种情况。这是由于 WPF 的限制而发生的。
WPF 现在是开源的,所以你可以看到我们需要解决的source code,它在IntializeComponent()
中被调用(虽然它有点难以理解)。总之,此方法获取控件的 XAML 资源的流,然后获取 loads it 和 XamlReader.LoadBaml()
。问题是当派生类与 XAML 资源文件位于不同的程序集中时,框架代码无法正确加载 XAML 资源文件。
要解决此问题,我们需要正确加载 XAML 资源流,然后手动调用 XamlReader.LoadBaml()
。这里已经有一个fewother 的答案可以做到这一点,但这是我的看法。下面的扩展方法比其他答案更简洁一些,通过反射只访问一个私有方法,并且还可以防止多次调用。
private static MethodInfo? _loadBamlMethod;
public static void InitializeComponent(this ContentControl control, string xamlResourceUri, ref bool contentLoaded)
// Ensure the control is only initialized once
if (contentLoaded) return;
contentLoaded = true;
// Use reflection to get the private XamlReader.LoadBaml() method and cache the result
_loadBamlMethod ??= typeof(XamlReader).GetMethod("LoadBaml", BindingFlags.NonPublic | BindingFlags.Static)
?? throw new InvalidOperationException("Could not find XamlReader.LoadBaml() via reflection");
// Load the XAML resource for the control
var stream = Application.GetResourceStream(new Uri(xamlResourceUri, UriKind.Relative)).Stream;
var parserContext = new ParserContext BaseUri = PackUriHelper.Create(new Uri("application://")) ;
_loadBamlMethod.Invoke(null, new object[] stream, parserContext, control, true );
然后可以这样使用。其他程序集中的控件现在可能从 BaseControl
继承而不会出现此问题。
public partial class BaseControl : UserControl
protected BaseControl()
// The resource URI here can be coped from the generated partial class
// Note that we are also re-using the _contentLoaded field defined in the generated partial class
this.InitializeComponent("/Senti.Common.PrismModules.Hmi;component/controls/basecontrol.xaml", ref _contentLoaded);
绝对应该注意,此解决方法(以及其他答案中的解决方法)通过访问 WPF 框架中的私有方法来工作,这显然不是受支持的用例。也就是说,我已经使用 .NET 5 版本的 WPF 开发和测试了这种方法,并且没有发现任何问题。微软还表示,除了错误修复等之外,WPF 框架的开发计划很少,所以这个解决方法应该是相当稳定的。
【讨论】:
以上是关于组件没有 uri 标识的资源的主要内容,如果未能解决你的问题,请参考以下文章