it-roy-ru.com

Компонент не имеет ресурса, идентифицируемого URI

Я хочу создать универсальную сетку данных для использования во всех моих представлениях/пользовательских элементах управления.

Это моя структура:

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

Затем приложение WPF называется «WPFApp»:

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'."

Что я делаю неправильно?

Это правильный подход или я далеко?

39
Willem

Я делал что-то очень похожее с тем же результатом. У меня была одна библиотека классов C #, которая содержала элемент управления WPF с именем UsageControl (xaml с сопровождающим файлом xaml.cs). В отдельном проекте C # (т. Е. Отдельной DLL) я создал C # class CPUUsageControl, который унаследовал от UsageControl, но включил в него свое собственное вращение. Когда я попытался использовать CpuUsageControl в одном из моих представлений, я получил ту же ошибку, что и вы.

То, что я сделал, чтобы исправить это, было в моей отдельной сборке, вместо создания класса, унаследованного от базового элемента управления, я создал новый элемент управления WPF, который содержал базовый элемент управления. Затем я поместил всю логику, которая содержалась в классе CpuUsage, в код WpfCpuUsageControl. Я был в состоянии использовать этот объект, все мои другие элементы управления просто отлично.

Для вашего элемента управления "GridView" я бы создал новый пользовательский элемент управления WPF , назовите его GridView и сделайте его содержать "ViewBase" в качестве содержимого элемента управления Grid. Внутри содержимого ViewBase, помещенного в ваш DataGrid, вот так:

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

Для меня также не очевидно, что вам нужен ViewBase для прямого наследования от UserControl. Если все, что вам нужно, это чтобы ваши элементы управления имели определенные свойства и метод, почему бы просто не создать класс BaseControl (который не наследуется ни от кого, кроме объекта) и иметь будущие элементы управления, наследуемые от него. Возможно, вам нужен абстрактный базовый класс или интерфейс.

Для проектов MVFM WPF у меня обычно есть BaseViewModel, который реализует для меня INotifyPropertyChanged, поэтому мне не нужно делать этот код везде.

Удачи, я знаю, что эту проблему было огромной болью, чтобы понять. Сообщение об исключении и Google наиболее бесполезны!

11
Steven Magana-Zook

К сожалению, у меня была именно эта ошибка, и я потратил целую вечность, пытаясь выяснить причину. Для меня это когда-то работало, но затем я внес несколько незначительных изменений в XAML производного элемента управления, и компилятор начал выдавать это сообщение об ошибке .. Короткое решение, избавившее от многих попыток его выяснить: shut закрыть Visual Studio и снова открыть его, перекомпилировать, проблема волшебным образом ушла! (Это VS2012 Pro) Просто добавьте это на тот случай, если кто-то читает по кругу, пытаясь найти несуществующую проблему со своим кодом. Возможно, стоит сначала попробовать «IT Crowd Solution».

56
HughHughTeotl

Причина, по которой вы получаете эту ошибку, заключается в том, что способ реализации 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. Это ошибка? Я не знаю...

19
Tim Lovell-Smith

Это дало мне головную боль в течение 3 дней! У меня есть XAML UserControl в библиотеке классов и класс (только C #), который является производным от UserControl в моем проекте .exe . В конструкторе xaml моего MainWindow.xaml и при запуске приложения я получил компонент «ошибка» не имеет ресурса, идентифицируемого URI ". Ответ" Хуана Карлоса Хирона ", наконец, привел меня к решению:

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

и вызвал это из файла .cs UserControl:

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

Еще раз спасибо "Хуан Карлос Хирон"!

18
PainElemental

Вы можете попробовать этот подход

Я создал свою собственную функцию 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
        }
    }
9
Juan Carlos Girón

Та же проблема здесь.

Укороченная версия:

Copy Local должен быть установлен в False!

Длинная версия:

Мы разработали решение WPF (MVVM, 20 проектов) и внедрили систему плагинов. Наш каталог/bin/Debug содержит исполняемый файл, некоторые dll-файлы и каталог плагинов, который содержит плагины ... Существует один проект "DialogLib" (библиотека классов, вид диалога), который определяет окно (представление), ViewModel, модель и некоторые интерфейсы. Один из плагинов использовал один из интерфейсов DialogLib. Само окно открывается основным приложением.

