该组件没有由 uri 标识的资源

发布于 2024-12-07 16:32:32 字数 1576 浏览 0 评论 0原文

我想创建一个通用数据网格以在我的所有视图/用户控件上使用。

这是我的结构:

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 应用程序":

调用了 “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'."

我做错了什么?

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

I want to create a Generic DataGrid to use on all my Views/UserControls.

This is my structure:

Class Library called "Core":

Class called "ViewBase":

public class ViewBase : UserControl
{
    public ViewBase()
    {
    }   

    //Rest of Methods and Properties
}

Class Library called "Controls":

UserControl Called "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>

Code Behind:

using Core;

public partial class GridView : ViewBase
{
    public GridView ()
    {
        InitializeComponent();
    }
}

Then is the WPF Aplication called "WPFApp":

Class called "View":

using Controls;

public class View : GridView
{
    public View()
    {
        InitializeComponent();
    }
}

My whole idea is to use GridView where i need a DataGrid.

When i run the application i get this error:

"The component 'WpfApp.View' does not have a resource identified by the URI '/Controls;component/GridView.xaml'."

What am i doing wrong?

Is this the correct approach or am i way off?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(22

梦在深巷 2024-12-14 16:32:33

当我在两个解决方案中打开同一个项目时,就会发生这种情况。修改一个项目中的基本控件会导致另一个项目出现此问题。如果关闭和打开不起作用,则删除“C:\Users...\AppData\Local\Microsoft\VisualStudio\12.0\Designer\ShadowCache”中的所有文件夹

Happend to me when I had the same project opened in two solutions. Modifying the base-control in one project cause the other project to have this problem. If closing and opening doesn't work, then delete all the folders in "C:\Users...\AppData\Local\Microsoft\VisualStudio\12.0\Designer\ShadowCache"

挥剑断情 2024-12-14 16:32:33

关闭并重新打开窗口时也会发生这种情况。所以它也可能与包和/或 dll 无关。
感谢 PainElemental 发布的解决方案,我解决了这个问题,恕我直言,该解决方案被低估了:

namespace MyNamespace
{
  public partial class MyDialog : Window
  {
    public MyDialog(ExcelReference sheetReference)
      {
        this.LoadViewFromUri("/MyApp;component/mynamespace/mydialog.xaml");
      }
  }
}

LoadViewFromUri 是作为扩展实现的,正如 PainElemental 所写。
最疯狂的是,我还在同一个项目中编写了其他窗口,没有遇到任何问题。
谢谢PainElemental,你结束了我旷日持久的痛苦!

This can happen also when closing and reopening a window. So it could also have nothing to do with packages and/or dlls.
I solved the problem thanks to the solution posted by PainElemental, which is IMHO underrated:

namespace MyNamespace
{
  public partial class MyDialog : Window
  {
    public MyDialog(ExcelReference sheetReference)
      {
        this.LoadViewFromUri("/MyApp;component/mynamespace/mydialog.xaml");
      }
  }
}

LoadViewFromUri is implemented as an extension, as PainElemental wrote.
The craziest is that I also wrote in the same project other windows without encountering any problem.
Thank you PainElemental, you ended my protracted pain!

单身情人 2024-12-14 16:32:33

当我从在其他计算机上运行的已安装产品中单击特定菜单选项时,我开始不断看到“该组件没有由 uri 标识的资源”错误。我尝试卸载该产品,确保其文件确实消失,然后重新启动并重新安装该产品。问题依然存在。我删除了 %TEMP% 目录的内容,问题就消失了。

I started consistently seeing a "the component does not have a resource identified by the uri" error when I clicked a particular menu choice from an installed product that was working on other computers. I tried uninstalling the product, making sure its files really were gone, rebooting, and reinstalling the product. The problem remained. I deleted the contents of my %TEMP% directory, and the problem ceased.

我不咬妳我踢妳 2024-12-14 16:32:33

正如 其他人在他们的答案中指出的那样,如果您有一个带有关联 XAML 资源的基本控件类,并且然后在一个单独的程序集中定义一个从基本控件继承的类。发生这种情况是由于 WPF 的限制。

WPF 现在是开源的,因此您可以看到 源代码,我们需要解决在 IntializeComponent() 中调用的问题(虽然有点难以理解)。总之,此方法获取控件的 XAML 资源的流,然后 加载它 XamlReader.LoadBaml()。问题在于,当派生类与 XAML 资源文件位于不同的程序集中时,框架代码无法正确加载 XAML 资源文件。

要解决此问题,我们需要正确加载 XAML 资源流,然后手动调用 XamlReader.LoadBaml()。还有一些 其他< /a> 这里的答案已经完全做到了这一点,但这是我的看法。下面的扩展方法比其他答案更简洁,通过反射仅访问一个私有方法,并且还可以防止多次调用。

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 框架的开发计划很少,因此这个解决方法应该相当稳定。

As others have pointed out in their answers, this will happen if you have a base control class with an associated XAML resource, and then define a class in a separate assembly that inherits from the base control. This happens because of a limitation in WPF.

WPF is open source now, so you can see the source code that we need to work around that is called in IntializeComponent() (though it's a bit difficult to follow). In summary, this method get a stream for the control's XAML resource and then loads it with XamlReader.LoadBaml(). The issue is that the framework code does not load the XAML resource file correctly when the derived class is in a different assembly than the XAML resource file.

To work around this issue we need to load the XAML resource stream correctly and then call XamlReader.LoadBaml() manually. There are a few other answers here already that do exactly this, but here's my take on it. The following extension method is a bit more concise than the other answers, accesses only one private method via reflection, and also guards against multiple calls.

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 });
}

