Как установить URI ресурса изображения из кода сзади

Я пытаюсь встроить PNG-изображение в DLL и загрузить его вImage контроль какBitmapImage, Однако WPF продолжает выдавать исключение, сообщающее, что ресурс не может быть найден.

Сначала приведем минимальный пример кода и шаги для воспроизведения проблемы:

Создайте проект WPF с именемImageResTest с пустым главным окном (вы можете установить пространство имен по умолчаниюImageResTest). Файл кода в главном окне должен выглядеть следующим образом:

using System;
using System.Windows;
using System.Windows.Controls;

namespace ImageResTest
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            var obj = new MyData.SomeStuff.MyClass();

            this.Content = obj.Img;
        }
    }
}

Создайте библиотеку классов с именемImageResTestLib (вы можете установить пространство имен по умолчаниюImageResTestкак указано выше, все, что здесь обсуждается, находится в том же корневом пространстве имен).

Добавить ссылки изImageResTestLib вPresentationCore, PresentationFramework, System.Xaml а такжеWindowsBase.Добавить ссылку изImageResTest вImageResTestLib.внутриImageResTestLib, добавьте иерархию папокMyData/SomeStuff/Resources.

вSomeStuff папку, добавьте следующий файлMyClass.cs:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace ImageResTest.MyData.SomeStuff
{
    public class MyClass
    {
        public MyClass()
        {
            img = new Image();
            {
                var bmp = new BitmapImage();
                bmp.BeginInit();
                bmp.UriSource = new Uri(@"/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png", UriKind.RelativeOrAbsolute);
                bmp.EndInit();

                img.Source = bmp;
                img.Width = bmp.PixelWidth;
            }
        }

        private Image img;

        public Image Img {
            get {
                return img;
            }
        }
    }
}

вResources папку, добавьте файл PNG с именемImg.png и установите его действие сборкиРесурс (как предложено, например,Вот).

Пока все хорошо - запуск этого приложения должен создать окно, которое создаетMyClass и получаетImage созданный этимMyClass экземпляр. Это изображение должно быть заполненоBitmapImage чьи данные были загружены из графики, включенной в качестве ресурса.

К сожалению, кажется, что-то не так с ресурсом URI.документация по MSDN пока не помогло.

Я пробовал следующие варианты URI ресурса:

Форма изображена в примере кода выше -/AssemblyName;component/Path/Filename - было предложеноВот а такжеВот, ноDirectoryNotFoundException брошен, говоря, что часть путиC:\ImageResTestLib;component\MyData\SomeStuff\Resources\Img.png не был найден.pack://application:,,,/MyData/SomeStuff/Resources/Img.png было предложеноВот, Вот, Вот а такжеВот, но бросаетIOException говоря, что ресурсmydata/somestuff/resources/img.png невозможно найти.pack://application:,,,/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png было также предложеноВот, также как иВот, но бросаетFileNotFoundException говоря этоImageResTestLib, Culture=neutral или одна из его зависимостей не была найдена.Resources/Img.png (относительно файла кода)Вот а такжеВот, но бросаетDirectoryNotFoundException говоря этоC:\Users\myusername\Documents\Test\DOTNET\WPFTest\ImageResTest\bin\Debug\Resources\Img.png не был найден.MyData/SomeStuff/Resources/Img.png (относительно проекта), также подразумеваетсяВот, ведет себя аналогично предыдущему.

Поскольку ни один из них не будет работать, я попробовал следующий обходной путь, основанный наResourceDictionary:

Добавьте словарь ресурсов WPF с именемMyClassResources.xaml вSomeStuff папка.В этом ресурсе dictioanry, добавитьBitmapImage ресурс с ключомimg.

Изменить содержимоеMyClass.cs нравится:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace ImageResTest.MyData.SomeStuff
{
    public class MyClass
    {
        public MyClass()
        {
            ResourceDictionary dict = new ResourceDictionary();
            dict.Source = new Uri("/ImgResTestLib;component/MyData/SomeStuff/MyClassResources.xaml", UriKind.RelativeOrAbsolute);

            img = new Image();
            {
                var bmp = (BitmapImage)dict["img"];

                img.Source = bmp;
                img.Width = bmp.PixelWidth;
            }
        }

        private Image img;

        public Image Img {
            get {
                return img;
            }
        }
    }
}

Теперь словарь ресурсов может быть загружен с указанного URI (при удалении содержимого словаря ресурсов загрузка завершается успешно). Однако графика PNG по-прежнему не обнаруживается при использовании пути, подобного/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png.

Что я делаю не так и как я могу загрузить соответствующие ресурсы (если это возможно, без дополнительного словаря ресурсов)?

РЕДАКТИРОВАТЬ: Еще немного информации:

Я использую немецкую Windows 7 x64Клиент .NET 4.0 установлен в качестве целевой платформыПросто чтобы убедиться, я попытался собрать и запустить это как в Visual Studio 2010, так и в SharpDevelop 4.3.3; оба раза приводят к одному и тому же исключению.

Трассировка стекаFileNotFoundException Я основываюсь наЯнкод выглядит следующим образом:

