该组件没有uri标识的资源

时间:2011-10-04 10:14:36

标签: c# .net wpf generics mvvm

我想在我的所有Views / UserControls上创建一个Generic 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 Aplication:

Class名为"View"

using Controls;

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

我的全部想法是使用GridView,我需要DataGrid

当我运行应用程序时,我收到此错误:

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

我做错了什么?

这是正确的做法还是我离开了?

21 个答案:

答案 0 :(得分:57)

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

答案 1 :(得分:20)

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

这是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()'确实得到了对象的派生类型,而不是实现代码的类的类型。

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

答案 2 :(得分:18)

这让我头疼了3天!我在类库中有一个XAML UserControl,在我的.exe项目中有一个来自UserControl的类(只有C#)。 在我的MainWindow.xaml的xaml设计器中,当启动应用程序时,我收到错误“组件没有uri标识的资源”。 “JuanCarlosGiró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");
        }
    }
}

再次感谢“JuanCarlosGirón”!

答案 3 :(得分:11)

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

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

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

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

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

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

祝你好运,我知道这个问题是一个巨大的痛苦。异常消息和谷歌是最无益的!

答案 4 :(得分:9)

您可以尝试这种方法

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

答案 5 :(得分:8)

这里也有同样的问题。

简短版本:

复制本地必须设置为 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引用属性的复制本地的值可以避免将DialogLib.dll复制到/ bin / Debug / plugins,从而解决问题。

我们在另一个项目中遇到了类似的问题(但是有不同的错误)我们想要使用类型 TypeA ,它是在dll文件,插件和主应用程序中定义的。 复制本地设置为 true ,这导致dll文件的副本位于 ../ bin / Debug / plugins 和< EM> ../斌/调试/ 。事实证明,即使它是相同的dll文件,主应用程序文件中的 TypeA 和插件中的 TypeA 也分别被视为不同类型的类型不能交换。

答案 6 :(得分:6)

我通过放置

解决了这个问题
myusercontrol = Activator.CreateInstance<myusercontrol>(); 

在包含InitializeComponent();

之前的usercontrol的窗口的构造函数中

答案 7 :(得分:6)

  • 删除obj文件夹
  • 删除bin文件夹
  • 重建解决方案

为我工作!

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

答案 8 :(得分:5)

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

  

该组件没有uri标识的资源

<强>尝试:
清洁和重建解决方案 - 没有用。
关闭并打开Visual Studio - 无法正常工作。

<强>解决方案:
进入项目bin目录并清除所有文件 再次跑完项目,工作得很好。

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

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

答案 9 :(得分:1)

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

答案 10 :(得分:1)

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

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

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

答案 11 :(得分:1)

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

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

MyWpfApplication.Controls MyWpfApplciation.GridView MyWpfApplciation.ViewBase

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

答案 12 :(得分:1)

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

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

Fyi,对我而言,该组件抱怨&#39;在错误中是SplitComboBox。

答案 13 :(得分:0)

比关闭所有Visual Studio更快只是为了杀死任务管理器中的XDescProc.exe。

XDescProc是设计师。在关闭过程的那一刻,您将在Visual Studio中看到重新加载设计器链接。点击它,XDes将再次启动,您的“没有资源”#39;错误应该消失。

以下是您杀死设计师流程后Visual Studio所显示的链接:

enter image description here

答案 14 :(得分:0)

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

这表明有问题的文件存在某种类型的缓存....所以关闭Visual Studio,删除bin目录并重建工作。

答案 15 :(得分:0)

我也遇到了这个问题,没有任何继承问题。我只是引用了一个包含对话框并尝试创建和显示该对话框的DLL。 我有程序集解析器从特定文件夹加载程序集,结果是我在VS中添加了引用并且没有关闭Copy Local。长话短说:我的进程加载了同一个DLL的两个版本。这似乎混淆了WPF(或运行时)。一旦我清除了Copy Local并删除了额外的DLL副本,它再次正常工作。

答案 16 :(得分:0)

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

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

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

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

当我进一步测试时,我将问题范围缩小到无法加载我正在使用的单独的“库.dll”文件,该文件包含我在失败的类的.xaml文件中使用的Converter,并且在进一步研究中,存在一个问题,就是Live环境使用的是与测试环境中使用的版本不同的“ library .dll”版本,即使我的“ popup .dll”异常消息未对此进行任何提及。

作为参考,我使用Copy Local = True,但这没有给我带来问题。为了最好地调试此类问题,了解.exe搜索.dll文件的位置很有帮助。据我了解,当您在VS中运行项目时,当Copy Local = True时,.dll将在构建时与.exe复制到同一文件夹。当.exe运行在标准位置时,它将搜索.dlls与.exe所在的文件夹。可以在.exe.config文件中的探测元素中设置.exe可以查找.dll的其他位置。在下面的示例中,它也可以在相对于.exe位置的'MyDLLs'和'MyDLLs \ Core'目录中进行搜索。请注意,它不会自然搜索任何子文件夹,您必须显式指定它们。我相信它也可以搜索GAC,但目前我对GAC的了解很少。

<configuration>
 ... 

   <runtime>  
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
         <probing privatePath="MyDLLs;MyDLLs\Core;"/>
      </assemblyBinding>
   </runtime>  
</configuration>

答案 17 :(得分:0)

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

答案 18 :(得分:0)

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

enter image description here

enter image description here

答案 19 :(得分:0)

感谢此主题中的所有提示。我认为我自己对此错误的更改又是出于稍有不同的原因,所以我将在此处发布以防万一。

在我的情况下,调用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资源,而不是其应有的资源。

这并不完美,但是我咨询了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 ...
}

我花了很长时间沮丧地想知道发生了什么事,所以我希望这可以帮助其他人。

答案 20 :(得分:0)

对我来说,在启动期间尝试在我的应用程序中启动窗口对话框 (window.ShowDialog()) 时,在窗口类构造函数的 InitializeComponent 方法中抛出了异常。 经过多次摸索,我发现问题是在 debug 目录中创建了一个 app.publish 文件夹,该文件夹仅包含应用程序 exe。删除 app.publish 文件夹解决了此异常。请参阅以下文章以防止创建此文件夹: What creates the directory "app.publish" in visual studio 2013?