C # - Как я могу иметь динамический Image / BitmapSource доступный из XAML? - PullRequest
0 голосов
/ 18 декабря 2018

В моем проекте на C # у меня есть список изображений, которые являются ресурсами, скомпилированными в exe:

/Pics/Image1.png /Pics/Image2.png /Pics/Image3.png ...

В моем коде я обрабатываю изображения, чтобы сопоставить их с темойприложение.Проблема, с которой я сталкиваюсь, заключается в том, что я пытаюсь найти простой способ доступа к этим обработанным изображениям в синтаксисе XAML.

Обычно я получаю доступ к изображению ресурса (предварительно обработанному):

<Image Source="/Pics/Image1.png" />

Поэтому я действительно хотел бы получить доступ к этим обработанным изображениям аналогичным образом.

Я попробовал статический словарь, подобный этому:

<Image Source="{x:Static local:Theme.Images.ImageDictionary[/Pics/Image1.png]}" />

Но это вызвало ошибку, потому что ему не нравится ".png", я не смог заставить его работать с ключами словаря.Не говоря уже о том, что это выглядит ужасно.

В идеале я хотел бы иметь возможность "заменить" ссылки на ресурсы или создать ресурс во время выполнения (например, PicsProcessed/Image1.png), но не смог понятьспособ добавления или изменения ресурсов в работающем приложении C # программным способом.

Любые предложения действительно приветствуются - спасибо!

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

Это заняло пару дней, но я нашел решение!

Я переместил все свои изображения в другой проект C # в том же решении, настроенном на компиляцию в виде DLL-файла Class Libary с именем DynamicResources.dll (Название сборки в настройках проекта - «DynamicResources»).Этот проект добавлен как ссылка на основной проект.Таким образом, я могу получить доступ к изображениям в XAML - чисто и аккуратно:

<Image Source="/DynamicResources;component/pics/image1.png" />

Затем в событии после сборки для основного проекта я переименую скомпилированный .dll, чтобы он не получалзагружается основным двоичным файлом .exe при запуске :

copy "$(TargetDir)DynamicResources.dll" "$(TargetDir)DynamicResources.temp" 
del "$(TargetDir)DynamicResources.dll"

Затем я использовал стороннюю библиотеку Mono.Cecil для загрузки файла DynamicResources.temp (в формате DLL), замены ресурсов,запишите его обратно в память, затем скажите приложению, чтобы загрузить его:

public static void UpdateAssembly()
{
    string dllFile = "DynamicResources.temp";
    string dllNamespace = "DynamicResources";

    var asm = AssemblyDefinition.ReadAssembly(dllFile);            
    var module = asm.Modules.FirstOrDefault();
    var resources = module.Resources;
    var dllResource = (EmbeddedResource)(resources.FirstOrDefault());
    var dllResourceReader = new ResourceReader(dllResource.GetResourceStream());
    var newResourceOutputStream = new MemoryStream();
    var newResourceWriter = new ResourceWriter(newResourceOutputStream);
    foreach (DictionaryEntry dllResourceEntry in dllResourceReader)
    {
       var image = (BitmapSource)new ImageSourceConverter().ConvertFrom(dllResourceEntry.Value);

       Color foreground = (Color)ColorConverter.ConvertFromString("#FFFFFF");
       var processed = (WriteableBitmap)ColorizeImage(image, foreground); // Your image processing function ?

       newResourceWriter.AddResource(dllResourceEntry.Key.ToString(), BitmapToByte(processed));       
    }
    newResourceWriter.Close();

    var newResource = new EmbeddedResource(dllResource.Name, dllResource.Attributes, newResourceOutputStream.ToArray());
    module.Resources.Remove(dllResource);
    module.Resources.Add(newResource);

    var woutput = new MemoryStream();

    asm.Write(woutput);
    var doutput = woutput.ToArray();
    Assembly assembly = Assembly.Load(doutput);
}
public static MemoryStream BitmapToByte(BitmapSource bitmapSource)
{
    var encoder = new System.Windows.Media.Imaging.PngBitmapEncoder();
    var frame = System.Windows.Media.Imaging.BitmapFrame.Create(bitmapSource);
    encoder.Frames.Add(frame);
    var stream = new MemoryStream();
    encoder.Save(stream);
    return stream;
}
public static void AttachAssembly(string myAsmFileName)
{
    Assembly assembly = Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + myAsmFileName); // LoadFrom
    AppDomain.CurrentDomain.Load(assembly.GetName());
}

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

0 голосов
/ 18 декабря 2018

Вы пытались создать Bitmap, а затем установить его как изображение source?Я думаю, что это должно быть легко.Дайте вашему изображению имя, скажем theImage.Вы не можете ссылаться на изображение, не дав ему имя.Попробуйте следующее:

string path="/Pics/Image3.png";//path to the image
var bitmapImage=new Bitmap(new Uri(path));
theImage.source=bitmapImage;//set the bitmap as the source.

Однако есть и другие способы достижения этого.Надеюсь, это поможет?

...