Which can then be used like this. Controls in other assemblies may now inherit from BaseControl and not see this issue.

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);
    }
}

It should definitely be noted that this workaround (as well as the ones in other answers) work by accessing a private method within the WPF framework, which is obviously not a supported use case. That said, I have developed and tested this approach with the .NET 5 version of WPF and not seen any issues. Microsoft has also said that very little development is planned for the WPF framework other than bugfixes etc, so this workaround should be fairly stable.

转角预定愛 2024-12-14 16:32:33

比关闭所有 Visual Studio 更快的方法是在任务管理器中杀死 XDescProc.exe。

XDescProc 是设计者。进程关闭后,您将在 Visual Studio 中看到“重新加载设计器”链接。单击该按钮,XDes 将再次启动,并且您的“无资源”错误应该消失。

以下是终止设计器进程后 Visual Studio 显示的链接:

在此处输入图像描述

Quicker than closing all of Visual Studio is just to kill XDescProc.exe in your task manager.

XDescProc is the designer. The moment the process is closed you'll see a Reload the designer link in visual studio. Click that and XDes will be started again and your 'no resource' error should be gone.

Here's the link visual studio shows after you kill the designer process:

enter image description here

乖不如嘢 2024-12-14 16:32:33

我不小心通过重命名/复制操作删除了用户控件。当我从版本控制恢复项目文件、xaml 文件和 .cs 时,该错误开始在设计工作室中发生,该控件被错误地删除/重命名。

这表明相关文件上有某种类型的缓存......因此关闭 Visual Studio,删除 bin 目录并重建工作。

I had accidently deleted a user control via a rename/copy action. When I reinstated the project file and the xaml file and .cs from version control this error started happening in the design studio for that control which had mistakenly been deleted/renamed.

That suggested some type of cache on the file in question....so closing Visual Studio, deleting the bin directory and rebuilding worked.

苯莒 2024-12-14 16:32:33

遵循 PainElemental 的解决方案(澄清一下,对于他的代码,我的 ClassLibrary1 是不带 .dll 扩展名的 .dll 名称),这是我的场景,以防它帮助任何人将其特定错误消息链接到问题:

我使用 dll 来加载和运行用户控件作为自己的弹出窗口进入主程序。 PainElemental 的解决方案大部分工作正常,但我的“popup.dll”中的 3 个类中有 1 个无法正确加载。我会得到一个带有 2 个内部异常的异常,例如:

mscorlib InvokeMethod...;
WpfXamlLoader.Load...为...StaticResourceExtension...提供值...;
ResolveBamlType ....方法或操作未实现。

