Я пытаюсь встроить PNG-графику в DLL и загрузить ее в Image
control как BitmapImage
. Однако WPF продолжает бросать исключение, говоря, что ресурс не найден.Как установить URI ресурса ресурса из Code-Behind
Во-первых, некоторый минимальный пример кода и шаги, чтобы воспроизвести проблему:
Создание проекта 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
и установить его сборки действие на ресурс (как это было предложено , например, here).
До сих пор, так хорошо - запуск этого приложения необходимо создать окно, которое инстанцирует MyClass
и извлекает Image
созданные этот MyClass
экземпляра. Это изображение должно быть заполнено BitmapImage
, данные которого были загружены из графического объекта, включенного в качестве ресурса.
К сожалению, в URI ресурса, похоже, что-то не так. documentation on MSDN пока не помог.
Я попытался следующие варианты URIs ресурсов:
- форма изображена в примере кода выше -
/AssemblyName;component/Path/Filename
- было предложено here и here, ноDirectoryNotFoundException
брошено, говоря, что часть путиC:\ImageResTestLib;component\MyData\SomeStuff\Resources\Img.png
не найден. pack://application:,,,/MyData/SomeStuff/Resources/Img.png
было предложено here, here, here и here, но бросаетIOException
о том, что ресурсmydata/somestuff/resources/img.png
не может быть найден.pack://application:,,,/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png
также было предложено here, а также here, но бросаетFileNotFoundException
говоря, чтоImageResTestLib, Culture=neutral
или один из его зависимостей не найден.Resources/Img.png
(относительный от файла кода) подразумевался here и here, но выбрасываетDirectoryNotFoundException
, заявив, чтоC:\Users\myusername\Documents\Test\DOTNET\WPFTest\ImageResTest\bin\Debug\Resources\Img.png
не найден.MyData/SomeStuff/Resources/Img.png
(относительно проекта), также как подразумевается here, ведет себя аналогично предыдущему.
Поскольку ни один из них не будет работать, я попробовал следующий обходной путь, основанный на ResourceDictionary
:
- Добавить словарь WPF ресурсов с именем MyClassResources.xaml в папке
SomeStuff
. - В этом ресурсе укажите источник
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
.
Что я делаю неправильно и как я могу загрузить соответствующие ресурсы (если возможно, без дополнительного ресурсного словаря)?
EDIT: Некоторые больше информации:
- Я использую 7 x64 Немецкий для Windows
- .NET 4.0 Client устанавливается в качестве целевой структуры
- Просто чтобы убедиться, я попытались создать и запустить это как из Visual Studio 2010, так и из SharpDevelop 4.3.3; оба раза приводят к одному и тому же исключению.
StackTrace из FileNotFoundException
я получаю на основе кода Ian»заключается в следующем:
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, в то время как для действия сборки установлено значение Resource, удаление ресурса и повторное добавление файла, а затем установка действия сборки ion до Ресурс, заставляет URI с именами файлов работать снова, так как логическое имя больше не будет в файле проекта. Аналогично, удаление элемента <LogicalName>
вручную из файла MSBuild должно работать.
Ваши инструкции помещают 'MyClass' в компонент ImageRestTestLib, но исходный код показывает пространство имен как« ImageRestTest », подразумевая, что он находится в основном проекте« ImageRestTest ». Очевидно, нет ничего, что мешало бы вам использовать разные пространства имен, но я хотел проверить, произошла ли ошибка в инструкциях. –
@IanGriffiths: Нет, это намеренно, поэтому все здесь находится в одном корневом пространстве имен. Спасибо за замечание; Я добавил комментарий в описании выше. –
невероятный ...HOURS потратил впустую, пытаясь заставить это работать, и, в конце концов, удалив изображение и добавив его обратно, затем установив его на ресурс, «волшебным образом» работал ... Мне нравится, как я, кажется, создаю рабочее приложение за час, но мне понадобится целый день, чтобы вставить в него изображение ...! – Rob