WPF Listbox с изображениями - как определить, не загружено ли изображение - PullRequest
1 голос
/ 27 сентября 2010

У меня есть wpf ListBox, и у каждого элемента есть изображение, которое список должен загрузить с сервера - определение списка выглядит так:

<ListBox x:Name="List" BorderThickness="0" AlternationCount="2" ItemContainerStyle="{StaticResource alternatingWithBinding}" 
     HorizontalContentAlignment="Stretch"  ScrollViewer.HorizontalScrollBarVisibility="Hidden">
<ListBox.ItemTemplate>
    <DataTemplate>
        <Grid x:Name="itemsGrid" Margin="3" ShowGridLines="False" >
            <Grid.RowDefinitions>
                <RowDefinition Height="59"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="45" />
                <ColumnDefinition Width="60" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="150" />
            </Grid.ColumnDefinitions>

            <Button x:Name="btn" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Tag="{Binding}" 
                CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" />
            <Image x:Name="Thumb" Grid.Column="1" Stretch="Uniform" Opacity="1.0" Source="{Binding Path=Image, Converter={StaticResource ImageConverter}}" Height="65" VerticalAlignment="Center"/>
            <TextBlock x:Name="Name" Grid.Column="2" Padding="2" Margin="17,0" VerticalAlignment="Center" Text="{Binding Path=Name}"
                       Tag="{Binding}" />
        </Grid>
        <DataTemplate.Triggers>
            ...
        </DataTemplate.Triggers>
    </DataTemplate>
</ListBox.ItemTemplate>

и конвертервыглядит так:

    public class ImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
            if (value is string)
            {
                value = new Uri((string)value);
            }

            if (value is Uri)
            {
                BitmapImage bi = new BitmapImage();
                bi.BeginInit();
                bi.DecodePixelWidth = 150;
                bi.UriSource = value;
                bi.DownloadFailed += new EventHandler<ExceptionEventArgs>(bi_DownloadFailed);
                bi.EndInit();
                return bi;
            }

            return null;
    }

Идея состоит в том, чтобы показать изображение по умолчанию, когда sourceUrl ничего не возвращает с сервера.Но так как я использую конвертер в коде XAML,

Source="{Binding Path=Image, Converter={StaticResource ImageConverter}}"

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

Ответы [ 2 ]

1 голос
/ 28 сентября 2010

Вы смотрели на свойство TargetNullValue класса Binding?

Если бы вы не смогли загрузить файл, конвертер вернул бы ноль.


 public object Convert(object value, Type targetType, 
  object parameter, System.Globalization.CultureInfo culture)
{

  if (parameter.ToString()=="blue")
  {
    return new Uri("Butterfly1.png", UriKind.RelativeOrAbsolute);
  }
  return null;
}

Затем настройте изображение по умолчанию в XAML

<Window.Resources>
<my:ImageConverter x:Key='ImageConverter1' />
<BitmapImage x:Key='defaultImage'
             UriSource='/WpfApplication1;component/default.png' />


Затем в привязке укажите TargetNullValue.


 <Image   Source='{Binding Converter={StaticResource ImageConverter1},
  ConverterParameter="red",TargetNullValue={StaticResource defaultImage}}'
         Height='100' />
<Image   Source='{Binding Converter={StaticResource ImageConverter1},
  ConverterParameter="blue",TargetNullValue={StaticResource defaultImage}}'
         Height='100' />

0 голосов
/ 28 сентября 2010

Хммм .... Я считаю, что загрузка происходит на EndInit, что имеет значение. Поскольку вы используете статический ресурс для конвертера, у вас будет один экземпляр для каждого приложения. Это означает, что если вы создадите переменную в области класса и будете использовать ее для хранения результатов загрузки, у вас могут возникнуть проблемы, если вы не будете осторожны с состоянием ваших переменных между вызовами Convert. Однако, поскольку пользовательский интерфейс отображается в одном потоке, вам не нужно сильно беспокоиться.

public class ImageConverter : IValueConverter
{
    private static readonly BitmapImage _default = MakeDefault();
    private bool _downloadFailed;

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
        if (value is string)
        {
            value = new Uri((string)value);
        }

        if (value is Uri)
        {
            _downloadFailed = false;
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.DecodePixelWidth = 150;
            bi.UriSource = value;
            // the event handler sets _downloadFailed to true!
            bi.DownloadFailed += bi_DownloadFailed;
            bi.EndInit();
            // unhook so we don't unintentionally keep the instance alive
            // this is important; you will leak BI instances otherwise!
            bi.DownloadFailed -= bi_DownloadFailed;
            if(_downloadFailed)                
              return _default;
            return bi;
        }

        return null;
}
...