就我而言,我确认它将加载新的 URI 并在测试中工作,但是当我尝试在实时环境中运行它时,LoadViewFromUri() 中会出错。

当我进一步测试时,我将问题范围缩小到无法加载我正在使用的单独的“库 .dll”文件,该文件包含我在失败的类的 .xaml 文件中使用的转换器,并进行进一步研究那里的问题是,实时环境使用的“library.dll”版本与我在测试环境中使用的不同,即使来自“popup.dll”的异常消息没有提及这一点。

作为参考,我使用 Copy Local=True 这并没有给我带来问题。为了最好地调试此类问题,了解 .exe 搜索 .dll 文件的位置会很有帮助。据我了解,当您在 VS 中运行项目时,当 Copy Local=True 时,.dll 在构建时会被复制到与 .exe 相同的文件夹中。当 .exe 运行时,它将搜索 .dll 的标准位置是与 .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>

Followed PainElemental's solution (to clarify, for his code the ClassLibrary1 for me was the .dll name without the .dll extension), here's my scenario in case it helps anyone link their specific error messages to the problem:

I use dll's to load and run usercontrols into a main program as their own popup windows. PainElemental's solution was mostly working , but 1 of the 3 classes in my "popup .dll" wouldn't load properly. I would get an exception with 2 inner exceptions, like:

mscorlib InvokeMethod...;
WpfXamlLoader.Load...Provide value on...StaticResourceExtension...;
ResolveBamlType....method or operation is not implemented.

In my case, I confirmed it would load the new URI and work in testing, but when I tried to run it over in my Live environment it would error in LoadViewFromUri().

As I tested further, I narrowed down the issue to not being able to load a separate "library .dll" file I was using which contained a Converter I was using in the .xaml file of the class which was failing, and on further research the issue there was that the Live environment was using a different "library .dll" version than I was using in my test environment, even though the exception message from my "popup .dll" did not make any mention of that.

For reference, I use Copy Local=True and that didn't give me issues. To best debug these kinds of issues, an understanding of the locations where .dll files are searched for by the .exe is helpful. As I understand it, when you are running projects in VS, when Copy Local=True the .dlls get copied to the same folder as the .exe when it is Built. When the .exe is run the standard location it will search for .dlls is the same folder as the .exe. Additional locations that the .exe can look for .dlls can be set in the .exe.config file, in the probing element. In the below example, it can also search in a 'MyDLLs' and the 'MyDLLs\Core' directory relative to the .exe's location. Note that it will not naturally search any subfolders, you have to specify them explicitly. I believe it also searches the GAC, but I currently have minimal knowledge concerning GAC.

<configuration>
 ... 

   <runtime>  
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         <probing privatePath="MyDLLs;MyDLLs\Core;"/>
      </assemblyBinding>
   </runtime>  
</configuration>
地狱即天堂 2024-12-14 16:32:33

您好,解决此问题的方法是将 xaml 用户控件重命名为 InitializeComponent() 上的所有小型大写字母...

输入图像此处描述

此处输入图片描述

Hi the way solve this problem was to rename the xaml usercontrol to all smallcaps on InitializeComponent()...

enter image description here

enter image description here

爱殇璃 2024-12-14 16:32:33

对于我来说,当尝试在启动期间在应用程序中启动窗口对话框 (window.ShowDialog()) 时,窗口类构造函数中的 InitializeComponent 方法引发了异常。
经过一番绞尽脑汁后,我发现问题是在 debug 目录中创建了一个 app.publish 文件夹,其中仅包含应用程序 exe。删除 app.publish 文件夹解决了此异常。请参阅以下文章以防止创建此文件夹:
什么在 Visual Studio 中创建目录“app.publish” 2013年?

For me, when trying to launch a window dialog (window.ShowDialog()) in my application during startup, the exception was thrown in the InitializeComponent method in the window's class constructor.
After much head scratching I had discovered that the issue was that an app.publish folder was getting created in the debug directory, which contained the application exe only. Deleting the app.publish folder resolved this exception. See the following article to prevent this folder from getting created:
What creates the directory "app.publish" in visual studio 2013?