System.Windows.Markup.XamlParseException: Zeilennummer "3" und Zeilenposition "2" von "Durch den Aufruf des Konstruktors für Typ "ImageResTest.Window1", der den angegebenen Bindungseinschränkungen entspricht, wurde eine Ausnahme ausgelöst.". ---> System.IO.FileNotFoundException: Die Datei oder Assembly "ImageResTestLib, Culture=neutral" oder eine Abhängigkeit davon wurde nicht gefunden. Das System kann die angegebene Datei nicht finden.
   bei System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   bei System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   bei System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   bei System.Reflection.Assembly.Load(AssemblyName assemblyRef)
   bei System.Windows.Navigation.BaseUriHelper.GetLoadedAssembly(String assemblyName, String assemblyVersion, String assemblyKey)
   bei MS.Internal.AppModel.ResourceContainer.GetResourceManagerWrapper(Uri uri, String& partName, Boolean& isContentFile)
   bei MS.Internal.AppModel.ResourceContainer.GetPartCore(Uri uri)
   bei System.IO.Packaging.Package.GetPartHelper(Uri partUri)
   bei System.IO.Packaging.Package.GetPart(Uri partUri)
   bei System.IO.Packaging.PackWebResponse.CachedResponse.GetResponseStream()
   bei System.IO.Packaging.PackWebResponse.GetResponseStream()
   bei System.IO.Packaging.PackWebResponse.get_ContentType()
   bei System.Windows.Media.Imaging.BitmapDecoder.SetupDecoderFromUriOrStream(Uri uri, Stream stream, BitmapCacheOption cacheOption, Guid& clsId, Boolean& isOriginalWritable, Stream& uriStream, UnmanagedMemoryStream& unmanagedMemoryStream, SafeFileHandle& safeFilehandle)
   bei System.Windows.Media.Imaging.BitmapDecoder.CreateFromUriOrStream(Uri baseUri, Uri uri, Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, RequestCachePolicy uriCachePolicy, Boolean insertInDecoderCache)
   bei System.Windows.Media.Imaging.BitmapImage.FinalizeCreation()
   bei System.Windows.Media.Imaging.BitmapImage.EndInit()
   bei ImageResTest.MyData.SomeStuff.MyClass..ctor(Uri baseUri) in C:\Users\username\Documents\Test\DOTNET\WPFTest\ImgResTestLib\MyData\SomeStuff\MyClass.cs:Zeile 36.
   bei ImageResTest.Window1..ctor() in c:\Users\username\Documents\Test\DOTNET\WPFTest\ImageResTest\Window1.xaml.cs:Zeile 17.
   --- End of inner exception stack trace ---
   bei System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
   bei System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
   bei System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
   bei System.Windows.Application.LoadBamlStreamWithSyncInfo(Stream stream, ParserContext pc)
   bei System.Windows.Application.LoadComponent(Uri resourceLocator, Boolean bSkipJournaledProperties)
   bei System.Windows.Application.DoStartup()
   bei System.Windows.Application.<.ctor>b__1(Object unused)
   bei System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   bei MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   bei System.Windows.Threading.DispatcherOperation.InvokeImpl()
   bei System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
   bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   bei System.Windows.Threading.DispatcherOperation.Invoke()
   bei System.Windows.Threading.Dispatcher.ProcessQueue()
   bei System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   bei MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   bei MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   bei System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   bei MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   bei System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   bei MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   bei MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   bei System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   bei System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   bei System.Windows.Threading.Dispatcher.Run()
   bei System.Windows.Application.RunDispatcher(Object ignore)
   bei System.Windows.Application.RunInternal(Window window)
   bei System.Windows.Application.Run(Window window)
   bei System.Windows.Application.Run()
   bei ImageResTest.App.Main() in c:\Users\username\Documents\Test\DOTNET\WPFTest\ImageResTest\obj\Debug\App.g.cs:Zeile 0.

EDIT2:

Добавление

Debug.WriteLine(typeof(MyData.SomeStuff.MyClass).Assembly.GetName().FullName);

в конструктор главного окна приводит к следующему выводу:

ImgResTestLib, Version=1.0.5123.16826, Culture=neutral, PublicKeyToken=null

Призыв к

Debug.WriteLine(BaseUriHelper.GetBaseUri(this).ToString());

печатает следующее:

pack://application:,,,/ImageResTest;component/window1.xaml

EDIT3:

В то время как принятый ответ решает проблему, описанную этим вопросом, действительная причина, по которой я не мог видеть свою графику в моем реальном проекте, была совсем другой:

Покани VS 2010, ни SharpDevelop датьЛюбые указание того, что ресурсы помечены какРесурс на самом деле есть логическое имя (в моем случае они сохранили его с того времени, когда я предварительно установил действие сборки наEmbeddedResource и поменял логическое имя). Логическое имя все еще появляется в<LogicalName> элемент в файле MSBuild и из того, что я вижу вILSpy, это это то, что фактически используется в качестве имени ресурса в скомпилированной сборке.

Правильный (рабочий) URI ресурса для такого ресурса слогическое имя кажется

/MyAssembly;component/LogicalResourceName

(таким образом, заменяя путь к каталогу ресурса, как обычно дляEmbeddedResource Ресурсы)

Хотя невозможно изменить логическое имя в VS или SharpDevelop, пока действие сборки установлено наРесурс, удалив ресурс и повторно добавив файл, затем установив действие сборки наРесурс, заставляет работать основанные на имени файла URI снова, так как логическое имя больше не будет в файле проекта. Аналогично, удаление<LogicalName> элемент вручную из файла MSBuild должен работать.

Ответы на вопрос(1)

Ваш ответ на вопрос