Мое приложение ссылается на библиотеку классов (.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 библиотеки классов?
Благодарю!
Есть несколько вещей, которые, как я думаю, вы могли бы прочитать, чтобы помочь вам справиться с вашей проблемой. Я бы начал с 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"
который будет работать только в том случае, если этот путь к файлу существует в сборке, которая его вызвала, - это значит, что это не сработает для вас, поскольку вы звоните с другой сборки.
Надеюсь это поможет!
Уже существует класс 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-изображения. В противном случае вам нужно будет добавить шаг преобразования.
pack:
URI можно использовать для доступа к файлам, скомпилированным какResource
илиContent
, их нельзя использовать для доступа к ресурсам, скомпилированным какEmbedded Resource
(.resx
).