Чтобы использовать интерфейс библиотеки DialogLib в плагине, мы должны были добавить ссылку на проект DialogLib к ссылкам проекта плагина. Когда приложение было запущено, плагины были загружены. Если пользователь затем выбирает пункт меню, окно должно открыться. На этом этапе ошибка «... компонент не имеет ресурса, идентифицированного URI ...» произошла, когда код Windows позади попытался выполнить свой InitializeComponent ().

Где проблема?

Проблема в том, что когда мы строили решение, VS правильно создал DialogLib.dll и скопировал его в/bin/Debug /. Это потому, что основной файл приложения хочет открыть окно. Но DialogLib.dll также был скопирован в/bin/Debug/plugins, потому что один из плагинов ссылался на него для использования одного из интерфейсов, определенных в DialogLib.dll. И что?

Когда плагин загружается во время выполнения, он использует интерфейс, определенный в /bin/Debug/plugins/DialogLib.dll. и основной файл приложения пытается открыть окно, определенное в /bin/Debug/DialogLib.dll. Хотя файлы идентичны, VS сталкивается с проблемами. Установка значения Copy Local в свойствах ссылок DialogLib ссылок плагинов позволяет избежать копирования DialogLib.dll в/bin/Debug/plugins и, таким образом, решает проблему.

У нас была такая же проблема (но другая ошибка) в другом проекте, где мы хотели использовать тип TypeA, который был определен в файле dll, в плагине и в основном приложении. Copy Local был установлен на true, что привело к расположению копии файла dll в ../bin/Debug/plugins и в ../bin/Debug/. Оказалось, что, хотя это был один и тот же файл dll, TypeA в основном файле приложения и TypeA в плагине обрабатывались как разные типы соответственно как типы, которые нельзя было заменить. 

7
ooorndtski

Я решил это, поместив 

myusercontrol = Activator.CreateInstance<myusercontrol>(); 

в конструкторе окна, содержащего usercontrol перед строкой InitializeComponent();

6
Darren
  • Удалить папку obj
  • Удалить папку bin
  • Восстановить решение

Работал на меня!

Также, если вы загружаете сборки с помощью Assembly.LoadFile, проверьте AppDomain.CurrentDomain.GetAssemblies() на наличие дубликатов сборок в текущем домене приложений. Поскольку в автоматически сгенерированном коде WPF UserControl, компонент будет загружен с использованием его относительного URI. А поскольку в текущем домене приложений есть дублирующиеся сборки, приложение не знает, какую из них использовать.

6
VahidN

Я получил ту же ошибку при использовании Visual Studio 2013.

Компонент не имеет ресурса, идентифицируемого URI

Пытался:
Очистка и восстановление решения - не сработало.
Закрытие и открытие Visual Studio - не сработало.

Решение:
Зашел в каталог проектов bin и очистил все файлы.
Запустил проект снова и работал нормально.

Откройте Package Manager Console , которая откроется в корневом каталоге вашего Решения и выполните следующую команду powershell:

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

Случайно, когда у меня был один и тот же проект, открытый в двух решениях. Изменение базового элемента управления в одном проекте приводит к возникновению этой проблемы в другом проекте. Если закрытие и открытие не работает, удалите все папки в «C:\Users ...\AppData\Local\Microsoft\VisualStudio\12.0\Designer\ShadowCache»

1
AMissico

@ Виллем, мне кажется, это нормально. На самом деле я попробовал это, и это сработало в моем случае. Я использовал ListBox вместо DataGrid (но это не имеет значения).

Все мои пространства имен были в одной сборке. Таким образом, я использовал общее родительское пространство имен для всех, например. 

MyWpfApplication.ControlsMyWpfApplciation.GridViewMyWpfApplciation.ViewBase

Поскольку все эти Controls, GridView, ViewBase конфликтуют с существующими пространствами имен и объявлениями классов на основе System или System.Windows.Controls. Поэтому я позаботился о том, чтобы в моем проекте были правильные MyWpfApplication.*.

1
WPF-it

Это может также произойти, когда закрытие и повторное открытие окна. Так что это также может не иметь ничего общего с пакетами и/или DLL.
Я решил проблему благодаря опубликованному PainElemental решению, которое, по-моему, недооценено:

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

LoadViewFromUri реализован как расширение, как писал PainElemental. Самым сумасшедшим является то, что я также написал в том же проекте другие окна без каких-либо проблем.
Спасибо, PainElemental, ты прекратил мою затяжную боль!

