web-dev-qa-db-fra.com

Le composant n'a pas de ressource identifiée par l'URI

Je souhaite créer un DataGrid générique à utiliser sur tous mes Views/UserControls.

Ceci est ma structure:

Class Library appelé "Core":

Class appelé "ViewBase":

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

    //Rest of Methods and Properties
}

Class Library appelé "Controls":

UserControl appelé "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 Derrière:

using Core;

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

Ensuite, l'application WPF appelée "WPFApp":

Class appelé "View":

using Controls;

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

Toute mon idée est d'utiliser GridView où j'ai besoin d'un DataGrid.

Quand je lance l'application, j'obtiens cette erreur:

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

Qu'est-ce que je fais mal?

Est-ce la bonne approche ou suis-je bien parti?

39
Willem

Je faisais quelque chose de très similaire avec le même résultat. J'avais une bibliothèque de classe C # contenant un contrôle WPF appelé UsageControl (xaml avec le fichier xaml.cs correspondant). Dans un projet C # distinct (c’est-à-dire une dll séparée), j’ai créé un C # class CPUUsageControl qui a hérité de UsageControl, mais lui a donné sa propre tournure. Lorsque j'ai essayé d'utiliser CpuUsageControl sur l'un de mes points de vue, j'ai eu la même erreur que vous.

Ce que j'ai fait pour résoudre ce problème se trouvait dans mon assemblée séparée, au lieu de créer une classe héritée du contrôle de base, j'ai créé un nouveau contrôle WPF qui contient contient le contrôle de base. J'ai ensuite mis toute la logique contenue dans la classe CpuUsage dans le code de WpfCpuUsageControl. J'ai pu utiliser cet objet et tous mes autres contrôles vont très bien.

Pour votre contrôle "GridView", je créerais un nouveau contrôle utilisateur WPF , appelez-le GridView et faites-le contient a "ViewBase" en tant que contenu du contrôle Grid.Inside du contenu de ViewBase placé dans votre DataGrid, comme ceci:

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

Il ne m’apparaît pas non plus que vous ayez besoin que ViewBase hérite directement de UserControl. Si tout ce que vous voulez, c’est que vos contrôles aient certaines propriétés et certaines méthodes, pourquoi ne pas créer une classe BaseControl (qui n’héritera de personne d’autre qu’un objet) et en fera hériter les futurs contrôles. Vous recherchez peut-être une classe de base abstraite ou une interface.

Pour les projets WPF MVVM, j'ai généralement BaseViewModel qui implémente INotifyPropertyChanged pour moi, de sorte que je n'ai pas à faire le même code partout.

Bonne chance, je sais que ce problème était une énorme douleur à résoudre. Le message d'exception et Google sont des plus inutiles!

11

Frustrement, j'ai eu exactement cette erreur et j'ai passé des heures à essayer de trouver la cause. Pour moi, cela fonctionnait jadis, mais j’ai ensuite apporté quelques modifications très mineures au XAML du contrôle dérivé, et le compilateur a commencé à donner ce message d’erreur . bas Visual Studio et rouvert, recompilé, problème est parti comme par magie! (Ceci est VS2012 Pro) Je l’ajoute au cas où une personne lisant tournerait en rond en essayant de trouver un problème inexistant avec son code. Cela vaut peut-être la peine d’essayer d’abord la «solution IT Crowd».

56
HughHughTeotl

Vous obtenez cette erreur parce que la manière dont InitializeComponent est implémenté (dans VS 2010) recherchera toujours dans l'assembly de la classe dérivée.

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

La ligne où il recherche votre ressource XAML est System.Windows.Application.LoadComponent (this, resourceLocator). Et cela échoue très probablement parce que l’équivalent de 'this.GetType (). Assembly' est utilisé pour déterminer quel Assembly rechercher la ressource identifiée par le Uri relatif. Et 'this.GetType ()' obtient le type dérivé de l'objet, pas le type de la classe où le code est implémenté.

PS. Est-ce un bug? Je ne sais pas...

19
Tim Lovell-Smith

Cela m'a donné des maux de tête pendant 3 jours! J'ai un UserControl XAML dans une bibliothèque de classes et une classe (uniquement en C #) qui dérive du contrôle UserControl dans mon projet .exe . Dans le concepteur xaml de mon MainWindow.xaml et lors du démarrage de l'application, j'ai le composant "error" n'a pas de ressource identifiée par l'uri ". La réponse de" Juan Carlos Girón "m'a finalement conduit à la 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
            }
        }
    }
}

et appelé cela à partir du fichier .cs de UserControl:

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

Merci encore à "Juan Carlos Girón"!

18
PainElemental

Vous pouvez essayer cette approche

J'ai créé ma propre InitializeComponent() et j'ai appelé de cette façon

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

Même problème ici.

Version courte:

Copy Local doit être réglé sur False!

Version longue:

