The component does not have a resource identified by the uri

后端 未结 20 971
悲哀的现实
悲哀的现实 2020-12-01 07:33

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

This is my structure:

Class Library called \"Core\":

相关标签:
20条回答
  • 2020-12-01 07:48

    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.

    0 讨论(0)
  • 2020-12-01 07:49

    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.

    0 讨论(0)
  • 2020-12-01 07:49

    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"

    0 讨论(0)
  • 2020-12-01 07:50

    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.

    0 讨论(0)
  • 2020-12-01 07:50

    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($"/{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.

    0 讨论(0)
  • 2020-12-01 07:51

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

    0 讨论(0)
提交回复
热议问题