Image UriSource и привязка данных

Я пытаюсь привязать список настраиваемых объектов к изображению WPF следующим образом:

<Image>
    <Image.Source>
        <BitmapImage UriSource="{Binding Path=ImagePath}" />
    </Image.Source>
</Image>

Но это не работает. Я получаю вот такую ​​ошибку:

«Должно быть установлено свойство« UriSource »или свойство« StreamSource ».

Что мне не хватает?


person urini    schedule 21.08.2008    source источник
comment
К сожалению, настоящая причина этого не объясняется в ответах. См. this (По какой-то причине WPF / XAML не 'не поддерживает прямую привязку объекта Uri к UriSource объекта BitmapImage. При запуске приложение выдает ошибку,)   -  person mins    schedule 25.08.2020


Ответы (6)


WPF имеет встроенные преобразователи для определенных типов. Если вы привяжете свойство изображения Source к значению string или Uri, внутри WPF будет использоваться ImageSourceConverter, чтобы преобразовать значение в ImageSource.

So

<Image Source="{Binding ImageSource}"/>

работал бы, если бы свойство ImageSource было строковым представлением действительного URI изображения.

Вы, конечно, можете свернуть свой собственный конвертер привязок:

public class ImageConverter : IValueConverter
{
    public object Convert(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        return new BitmapImage(new Uri(value.ToString()));
    }

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

и используйте это так:

<Image Source="{Binding ImageSource, Converter={StaticResource ImageConverter}}"/>
person Brian Leahy    schedule 21.08.2008
comment
(На самом деле преобразователь типов создает не BitmapImage, а другой подкласс ImageSource: BitmapFrameDecode, который является внутренним.) - person H.B.; 27.09.2011
comment
@ H.B. Как бы вы преобразовали обратно, если бы вы хотели сохранить изменение изображения? - person Igor; 16.06.2014
comment
Альтернатива конвертеру: сделайте свое свойство, к которому вы привязываете (здесь: ImageSource), типа Uri или BitmapImage и приведите его туда. Если вам нужно иметь дело с возможными null значениями (сбой приведения и т. Д.), Добавьте TargetNullValue={x:Null} в вашу привязку. - person Gerrit; 28.10.2015
comment
Сработало отлично! ты - person Mohammed A. Fadil; 21.10.2019
comment
Как это объясняет сообщение об ошибке Необходимо установить свойство «UriSource» или свойство «StreamSource»? (что было не так в коде OP, который устанавливает путь с помощью Uri?) - person mins; 25.08.2020

В этой статье Атула Гупты есть пример кода, который охватывает несколько сценариев:

  1. Обычная привязка изображения ресурса к свойству Source в XAML
  2. Привязка изображения ресурса, но из кода позади
  3. Привязка изображения ресурса в коде позади с помощью Application.GetResourceStream
  4. Загрузка изображения из пути к файлу через поток памяти (то же самое применимо при загрузке данных изображения блога из базы данных)
  5. Загрузка изображения из пути к файлу, но с использованием привязки к пути к файлу Свойство
  6. Привязка данных изображения к пользовательскому элементу управления, который внутренне имеет элемент управления изображением через свойство зависимости
  7. То же, что и пункт 5, но также гарантирует, что файл не будет заблокирован на жестком диске.
person Drew Noakes    schedule 14.05.2009

Вы также можете просто установить атрибут Source, а не использовать дочерние элементы. Для этого вашему классу необходимо вернуть изображение как растровое изображение. Вот пример того, как я это сделал

<Image Width="90" Height="90" 
       Source="{Binding Path=ImageSource}"
       Margin="0,0,0,5" />

И свойство класса просто это

public object ImageSource {
    get {
        BitmapImage image = new BitmapImage();

        try {
            image.BeginInit();
            image.CacheOption = BitmapCacheOption.OnLoad;
            image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
            image.UriSource = new Uri( FullPath, UriKind.Absolute );
            image.EndInit();
        }
        catch{
            return DependencyProperty.UnsetValue;
        }

        return image;
    }
}

Я полагаю, это может быть немного больше работы, чем преобразователь значений, но это другой вариант.

person palehorse    schedule 21.08.2008
comment
Подобная реализация идеально подходит для случаев, когда ваш растровый ресурс уже загружен в ваш объект и вы хотите передать биты привязке. БЛАГОДАРНОСТЬ! - person Scott Fletcher; 17.10.2008

У вас должна быть реализация IValueConverter интерфейс, который преобразует uri в изображение. Ваша реализация Convert IValueConverter будет выглядеть примерно так:

BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(value as string);
image.EndInit();

return image;

Тогда вам нужно будет использовать конвертер в своей привязке:

<Image>
    <Image.Source>
        <BitmapImage UriSource="{Binding Path=ImagePath, Converter=...}" />
    </Image.Source>
</Image>
person Dale Ragan    schedule 21.08.2008
comment
Похоже, конвертер возвращает BitmapImage, и результат должен быть назначен непосредственно Image.Source, а не другому BitmapImage UriSource. - person mins; 25.08.2020

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

Это приводит к постоянному созданию новых дескрипторов файлов и блокирует любую попытку удалить файл, поскольку он все еще используется. Это можно проверить с помощью Process Explorer.

Если в какой-то момент файл изображения может быть удален, можно использовать такой конвертер: с использованием XAML для привязки к System.Drawing.Image в элемент управления System.Windows.Image

Недостатком этого метода потока памяти является то, что изображения загружаются и декодируются каждый раз, и кеширование не может происходить: «Чтобы изображения не декодировались более одного раза, назначьте свойство Image.Source из Uri вместо использования потоки памяти "Источник:" Советы по производительности для приложений Магазина Windows, использующих XAML "

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

person Luis Cantero    schedule 15.12.2012

вы можете использовать

ImageSourceConverter класс

получить то, что ты хочешь

    img1.Source = (ImageSource)new ImageSourceConverter().ConvertFromString("/Assets/check.png");
person Karthik Krishna Baiju    schedule 20.10.2013