/ / URI Pack pre obrázok vložený do súboru resx - wpf, image, internacionalizácia, zdroje, uri

Pack URI na obrázok vložený do súboru resx - wpf, image, internacionalizácia, zdroje, uri

Ako môžem vytvoriť URI paketu na obrázok, ktorý je v súbore so zdrojmi?

Mám zhromaždenie MyAssembly.Resources.dll, má priečinok s názvom snímky, potom je tu nazvaný zdrojový súbor Assets.resx, Tento zdrojový súbor obsahuje môj obrázok (nazývaný MyImage.png). Riadok kódu, ktorý mám, je:

uri = new Uri("pack://application:,,,/MyAssembly.Resources,Culture=neutral,PublicKeyToken=null;component/Images/Assets/MyImage.png");

Keď sa však pokúsim dodať tento URI konštruktorovi nového BitmapImage Mám to IOException so správou

Nemožno nájsť zdroj "images / assets / myimage.png".

Všimnite si, že mám iné voľné obrázky v tej istej zostave, ktoré môžem načítať jemne pomocou balíka URI, tieto obrázky majú svoju zostavu nastavenú na Resource ale nie sú vložené do súboru resx, Mala by som obsahovať meno súboru resx v ceste?

(Hľadám vkladanie obrázkov do súborov resx, aby som mohol využiť nastavenie kultúry používateľského rozhrania na získanie správneho obrázka (obrázok obsahuje text)).

odpovede:

15 pre odpoveď č. 1

Nemyslím si, že je možné použiť schému protokolu "pack". Tento protokol súvisí s normalizovanými špecifikáciami konvencií otvoreného balenia (http://tools.ietf.org/id/draft-shur-pack-uri-scheme-05.txt pre ukazovatele). Tak packs poukazuje na zdroje balíka aplikácie (alebo časti v OPC termínoch), nie na .NET vložené zdroje.

Môžete však definovať vlastnú schému, napríklad "resx" a použiť ju v komponente WPF uris. Nové schémy Uri pre takéto použitia možno definovať pomocou WebRequest.RegisterPrefix.

Tu je príklad založený na malom Wpfaplikácie s názvom "WpfApplication1". Táto aplikácia má definovaný súbor Resource1.resx (a pravdepodobne aj iné lokalizované zodpovedajúce súbory Resource1, ako napríklad Resource1.fr-FR.resx pre francúzsky). Každý z týchto súborov ResX definuje zdroj obrázkov s názvom "img" (poznamenajte si, že toto meno nie je totožné s názvom súboru obrázka, na ktorom je zdroj založený).

Tu je MainWindow.xaml:

<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Image Source="resx:///WpfApplication1.Resource1/img" />
</Window>

Formát uri je tento:

resx://assembly name/resource set name/resource name

a názov zostavy je voliteľný, takže

resx:///resource set name/resource name

je tiež platný a poukazuje na zdroje v hlavnom zhromaždení (môj vzorka to používa)

Toto je kód, ktorý ho podporuje, v aplikácii App.xaml.cs alebo niekde inde, musíte zaregistrovať novú schému:

public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
ResXWebRequestFactory.Register();
base.OnStartup(e);
}
}

Implementácia schémy:

public sealed class ResXWebRequestFactory : IWebRequestCreate
{
public const string Scheme = "resx";
private static ResXWebRequestFactory _factory = new ResXWebRequestFactory();

private ResXWebRequestFactory()
{
}

// call this before anything else
public static void Register()
{
WebRequest.RegisterPrefix(Scheme, _factory);
}

WebRequest IWebRequestCreate.Create(Uri uri)
{
return new ResXWebRequest(uri);
}

private class ResXWebRequest : WebRequest
{
public ResXWebRequest(Uri uri)
{
Uri = uri;
}

public Uri Uri { get; set; }

public override WebResponse GetResponse()
{
return new ResXWebResponse(Uri);
}
}

private class ResXWebResponse : WebResponse
{
public ResXWebResponse(Uri uri)
{
Uri = uri;
}

public Uri Uri { get; set; }

public override Stream GetResponseStream()
{
Assembly asm;
if (string.IsNullOrEmpty(Uri.Host))
{
asm = Assembly.GetEntryAssembly();
}
else
{
asm = Assembly.Load(Uri.Host);
}

int filePos = Uri.LocalPath.LastIndexOf("/");
string baseName = Uri.LocalPath.Substring(1, filePos - 1);
string name = Uri.LocalPath.Substring(filePos + 1);

ResourceManager rm = new ResourceManager(baseName, asm);
object obj = rm.GetObject(name);

Stream stream = obj as Stream;
if (stream != null)
return stream;

Bitmap bmp = obj as Bitmap; // System.Drawing.Bitmap
if (bmp != null)
{
stream = new MemoryStream();
bmp.Save(stream, bmp.RawFormat);
bmp.Dispose();
stream.Position = 0;
return stream;
}

// TODO: add other formats
return null;
}
}
}

4 pre odpoveď č. 2

