【问题标题】:The component does not have a resource identified by the uri组件没有 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'."

我做错了什么?

这是正确的方法还是我离题了?

【问题讨论】:

    标签: c# .net wpf generics mvvm


    【解决方案1】:

    @Willem,这对我来说似乎完全没问题。事实上,我试过这个,它在我的情况下有效。我使用ListBox 而不是DataGrid(但这不重要)。

    我所有的命名空间都在一个程序集中。所以我为所有人使用了一个共同的父命名空间,例如

    MyWpfApplication.Controls MyWpfApplciation.GridView MyWpfApplciation.ViewBase

    因为所有这些 ControlsGridViewViewBase 都与现有的基于 SystemSystem.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 文件、插件和主应用程序中定义的类型 TypeACopy 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};V{version};{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://stackoverflow.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 itXamlReader.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 框架的开发计划很少,所以这个解决方法应该是相当稳定的。

                                  【讨论】:

                                    猜你喜欢
                                    • 2013-07-09
                                    • 2019-04-02
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2019-04-11
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2012-03-16
                                    • 1970-01-01
                                    相关资源
                                    最近更新 更多