Nous avons développé une solution WPF (MVVM, 20 projets) et mis en place un système plug-in. Notre répertoire/bin/Debug contient l'exécutable, des fichiers dll et un répertoire de plugins contenant les plugins . Il existe un projet "DialogLib" (bibliothèque de classes, type de dialogue) qui définit une fenêtre (la vue), le ViewModel, Model et quelques interfaces. L'un des plugins utilisait l'une des interfaces de DialogLib. La fenêtre elle-même est ouverte par l'application principale.

Pour utiliser l'interface de la bibliothèque 'DialogLib' dans le plugin, nous avons dû ajouter une référence de projet de DialogLib aux références de projet des plugins. Lorsque l'application a été démarrée, les plugins ont été chargés. Si l'utilisateur sélectionne ensuite un élément de menu, la fenêtre devrait s'ouvrir. À ce stade, l'erreur "... le composant n'a pas de ressource identifiée par l'URI ..." s'est produite lorsque le code Windows situé derrière a tenté d'exécuter InitializeComponent ().

Où est le problème?

Le problème est que, lorsque nous avons créé la solution, VS a créé correctement le fichier DialogLib.dll et l’a copié dans/bin/Debug /. En effet, le fichier principal de l’application veut ouvrir la fenêtre. Mais DialogLib.dll a également été copié dans/bin/Debug/plugins, car l’un des plugins l’a référencé pour utiliser l’une des interfaces définies dans DialogLib.dll. Et alors?

Lorsque le plug-in est chargé à l'exécution, il utilise l'interface définie dans /bin/Debug/plugins/DialogLib.dll. et le fichier principal de l’application essaie d’ouvrir la fenêtre définie dans /bin/Debug/DialogLib.dll. Bien que les fichiers soient identiques, VS rencontre des problèmes. La définition de la valeur Copy Local des propriétés de référence DialogLib des références de plug-ins évite de copier DialogLib.dll dans/bin/Debug/plugins et résout donc le problème.

Nous avons eu le même problème (mais une erreur différente) dans un autre projet où nous voulions utiliser un type TypeA, défini dans un fichier dll, dans un plugin et dans l'application principale. Copy Local a été défini sur true, ce qui a permis de placer une copie du fichier dll dans ../bin/Debug/plugins et dans ../bin/Debug/. Il s’est avéré que, même s’il s’agissait du même fichier DLL, les fichiers TypeA du fichier principal de l’application et TypeA du plug-in étaient traités comme des types différents, respectivement, comme des types ne pouvant pas être échangés. 

7
ooorndtski

J'ai résolu ceci en plaçant 

myusercontrol = Activator.CreateInstance<myusercontrol>(); 

dans le constructeur de la fenêtre contenant le contrôle utilisateur avant la ligne InitializeComponent();

6
Darren
  • Supprimer le dossier obj
  • Supprimer le dossier bin
  • Reconstruire la solution

Travaillé pour moi!

De même, si vous chargez des assemblys à l'aide de Assembly.LoadFile, recherchez AppDomain.CurrentDomain.GetAssemblies() pour les assemblys en double dans le domaine AppDomain actuel. Dans le code généré automatiquement par WPF UserControl, le composant sera chargé à l'aide de son URI relatif. Et comme il existe des assemblys en double dans l'AppDomain actuel, l'application ne sait pas lequel utiliser.

6
VahidN

J'ai reçu la même erreur lors de l'utilisation de Visual Studio 2013.

Le composant n'a pas de ressource identifiée par l'URI

A tenté:
Nettoyer et reconstruire la solution - n'a pas fonctionné.
Fermer et ouvrir Visual Studio - ne fonctionnait pas.

Solution:
Entré dans le répertoire projects bin et effacé tous les fichiers.
J'ai repris le projet et a bien fonctionné.

Ouvrez le Package Manager Console qui ouvrira dans le répertoire racine de votre solution et exécutez la commande powershell suivante:

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

Cela m’arrive quand j’ai eu le même projet ouvert en deux solutions. La modification du contrôle de base dans un projet provoque ce problème dans l'autre projet. Si fermer et ouvrir ne fonctionnent pas, supprimez tous les dossiers de "C:\Utilisateurs ...\AppData\Local\Microsoft\VisualStudio\12.0\Designer\ShadowCache"

1
AMissico

@ Willem, cela me semble parfaitement correct. En fait, j'ai essayé cela et cela a fonctionné dans mon cas. J'ai utilisé ListBox au lieu de DataGrid (mais cela ne devrait pas importer).

Tous mes espaces de noms étaient dans une assemblée. J'ai donc utilisé un espace de noms commun pour tous les parents, par exemple. 

MyWpfApplication.ControlsMyWpfApplciation.GridViewMyWpfApplciation.ViewBase

Coz toutes ces Controls, GridView, ViewBase sont en conflit avec les déclarations de classe et d'espaces de noms basés sur System ou System.Windows.Controls existants. Je me suis donc assuré de mentionner les correctifs MyWpfApplication.* dans mon projet.

1
WPF-it

Cela peut arriver aussi quand fermant et rouvrant une fenêtre. Cela n’a donc rien à voir avec les packages et/ou les dll.
J'ai résolu le problème grâce à la solution publiée par PainElemental, qui est sous-estimée à mon humble avis:

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