Existujú dva spôsoby, ako vložiť zdroj do zostavy. Windows Forms používa Embedded Resource Vytvoriť akciu. WPF očakáva, že zdroje obsiahnuté v zostavách budú označené značkou Resource Vytvoriť akciu.

Keď použijete Editor obrázkov v aplikácii Visual Studio na pridanie obrázka, označuje ho ako vložený zdroj. Tiež ho ukladá ako typ System.Drawing.Bitmap, WPF očakávajú System.Windows.Media.ImageSource typu.

Ak máte disembler (napríklad ILSpy), môžete sa pozrieť na vplyv nastavenia rôznych akcií na vytváranie súborov.

Ukážkový projekt ImagesLib

Tu je screenshot projektu s dvomi obrázkami. Je to zrejmé z názvov, cat_embedded.jpg používa Embedded Resource Vytvorenie akcie a cat_resource.jpg používa Resource Vytvorenie akcie.

tu zadajte popis obrázku

Vyzerajú to v ILSpy.

tu zadajte popis obrázku

Pozrite sa, ako je súbor cat_resource.jpg v sekcii ImageLib.g.resources? To je miesto, kde WPF hľadá zdroje. Cesta k súboru je súčasťou názvu zdroja (images/cat_resource.jpg). Takže keď použijete cestu ako:

var uri = new Uri("pack://application:,,,/ImageLib;component/Images/cat_resource.jpg");

zadáte zodpovedajúcu cestu za slovom ;component.

Druhý jpg súbor sa nachádza na inom mieste v zostave a používa sa v menách (ImageLib.Images.cat_embedded.jpg).

Môžete skúsiť veľa permutácií tohto reťazca, aby ste sa pokúsili získať obrázok cat_embedded.jpg, ale WPF to nenašiel.

Editor RESX

Tu je ďalší projekt, ktorý má dva obrázky, jeden označený ako zdroj a jeden pridaný resx editorom.

tu zadajte popis obrázku

A tu je demontovaný snímok obrazovky.

tu zadajte popis obrázku

Ako vidíte, resx obrázok používa to istéURI ako predchádzajúci príklad vloženého obrázku. Vo vašom prípade sa zdá, že nebudete môcť získať obrázky z resx súboru pomocou balíka URI.

lokalizácia

Z toho, čo ste vo svojej otázke povedali, to, čo sa pokúšate dosiahnuť, je lokalizácia obrázkov správne?

Pozreli ste sa na tento článok MSDN?

Prehľad globalizácie a lokalizácie WPF


3 pre odpoveď № 3

Ako správne uviedol Walt, to, čo dostanete zo súboru resx, je a System.Drawing.Bitmap, Takže toto musí byť prevedené na a System.Windows.Media.ImageSource alebo podtypu.

Nie som si istý, či to pre vás spadá pod časové plytvanie, pretože nepoužíva URI, ale tu som získal obrázky z resx súborov v inej knižnici. jednoduchý proxy pretože súbor dizajnérov resx odhaľuje iba interný konštruktor (aj keď je trieda verejná), potom definujte ValueConverter, ktorý poskytne ImageSource.

tu zadajte popis obrázku

<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:resx="clr-namespace:MyAssembly.Resources;assembly=MyAssembly.Resources"
Title="MainWindow" Height="350" Width="525">

<Window.Resources>
<resx:AssetsProxy x:Key="Assets" />
<resx:BitmapToImageSourceConverter x:Key="BitmapConverter" />
</Window.Resources>

<Image Source="{Binding myimage, Source={StaticResource Assets}, Converter={StaticResource BitmapConverter}}" />
</Window>

AssetsProxy:

namespace MyAssembly.Resources
{
public class AssetsProxy : Images.Assets
{
public AssetsProxy() : base() { }
}
}

Bitmap na konverziu ImageSource:

using System;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Windows.Data;
using System.Windows.Media.Imaging;

namespace MyAssembly.Resources
{
/// <summary>
/// Converts a BitmapImage, as provided by a resx resource, into an ImageSource/BitmapImage
/// </summary>
public class BitmapToImageSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
BitmapImage bitmapImage = null;
if (value is System.Drawing.Image)
{
bitmapImage = ((System.Drawing.Image)value).ToBitmapImage();
}
return bitmapImage;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

public static class BitmapExtensions
{
/// <summary>
/// Converts the System.Drawing.Image to a System.Windows.Media.Imaging.BitmapImage
/// </summary>
public static BitmapImage ToBitmapImage(this System.Drawing.Image bitmap)
{
BitmapImage bitmapImage = null;
if (bitmap != null)
{
using (MemoryStream memory = new MemoryStream())
{
bitmapImage = new BitmapImage();
bitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
}
}
return bitmapImage;
}
}
}

2 pre odpoveď № 4

Opisoval som komponent pre použitie resx obrázkov vo WPF v tomto blogovom príspevku: http://wpfglue.wordpress.com/2012/05/31/localization-revisited/ , Ďalšie informácie o používaní resx zdrojov vo WPF nájdete pod http://wpfglue.wordpress.com/category/localization/

V týchto príspevkoch nepoužívam pack uris, ale rozšírenia značiek.