仅此而已 2024-12-14 16:32:32

令人沮丧的是,我确实遇到了这个错误,并花了很长时间试图找出原因。对我来说,它曾经有效,但后来我对派生控件的 XAML 做了一些非常小的更改,编译器开始给出该错误消息。
简短的解决方案,省去很多时间来尝试解决它:关闭 Visual Studio 并重新打开它,重新编译,问题神奇地消失了! (这是VS2012专业版)
只是添加了这一点,以防任何阅读的人兜圈子试图找到他们的代码不存在的问题。可能值得首先尝试“IT Crowd 解决方案”。

Frustratingly, I had exactly this error and spent forever trying to work out the cause. For me, it was once working but then I made some very minor changes to the XAML of the derived control, and the compiler started giving that error message.
Short solution, cutting out many hours of trying to figure it out: shut down Visual Studio and re-opened it, recompiled, problem magically went away! (This is VS2012 Pro)
Just added this in case anyone reading is going round in circles trying to find a non-existent problem with their code. Might be worth trying the "IT Crowd solution" first.

难以启齿的温柔 2024-12-14 16:32:32

这让我头疼了三天!我的类库中有一个 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”!

This gave me headaches for 3 days! I have a XAML UserControl in a class library and a class (only C#) that derives from the UserControl in my .exe project.
In xaml designer of my MainWindow.xaml and when starting the application, I got the error "component does not have a resource identified by the uri".
The answer of "Juan Carlos Girón" finally lead me to the solution:

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
            }
        }
    }
}

and called that from by UserControl's .cs file:

namespace ClassLibrary1
{
    public partial class MyUserControl : UserControl
    {
        public MyUserControl()
        {
            //InitializeComponent();
            this.LoadViewFromUri("/ClassLibrary1;component/myusercontrol.xaml");
        }
    }
}

Thanks again to "Juan Carlos Girón"!

旧时光的容颜 2024-12-14 16:32:32

您收到此错误的原因是因为(在 VS 2010 中)实现的 InitializeComponent 方式将始终在派生类的程序集中进行搜索。

这是InitializeComponent:

/// <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()”确实获取对象的派生类型,而不是实现代码的类的类型。

附言。这是一个错误吗?我不知道...

The reason you are getting this error is because the way InitializeComponent that is implemented (in VS 2010) will always search in the derived class's assembly.

Here is InitializeComponent:

/// <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
}

The line where it looks up your XAML resource is System.Windows.Application.LoadComponent(this, resourceLocator). And this most probably fails because equivalent of 'this.GetType().Assembly' is used to determine which assembly to search for the resource identified by the relative Uri. And 'this.GetType()' does get the derived type of the object, not the type of the class where the code is implemented.

PS. Is this a bug? I do not know...

如梦亦如幻 2024-12-14 16:32:32

您可以尝试这种方法,

我创建了自己的 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
        }
    }

You can try this approach

I created my own InitializeComponent() and I called this way

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
        }
    }
給妳壹絲溫柔 2024-12-14 16:32:32

这里同样的问题。

简短版本:

复制本地必须设置为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,从而解决问题。

我们在另一个项目中遇到了类似的问题(但错误不同),我们想要使用类型 TypeA,该类型是在 dll 文件、插件和主应用程序中定义的。 Copy Local 设置为 true,这导致 dll 文件的副本位于 ../bin/Debug/plugins 和 < em>../bin/Debug/。事实证明,即使是同一个 dll 文件,主应用程序文件中的 TypeA 和插件中的 TypeA 分别被视为不同的类型,因为类型可以不可以交换。

Same problem here.

Short version:

Copy Local has to be set to False!

Long version:

We developed a WPF solution (MVVM, 20 projects) and implemented a plug-in system. Our /bin/Debug directory contains the executable, some dll files and a plugin directory that contains the plugins.
There is one project "DialogLib" (Class library, kind of dialog) that defines a window (the view), the ViewModel, Model and some interfaces. One of the plugins used one of the interfaces of DialogLib. The window itself is opened by the main application.

