ImageSource в библиотеке классов не будет отображаться

1

Мое приложение ссылается на библиотеку классов (.dll). В проекте библиотеки классов три изображения были помещены в Resource.resx. Одно изображение должно быть выбрано во время выполнения и показано на кнопке. После googling вокруг, я решил использовать конвертер, чтобы помочь привязке в xaml:

[ValueConversion(typeof(Side), typeof(ImageSource))]
public class SideToImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Side side = (Side)value;
        switch (side)
        {
            case Side.Left:
                return ToWpfBitmap(Properties.Resources.LeftArmOnCart);
            case Side.Right:
                return ToWpfBitmap(Properties.Resources.RightArmOnCart);
            case Side.Both:
                return ToWpfBitmap(Properties.Resources.RightArmOnCart);
            default:
                throw new ArgumentException("Current configuration is invalid");
        }
    }

    private static BitmapSource ToWpfBitmap(Bitmap bitmap)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            bitmap.Save(stream, ImageFormat.Png);

            stream.Position = 0;
            BitmapImage result = new BitmapImage();
            result.BeginInit();
            // According to MSDN, "The default OnDemand cache option retains access to the stream until the image is needed."
            // Force the bitmap to load right now so we can dispose the stream.
            result.CacheOption = BitmapCacheOption.OnLoad;
            result.StreamSource = stream;
            result.EndInit();
            result.Freeze();
            return result;
        }
    }
}

Код xaml выглядит так:

<Image Source="{Binding Side, Converter={StaticResource SideToImageConverter}}" .../>

К сожалению, изображение не будет отображаться без каких-либо исключений. Отладка в код конвертера, аргумент битмапа в ToWpfBitmap() выглядит отлично (значения Width/Height были правильными).

BTW, как еще одно испытание, следующий код работает нормально.

[ValueConversion(typeof(Side), typeof(ImageSource))]
public class SideToImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Side side = (Side)value;
        switch (side)
        {
            case Side.Left:
                return LoadBitmap("LeftArmOnCart.png");
            case Side.Right:
                return LoadBitmap("RightArmOnCart.png");
            case Side.Both:
                return LoadBitmap("RightArmOnCart.png");
            default:
                throw new ArgumentException("Current configuration is invalid");
        }
    }

    private static BitmapSource LoadBitmap(string name)
    {
        BitmapImage result = new BitmapImage();
        result.BeginInit();
        string uri = "c:/.../Resources/Images/" + name;
        result.CacheOption = BitmapCacheOption.OnLoad;
        result.UriSource = new Uri(uri, UriKind.Absolute);
        result.EndInit();
        return result;
    }
}

Однако абсолютный путь нежелателен. Итак, я пропущу что-нибудь?

Я понимаю, что можно использовать относительный путь, выпуская три файла изображений. Но, возможно ли НЕ выпускать три файла, а только DLL библиотеки классов?

Благодарю!

Теги:
xaml
wpf

2 ответа

0
Лучший ответ

Есть несколько вещей, которые, как я думаю, вы могли бы прочитать, чтобы помочь вам справиться с вашей проблемой. Я бы начал с URI пакета в WPF, чтобы вы могли понять, как использовать URI для проверки определенного расположения библиотеки. Поскольку эти изображения находятся в другом файле ресурсов сборки, прочитайте "Ссылка на файл сборки ссылок" в ссылке.

Я думаю, что другая вещь, о которой стоит упомянуть, заключается в том, что разница между двумя методами заключается в том, что вы предоставляете UriSource (внизу), а другой - нет. Глядя на Image.Source, при использовании в XAML он ожидает imageUri. С этим намеком мы можем сказать, что это определенно связано с URI.

Фактически, ваши изображения уже сохранены как поток внутри библиотек, в которых они существуют, поэтому нам не нужно ничего делать с созданием нового растрового изображения или того, что вы делаете, вместо этого мы можем просто предоставить допустимый URI пакета. и верните строку.

Я думаю, что что-то вроде этого должно работать, если имя библиотеки, в которой находятся изображения, это YourApp.Models, в YourApp.Models Resources\Images\:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    Side side = (Side)value;
    switch (side)
    {
        case Side.Left:
            return "pack://application:,,,/YourApp.Models;component/Resources/Images/LeftArmOnCart.png";
        case Side.Right:
        case Side.Both:
            return "pack://application:,,,/YourApp.Models;component/Resources/Images/RightArmOnCart.png";
        default:
            throw new ArgumentException("Current configuration is invalid");
    }
}

Примечание. Имена путей чувствительны к косой черте вперед/назад, именам сборки, компоненту. Убедитесь, что все правильно отформатировано.

Это считается абсолютным URI. Относительный URI будет просто "/Resources/Images/LeftArmOnCart.png" который будет работать только в том случае, если этот путь к файлу существует в сборке, которая его вызвала, - это значит, что это не сработает для вас, поскольку вы звоните с другой сборки.

Надеюсь это поможет!

  • 0
    Хотя pack: URI можно использовать для доступа к файлам, скомпилированным как Resource или Content , их нельзя использовать для доступа к ресурсам, скомпилированным как Embedded Resource ( .resx ).
  • 0
    Правда. Я бы, вероятно, добавил их в решение и установил бы их действие по сборке для Resource, если приложение не будет локализовано, а ваши изображения являются фирменными растровыми изображениями, которые вы не хотите изменять.
Показать ещё 1 комментарий
0

Уже существует класс InteropBitmap который можно использовать для преобразования растрового изображения GDI в WPF ImageSource, хотя я считаю, что он не очень хорошо обрабатывает альфа-каналы. Это механизм, который я использую:

public static BitmapSource CreateBitmapSourceFromGdiBitmap(Bitmap bitmap)
{
    if (bitmap == null)
        throw new ArgumentNullException("bitmap");

    var rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);

    var bitmapData = bitmap.LockBits(
        rect,
        ImageLockMode.ReadWrite,
        PixelFormat.Format32bppArgb);

    try
    {
        var size = (rect.Width * rect.Height) * 4;

        return BitmapSource.Create(
            bitmap.Width,
            bitmap.Height,
            bitmap.HorizontalResolution,
            bitmap.VerticalResolution,
            PixelFormats.Bgra32,
            null,
            bitmapData.Scan0,
            size,
            bitmapData.Stride);
    }
    finally
    {
        bitmap.UnlockBits(bitmapData);
    }
}

Обратите внимание, что эта реализация предполагает формат 32GB пикселей ARGB. Это должно быть хорошо, если вы используете PNG-изображения. В противном случае вам нужно будет добавить шаг преобразования.

  • 0
    Пробовал, но все равно не будет показывать молча, не бросая никаких исключений. Чувствую, что это по сути похоже на функцию ToWpfBitmap (), которую я использовал. Не так ли?
  • 0
    Не совсем то же самое - мой копирует уже декодированные данные растрового изображения, а ваш кодирует обратно в формат PNG, а затем снова декодирует. Меньше этапов, чтобы что-то пошло не так. Что такое PixelFormat растрового изображения, загруженного из ресурсов библиотеки?
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню