Предоставление исходного заполнителя изображения для класса WPF Image - PullRequest
0 голосов
/ 10 августа 2011

Когда я запускаю проект, возникает ошибка времени выполнения: Ошибка: должно быть установлено свойство 'UriSource' или свойство 'StreamSource'.потому что this.ImageUri имеет значение null, я не знаю, почему this.ImageUri будет иметь значение null!помогите мне

Я работал с WPF ListBox, используя изображения в качестве элементов списка.Путь к источнику изображения указывает на сервер, на котором размещены эти изображения.Находясь в быстрой сети, изображения появлялись без заметной задержки.Однако по медленной ссылке стало очевидно, что пользовательский опыт ухудшился, и я действительно хотел показать изображение заполнителя, пока изображение загружалось и декодировалось.

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

Пример XAML ниже взят из моего стиля контейнера элемента.Я заменил Image на мою локальную реализацию класса local: ImageLoader.

<Window.Resources>
<DataTemplate DataType="{x:Type local:MyData}">
...
<StackPanel Grid.Column="0" Margin="5">
<Border BorderThickness="0">
<MyControl:ImageLoader Width="50" Height="50" ImageUri="{Binding Path=profile_image_url_https, FallbackValue=profile_image_url_https}" InitialImage="/MyProject;component/Images/nopic.png"  HorizontalAlignment="Left"></imgz:ImageLoader>
</Border>
</StackPanel>
...
</DataTemplate>
</Window.Resources>

<Grid>
<ListBox ItemsSource="{Binding Source = {StaticResource MyData}}"    />
</Grid>

Суть обработки исходного изображения - в методе OnLoaded (), где я использую BitmapImage в качестве источника и устанавливаю UriSourceк свойству зависимостей ImageUri производного класса, которое позволяет связывать данные.Исходное изображение обновляется до фактического изображения, когда загрузка завершена или когда получено событие сбоя.Этот класс также позволяет вам указать «LoadFailedImage».

public class ImageLoader : Image
{
    public static readonly DependencyProperty ImageUriProperty = DependencyProperty.Register(
        "ImageUri", typeof(Uri), typeof(ImageLoader), new PropertyMetadata(null, null));

    private BitmapImage loadedImage;

    public ImageLoader()
    {
        this.Loaded += this.OnLoaded;
    }

    public string LoadFailedImage
    {
        get;
        set;
    }

    public Uri ImageUri
    {
        get {return this.GetValue(ImageUriProperty) as Uri;}
        set {this.SetValue(ImageUriProperty, value);}
    }

    public string InitialImage
    {
        get;
        set;
    }

    private new ImageSource Source
    {
        get {return base.Source;}
        set {base.Source = value;}
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        // Loading the specified image            
        this.loadedImage = new BitmapImage();
        this.loadedImage.BeginInit();
        this.loadedImage.CacheOption = BitmapCacheOption.OnDemand;
        this.loadedImage.DownloadCompleted += this.OnDownloadCompleted;
        this.loadedImage.DownloadFailed += this.OnDownloadFailed;
        this.loadedImage.UriSource = this.ImageUri;
        this.loadedImage.EndInit();

        // The image may be cached, in which case we will not use the initial image
        if (!this.loadedImage.IsDownloading)
        {
            this.Source = this.loadedImage;
        }
        else
        {
            // Create InitialImage source if path is specified
            if (!string.IsNullOrWhiteSpace(this.InitialImage))
            {
                BitmapImage initialImage = new BitmapImage();

                // Load the initial bitmap from the local resource
                initialImage.BeginInit();
                initialImage.UriSource = new Uri(this.InitialImage, UriKind.Relative);
                initialImage.DecodePixelWidth = (int)this.Width;
                initialImage.EndInit();

                // Set the initial image as the image source
                this.Source = initialImage;                
            }
        }

        e.Handled = true;
    }

    private void OnDownloadFailed(object sender, ExceptionEventArgs e)
    {
        if (!string.IsNullOrWhiteSpace(this.LoadFailedImage))
        {
            BitmapImage failedImage = new BitmapImage();

            // Load the initial bitmap from the local resource
            failedImage.BeginInit();
            failedImage.UriSource = new Uri(this.LoadFailedImage, UriKind.Relative);
            failedImage.DecodePixelWidth = (int)this.Width;
            failedImage.EndInit();
            this.Source = failedImage;
        }
    }

    private void OnDownloadCompleted(object sender, EventArgs e)
    {
        this.Source = this.loadedImage;
    }
}

Когда я запускаю проект, возникает ошибка времени выполнения: Ошибка: должно быть установлено свойство 'UriSource' или свойство 'StreamSource'.потому что this.ImageUri имеет значение null, я не знаю, почему this.ImageUri будет иметь значение null!помоги мне

1 Ответ

2 голосов
/ 10 августа 2011

Если это не точка с запятой в InitialImage = "/ MyProject; component / Images / nopic.png",может быть, лучше установить InitialImage по умолчанию в ImageUri

 public static readonly DependencyProperty ImageUriProperty = DependencyProperty.Register(
    "ImageUri", typeof(Uri), typeof(ImageLoader), new PropertyMetadata(new Uri("/MyProject/component/Images/nopic.png"), null));

UPDATE:
Вы должны связать с Image.Source и использовать PriorityBinding для отображения заполнителя.

<Image.Source>
    <PriorityBinding>
        <!--highest priority sources are first in the list-->
        <Binding Path="YourImageUri"
           IsAsync="True" />
        <Binding Path="InitialImageUri"
           IsAsync="True" />
    </PriorityBinding>
</Image.Source>

Для "LoadFailedImage" a будет подписываться на Image.ImageFailed Событие.
Надеюсь, это поможет.

...