To use the interface of the 'DialogLib' library in the plugin we had to add a project reference of DialogLib to the plugins project references. When the application was started, the plugins were loaded. If the user then selects a menu item, the window should open. At this point the error "... component does not have a resource identified by the URI ..." occured when the windows code behind tried to execute its InitializeComponent().

Where's the problem?

The problem is, that, when we built the solution VS has created the DialogLib.dll correctly and copied it to /bin/Debug/. This is because the main application file wants to open the window. But DialogLib.dll was also copied to /bin/Debug/plugins because one of the plugins referenced it to use one of the interfaces defined in DialogLib.dll. So what?

When the plugin is loaded at runtime it uses the interface defined in /bin/Debug/plugins/DialogLib.dll. and the main application file tries to open the window defined in /bin/Debug/DialogLib.dll. Although the files are identical, VS runs into trouble. Setting the value of Copy Local of the DialogLib reference properties of the plugins references avoids copying DialogLib.dll to /bin/Debug/plugins and thus solves the problem.

We had a similar same problem (but different error) in another project where we wanted to use a type TypeA, that was defined in a dll file, in a plugin and in the main application. Copy Local was set to true which caused a copy of the dll file to be located in ../bin/Debug/plugins and in ../bin/Debug/. It turned out that, even though it was the same dll file, the TypeA in the main app file and TypeA in the plugin were treated as different types respectively as types which could not be exchanged.

风吹雨成花 2024-12-14 16:32:32

我正在做一些非常相似的事情,但得到了相同的结果。我有一个 C# 类库,其中包含一个名为“UsageControl”的 WPF 控件(带有附带的 xaml.cs 文件的 xaml)。在一个单独的 C# 项目(即单独的 dll)中,我创建了一个 C# CPUUsageControl,它继承自UsageControl,但在其上添加了自己的旋转。当我尝试在我的视图之一上使用 CpuUsageControl 时,我遇到了与您相同的错误。

我所做的修复是在单独的程序集中,而不是创建从基本控件继承的类,而是创建了一个包含基本控件的新 WPF 控件。然后,我将 CpuUsage 类中包含的所有逻辑放入 WpfCpuUsageControl 的代码后面。我能够使用这个对象是我所有其他控件都很好。

对于您的控件“GridView”,我将创建一个新的WPF用户控件,将其命名为GridView并使其包含“ViewBase”作为网格控件的内容。 ViewBase 的内容放入 DataGrid 中,如下所示:

<UserControl....>
    <Grid>
        <ViewBase name="vBase">
            <DataGrid name="dGrid" />
        </ViewBase>
    </Grid>
</UserControl>

我也不清楚您需要 ViewBase 直接从 UserControl 继承。如果您想要的只是让控件具有某些属性和方法,为什么不直接创建一个 BaseControl 类(除了对象之外不继承任何人)并让未来的控件继承它。也许抽象基类或接口就是您所追求的。

对于 MVVM WPF 项目,我通常有一个 BaseViewModel 为我实现 INotifyPropertyChanged,因此我不必在任何地方都执行相同的代码。

祝你好运,我知道解决这个问题是一个巨大的痛苦。异常消息和谷歌是最没有帮助的!

I was doing something very similar with the same result. I had one C# class library that contained a WPF control called UsageControl (xaml with accompanying xaml.cs file). In a separate C# project(i.e. separate dll) I created a C# class CPUUsageControl which inherited from UsageControl, but put its own spin on it. When I tried to use the CpuUsageControl on one of my views I got the same error you did.

What I did to fix that was in my seperate assembly, instead of creating a class that inherited from the base control, i created a new WPF Control that contained the base control. I then put all of the logic that was contained in the CpuUsage class into the WpfCpuUsageControl's code behind. I was able to use this object is all of my other controls just fine.

For your Control "GridView" i would create a new WPF user control, call it GridView and make it contain a "ViewBase" as the content of the Grid control.Inside of the ViewBase's content put in your DataGrid, like this:

<UserControl....>
    <Grid>
        <ViewBase name="vBase">
            <DataGrid name="dGrid" />
        </ViewBase>
    </Grid>
</UserControl>

It is also not apparent to me that you need ViewBase to inherit from UserControl directly. If all you want are for your controls to have certain properties and method why not just make a BaseControl class (that does not inherit from anyone but object) and have future controls inherit from it. Perhaps an abstract base class or interface is what you're after.

For MVVM WPF projects, I typically have a BaseViewModel which implements INotifyPropertyChanged for me so I don't have to do that same code everywhere.

Best of luck, I know this problem was a huge pain to figure out. The exception message and google are most unhelpful!

沫离伤花 2024-12-14 16:32:32
  • 删除 obj 文件夹
  • 删除 bin 文件夹
  • 重建解决方案

对我有用!

此外,如果您使用 Assembly.LoadFile 加载程序集,请检查 AppDomain.CurrentDomain.GetAssemblies() 以查找当前 AppDomain 中的重复程序集。因为在 WPF UserControl 自动生成的代码中,将使用其相对 URI 加载组件。由于当前 AppDomain 中存在重复的程序集,因此应用程序不知道要使用哪一个。

  • Delete obj folder
  • Delete bin folder
  • Rebuild solution

Worked for me!

Also if you are loading assemblies using Assembly.LoadFile, check out AppDomain.CurrentDomain.GetAssemblies() for duplicate assemblies in the current AppDomain. Because in auto-generated code of WPF UserControl, the component will be loaded using its relative URI. And since there are duplicate assemblies in the current AppDomain, application doesn't know which one to use.

感情废物 2024-12-14 16:32:32

我通过在

myusercontrol = Activator.CreateInstance<myusercontrol>(); 

InitializeComponent(); 行之前放置包含用户控件的窗口的构造函数来解决此问题

I resolved this by placing

myusercontrol = Activator.CreateInstance<myusercontrol>(); 

in the constructor of the window containing the usercontrol before the InitializeComponent(); line

2024-12-14 16:32:32

我在使用 Visual Studio 2013 时收到了同样的错误。

该组件没有由 uri 标识的资源

已尝试:
清理和重建解决方案 - 不起作用。
关闭并打开 Visual Studio - 不起作用。

解决方案:
进入项目 bin 目录并清除所有文件。
再次运行该项目并运行良好。

打开包管理器控制台,该控制台将在解决方案的根目录中打开,然后运行以下 powershell 命令:

Get-ChildItem -inc bin,obj -recurse | Remove-Item -recurse -force -EA SilentlyContinue

I received the same error when using Visual Studio 2013.

The component does not have a resource identified by the uri

Tried:
Cleaning and rebuilding the solution - did not work.
Closing and opening Visual Studio - did not work.

Solution:
Went into the projects bin directory and cleared out all files.
Ran the project again and worked fine.

Open the Package Manager Console which will open in the root directory of your Solution and run the following powershell command:

Get-ChildItem -inc bin,obj -recurse | Remove-Item -recurse -force -EA SilentlyContinue
浅忆流年 2024-12-14 16:32:32

感谢该线程中的所有提示。我认为我自己对这个错误的变体又是出于稍微不同的原因,所以我会在这里发布以防万一它有用。

在我的情况下,调用 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,但找不到它(因为它首先找到了程序集的旧版本),然后引发异常。或者也许它找到了一些东西,但也许它从碰巧也加载的程序集的旧版本或新版本中提取了与其应有的不同的 XAML 资源。

它并不完美,但我咨询过 Pack URI 规范,并通过编写我自己的扩展方法来解决这个问题,该方法确保使用适当的版本和公钥令牌找到程序集,而不是简单地找到该程序集程序集短名称。

如果它对其他人有用,这是我最终得到的简化版本。

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 ...
}

我花了很长时间试图弄清楚发生了什么,所以我希望这对其他人有帮助。

Thanks for all the tips in this thread. I think my own variation of this error was for a slightly different reason again, so I'll post here in case it's of use.

In my situation, the error occurred when invoking window.ShowDialog(). More specifically, my window is defined in a separate class library assembly (let's call it AssemblyA.dll).

I have multiple versions of AssemblyA which are used in various products, some of which are plugins and some aren't. In short, the consequence is that the process might end up loading several different strong-named versions of AssemblyA. So there are duplicate assemblies in the app domain as @VahidN pointed out, but they're strictly differently versioned assemblies which are meant to be there, and merely share the same AssemblyShortName.

WPF's auto-generated code for InitializeComponent() looks like this:

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
}

It's only referring to the short name of AssemblyA, and not to the specific version or public key token of AssemblyA in which the InitializeComponent() method is running. The consequence is that the code just seems to find the first AssemblyA assembly loaded into the process, searches for the XAML, can't find it (because it's found an older version of the assembly first), and then throws an exception. Or perhaps it finds something but maybe it's pulled a different XAML resource than what it's meant to have, from either an older or newer version of the assembly that happens to also be loaded.

It's not perfect, but I've consulted the Pack URI specification, and worked around this by writing my own extension method that makes sure the assembly is found with the appropriate version and public key token, rather than simply the AssemblyShortName.

In case it's of use for others, here's a simplified version of what I've ended up with.

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(
quot;/{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;
}

The _contentLoaded bit could probably be done with extension properties, but I need the code for this library to compile in C# 7.3 so I have a much longer workaround which I removed so as not to distract.

Then I call it from the constructor like this:

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 ...
}

I spent ages getting frustrated trying to figure out what was going on, so I hope this helps someone else out there.

三寸金莲 2024-12-14 16:32:32

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

我的所有命名空间都在一个程序集中。 使用了一个公共的父命名空间

所以我对所有的例如MyWpfApplication.Controls
MyWpfApplciation.GridView
MyWpfApplciation.ViewBase

因为所有这些 ControlsGridViewViewBase 都与现有的System 发生冲突> 或基于 System.Windows.Controls 的命名空间和类声明。因此,我确保在我的项目中引用了正确的 MyWpfApplication.*

@Willem, this seems perfectly OK to me. In fact I tried this and it worked in my case. I used ListBox instead of DataGrid (but that shouldnt matter).

All my namespaces were in one assembly. So I used a common parent namespace for all e.g.

MyWpfApplication.Controls
MyWpfApplciation.GridView
MyWpfApplciation.ViewBase

Coz all these Controls, GridView, ViewBase are clashing with existing System or System.Windows.Controls based namespace and class declarations. So I made sure I referred correct ones MyWpfApplication.* in my project.

娜些时光,永不杰束 2024-12-14 16:32:32

我刚刚也遇到了这个问题,没有任何继承问题。我只是引用一个包含对话框的 DLL,并尝试创建并显示该对话框。
我有程序集解析器,可以从特定文件夹加载程序集,结果发现我已在 VS 中添加了引用,并且没有关闭“复制本地”。长话短说:我的进程加载了同一个 DLL 的两个版本。这似乎让 WPF(或运行时)感到困惑。当我清除了 Copy Local 并删除了多余的 DLL 副本后,它又恢复正常了。

I just ran into this problem as well without any inheritance issues. I was just referencing a DLL that contained a dialog and trying to create and display that dialog.
I have assembly resolver that loads assemblies from a specific folder and it turns out that I had added the reference in VS and had not turned off Copy Local. Long story short: my process had loaded two versions of that same DLL. This seems to confuse WPF (or the runtime). Once I cleared the Copy Local and deleted the extra DLL copies, it worked fine again.

身边 2024-12-14 16:32:32

重命名 xaml 文件后出现此错误。反转重命名解决了问题。

此外,我发现 App.xaml 中对 xaml 文件名的引用未更新(StartupUri),但将其重命名为当前名称并不能解决问题(但也许对您有用)。基本上,我无法重命名 xaml 文件。

仅供参考,对我来说,错误中“抱怨”的组件是 SplitComboBox。

I got this error after renaming a xaml file. Reversing the renaming solved the problem.

Furthermore, I found that a reference to the xaml file name in App.xaml was not updated (the StartupUri), but renaming that to the current name didn't resolve the problem (but maybe it does for you). Basically, I can't rename the xaml file.

Fyi, for me, the component 'complaining' in the error was SplitComboBox.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文