LoadViewFromUri est implémenté comme une extension, comme l’a écrit PainElemental. Le plus fou est que j’ai aussi écrit dans le même projet d’autres fenêtres sans rencontrer de problème.
Merci PainElemental, vous avez mis fin à ma douleur prolongée!

1
Mauro

J'ai eu cette erreur après avoir renommé un fichier xaml. Inverser le changement de nom a résolu le problème. 

De plus, j’ai trouvé qu’une référence au nom de fichier xaml dans App.xaml n’était pas mise à jour (le StartupUri), mais renommer ce nom en nom actuel ne résolvait pas le problème (mais peut-être le fait-il pour vous). En gros, je ne peux pas renommer le fichier xaml. 

Fyi, pour moi, le composant "se plaindre" dans l'erreur était SplitComboBox.

1
JBSnorro

J'avais accidentellement supprimé un contrôle utilisateur via un renommer / copie action. Lorsque j'ai rétabli le fichier de projet ainsi que le fichier xaml et les fichiers .cs de contrôle de version, cette erreur a commencé à se produire dans le studio de création pour ce contrôle qui avait été supprimé/renommé par erreur. 

Cela suggérait un certain type de cache sur le fichier en question ... donc fermer Visual Studio, supprimer le répertoire bin et reconstruire a fonctionné.

0
ΩmegaMan

Plus rapide que de fermer tout Visual Studio consiste simplement à tuer XDescProc.exe dans votre gestionnaire de tâches. 

XDescProc est le concepteur. Dès que le processus est fermé, vous verrez un lien Recharger le concepteur dans Visual Studio. Cliquez dessus et XDes sera redémarré et votre erreur «aucune ressource» devrait disparaître.

Voici le lien que visual studio montre après avoir tué le processus du concepteur:

 enter image description here

0
Bill Tarbell

La solution de PainElemental suivie (pour clarifier, pour son code la ClassLibrary1 pour moi était le nom .dll sans l'extension .dll), voici mon scénario au cas où cela aide quelqu'un à lier ses messages d'erreur spécifiques au problème:

J'utilise des dll pour charger et exécuter usercontrols dans un programme principal sous la forme de leurs propres fenêtres contextuelles. La solution de PainElemental fonctionnait généralement, mais 1 des 3 classes de mon "popup .dll" ne se chargerait pas correctement. Je voudrais obtenir une exception avec 2 exceptions internes, comme:

mscorlib InvokeMethod ...;
WpfXamlLoader.Load ... Fournit une valeur pour ... StaticResourceExtension ...;
ResolveBamlType .... méthode ou opération non implémentée. 

Dans mon cas, j'ai confirmé qu'il chargerait le nouvel URI et fonctionnerait en test, mais lorsque j'essayais de l'exécuter dans mon environnement Live, une erreur se produirait dans LoadViewFromUri ().

Comme je l'ai testé plus avant, j'ai limité le problème à l'impossibilité de charger un fichier "library .dll" séparé que j'utilisais et qui contenait un convertisseur que j'utilisais dans le fichier .xaml de la classe en échec, ainsi que sur des recherches supplémentaires. le problème était que l'environnement Live utilisait une version de "bibliothèque .dll" différente de celle que j'utilisais dans mon environnement de test, même si le message d'exception de mon "popup .dll" ne le mentionnait pas.

Pour référence, j'utilise Copy Local = True et cela ne m'a pas posé de problème. Pour mieux résoudre ces problèmes, il est utile de connaître les emplacements où les fichiers .dll sont recherchés. Si je comprends bien, lorsque vous exécutez des projets dans VS, lorsque Copy Local = True, les .dll sont copiés dans le même dossier que le fichier .exe lorsqu’il est construit. Lorsque le fichier .exe est exécuté à l'emplacement standard, il recherchera .dll est le même dossier que le fichier .exe. Les emplacements supplémentaires que le fichier .exe peut rechercher .dlls peuvent être définis dans le fichier .exe.config, dans l'élément probing. Dans l'exemple ci-dessous, il peut également effectuer une recherche dans un répertoire "MyDLLs" et "MyDLLs\Core" par rapport à l'emplacement du fichier .exe. Notez que cela ne cherchera pas naturellement dans les sous-dossiers, vous devez les spécifier explicitement. Je crois qu’il cherche aussi dans le GAC, mais j’ai actuellement peu de connaissances sur GAC.

<configuration>
 ... 

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

J'ai juste rencontré ce problème aussi sans aucun problème d'héritage. Je faisais juste référence à une DLL qui contenait une boîte de dialogue et j'essayais de créer et d'afficher cette boîte de dialogue. J'ai un résolveur d'assemblage qui charge les assemblys à partir d'un dossier spécifique et il s'avère que j'avais ajouté la référence dans VS et que je n'avais pas désactivé Copy Local. Longue histoire courte: mon processus avait chargé deux versions de cette même DLL. Cela semble confondre WPF (ou le runtime). Une fois que j'ai effacé la copie locale et supprimé les copies supplémentaires DLL, cela a fonctionné à nouveau.

0
Clutchplate