Jak ustawić identyfikator URI zasobów obrazu z Code-Behind
Próbuję osadzić grafikę PNG w bibliotece DLL i załadować ją do plikuImage
kontrola jakBitmapImage
. Jednak WPF nadal rzuca wyjątek informujący, że nie można znaleźć zasobu.
Po pierwsze, jakiś minimalny przykładowy kod i kroki do odtworzenia problemu:
Utwórz projekt WPF o nazwieImageResTest z pustym głównym oknem (możesz ustawić domyślną przestrzeń nazw naImageResTest
). Plik z kodem głównego okna powinien wyglądać następująco:
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;
}
}
}
Utwórz bibliotekę klas o nazwieImageResTestLib (możesz ustawić domyślną przestrzeń nazw naImageResTest
, jak wyżej, więc wszystko omawiane tutaj jest w tej samej przestrzeni nazw roota.
MyData/SomeStuff/Resources
.wSomeStuff
folder, dodaj następujący plikMyClass.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;
}
}
}
}
wResources
folder, dodaj nazwany plik PNGImg.png
i ustaw jego akcję budowania naRatunek (jak sugerowano, na przykład,tutaj).
Do tej pory tak dobrze - uruchomienie tej aplikacji powinno stworzyć okno, które tworzy instancjęMyClass
i pobieraImage
stworzony przez toMyClass
instancja. Ten obraz powinien być wypełnionyBitmapImage
którego dane zostały załadowane z grafiki dołączonej jako zasób.
Niestety, wydaje się, że coś jest nie tak z URI zasobów. Thedokumentacja w MSDN do tej pory nie pomógł.
Próbowałem następujących wariantów identyfikatorów URI zasobów:
Formularz przedstawiony w powyższym przykładzie kodu -/AssemblyName;component/Path/Filename
- zasugerowanotutaj itutaj, aleDirectoryNotFoundException
jest rzucony, mówiąc, że część ścieżkiC:\ImageResTestLib;component\MyData\SomeStuff\Resources\Img.png
nie znaleziono.pack://application:,,,/MyData/SomeStuff/Resources/Img.png
zasugerowanotutaj, tutaj, tutaj itutaj, ale rzucaIOException
mówiąc, że zasóbmydata/somestuff/resources/img.png
nie znaleziono.pack://application:,,,/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png
zasugerowano równieżtutaj, jak równieżtutaj, ale rzucaFileNotFoundException
mówiąc, żeImageResTestLib, Culture=neutral
lub nie znaleziono jednej z jego zależności.Resources/Img.png
(relatywnie do pliku kodu) było dorozumianetutaj itutaj, ale rzucaDirectoryNotFoundException
mówiąc, żeC:\Users\myusername\Documents\Test\DOTNET\WPFTest\ImageResTest\bin\Debug\Resources\Img.png
nie znaleziono.MyData/SomeStuff/Resources/Img.png
(w stosunku do projektu), również w sposób dorozumianytutaj, zachowuje się analogicznie do poprzedniego.Ponieważ żaden z nich nie zadziałał, próbowałem obejść następujące obejście oparte na aResourceDictionary
:
SomeStuff
teczka.W tym dyktacie zasobów dodaj aBitmapImage
zasób za pomocą kluczaimg
.Zmień zawartośćMyClass.cs lubię to:
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;
}
}
}
}
Teraz słownik zasobów można załadować ze wskazanego identyfikatora URI (podczas usuwania zawartości słownika zasobów ładowanie zakończy się pomyślnie). Jednak grafika PNG nadal nie jest znaleziona podczas korzystania z takiej ścieżki/ImageResTestLib;component/MyData/SomeStuff/Resources/Img.png
.
Co robię źle i jak mogę załadować odpowiednie zasoby (jeśli to możliwe, bez dodatkowego słownika zasobów)?
EDYCJA: Więcej informacji:
Używam niemieckiego systemu Windows 7 x64Klient .NET 4.0 jest ustawiony jako struktura docelowaAby się upewnić, próbowałem budować i uruchamiać je zarówno z poziomu Visual Studio 2010, jak i SharpDevelop 4.3.3; oba czasy powodują ten sam wyjątek.Ślad stosuFileNotFoundException
Staję na podstawieIanKod jest następujący:
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:
Dodawanie
Debug.WriteLine(typeof(MyData.SomeStuff.MyClass).Assembly.GetName().FullName);
do konstruktora głównego okna uzyskuje się następujące dane wyjściowe:
ImgResTestLib, Version=1.0.5123.16826, Culture=neutral, PublicKeyToken=null
Wezwanie do
Debug.WriteLine(BaseUriHelper.GetBaseUri(this).ToString());
drukuje następujące informacje:
pack://application:,,,/ImageResTest;component/window1.xaml
EDIT3:
Chociaż zaakceptowana odpowiedź rozwiązuje problem opisany w tym pytaniu, faktycznym powodem, dla którego nie mogłem zobaczyć mojej grafiki w moim rzeczywistym projekcie, było coś zupełnie innego:
Podczasani VS 2010 ani SharpDevelop daćkażdy wskazanie tego, zasoby oznaczone jakoRatunek faktycznie mają logiczną nazwę (w moim przypadku zachowali ją od momentu, kiedy wstępnie ustawiłem akcję kompilacji naEmbeddedResource i zmienił nazwę logiczną). Nazwa logiczna nadal pojawia się w a<LogicalName>
element w pliku MSBuild iz tego, co widzęILSpy, że jest tym, co jest faktycznie używane jako nazwa zasobu w skompilowanym zestawie.
Prawidłowy (działający) URI zasobu do takiego zasobu za pomocąnazwa logiczna wygląda na to
/MyAssembly;component/LogicalResourceName
(zastępując w ten sposób ścieżkę katalogu do zasobu, jak zwykle dlaEmbeddedResource zasoby)
Chociaż nie można zmienić nazwy logicznej w VS lub SharpDevelop, podczas gdy akcja kompilacji jest ustawiona naRatunek, usunięcie zasobu i ponowne dodanie pliku, a następnie ustawienie akcji kompilacji naRatunek, sprawia, że identyfikatory URI oparte na nazwach plików działają ponownie, ponieważ nazwa logiczna nie będzie już w pliku projektu. Podobnie, usunięcie<LogicalName>
element ręcznie z pliku MSBuild powinien działać.