1
Mauro

Я получил эту ошибку после переименования файла xaml. Обратное переименование решило проблему. 

Кроме того, я обнаружил, что ссылка на имя файла xaml в App.xaml не была обновлена ​​(StartupUri), но переименование этого в текущее имя не решило проблему (но, возможно, это поможет вам). По сути, я не могу переименовать файл xaml. 

К вашему сведению, компонент «жаловаться» на ошибку был SplitComboBox.

1
JBSnorro

Я случайно удалил пользовательский элемент управления через переименовать / копировать действие. Когда я восстановил файл проекта, файл xaml и файл .cs из системы управления версиями, эта ошибка начала возникать в студии дизайна для этого элемента управления, который был ошибочно удален/переименован. 

Это предполагает некоторый тип кэша для рассматриваемого файла .... поэтому закрытие Visual Studio, удаление каталога bin и перестройка работали.

0
ΩmegaMan

Быстрее, чем закрытие всей Visual Studio, достаточно просто убить XDescProc.exe в вашем диспетчере задач. 

XDescProc является дизайнером. Как только процесс завершится, вы увидите ссылку «Перезагрузить конструктор» в Visual Studio. Нажмите на него, и XDes будут запущены снова, и ваша ошибка «нет ресурсов» должна исчезнуть.

Вот ссылка, которую визуальная студия показывает после того, как вы убили процесс конструктора:

 enter image description here

0
Bill Tarbell

Следуя решению PainElemental (чтобы уточнить, для моего кода ClassLibrary1 для меня было имя .dll без расширения .dll), вот мой сценарий на случай, если он поможет кому-либо связать свои конкретные сообщения об ошибках с проблемой:

Я использую DLL для загрузки и запуска пользовательских контролей в основную программу как свои собственные всплывающие окна. Решение PainElemental в основном работало, но 1 из 3 классов в моем "popup .dll" не загружался должным образом. Я бы получил исключение с 2 внутренними исключениями, например:

mscorlib InvokeMethod ...;
WpfXamlLoader.Load ... Предоставить значение для ... StaticResourceExtension ...;
ResolveBamlType .... метод или операция не реализованы. 

В моем случае я подтвердил, что он загрузит новый URI и будет работать в тестировании, но когда я попытался запустить его в моей среде Live, в LoadViewFromUri () произойдет ошибка.

В ходе дальнейшего тестирования я сузил проблему до невозможности загрузки отдельного файла «library .dll», который я использовал, который содержал конвертер, который я использовал в файле .xaml класса, который не удался, и дальнейших исследований. проблема заключалась в том, что в среде Live использовалась версия «library .dll», отличная от той, что использовалась в моей тестовой среде, хотя в сообщении об исключении из моей «popup .dll» об этом ничего не упоминалось.

Для справки я использую Copy Local = True, и это не доставило мне проблем. Чтобы наилучшим образом отладить подобные проблемы, полезно знать, где файлы .dll ищут .exe. Насколько я понимаю, когда вы запускаете проекты в VS, когда Copy Local = True, DLL-файлы копируются в ту же папку, что и EXE-файл при его сборке. Когда .exe запускается в стандартном расположении, он ищет .dlls в той же папке, что и .exe. Дополнительные местоположения, которые .exe может искать .dll, могут быть установлены в файле .exe.config, в элементе probeing. В приведенном ниже примере он также может выполнять поиск в каталоге «MyDLLs» и «MyDLLs\Core» относительно расположения .exe. Обратите внимание, что он не будет естественно искать какие-либо подпапки, вы должны указать их явно. Я полагаю, что это также ищет GAC, но у меня в настоящее время есть минимальные знания относительно GAC.

<configuration>
 ... 

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

Я только что столкнулся с этой проблемой без каких-либо проблем с наследованием. Я просто ссылался на DLL, который содержал диалог, и пытался создать и отобразить этот диалог. У меня есть сборщик разрешений, который загружает сборки из определенной папки, и получается, что я добавил ссылку в VS и не отключил функцию копирования локальных файлов. Короче говоря: мой процесс загрузил две версии той же DLL. Это, кажется, сбивает с толку WPF (или время выполнения). После того, как я очистил Copy Local и удалил лишние DLL копии, он снова заработал нормально.

0
Clutchplate