Hello! I am interested in this question: I have a collection of pictures asynchronously downloaded and attached to the wpf page, but during the download, when the value of each element of the pictures is null, I have empty space. How to upload a default image to this empty place? I tried the TargetNullValue parameter but there is no result.

A snippet of WPF code:

<ItemsControl Grid.Row="0" ItemsSource="{Binding RecentMedias}" > <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <UniformGrid Columns="5" Rows="6" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <Image Source="{Binding Path=Images, IsAsync=True, TargetNullValue=DefaultImage}"/> </Image> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> 

Scrap C #:

 private ImageSource defaultImage = null; public ImageSource DefaultImage { get { return defaultImage; } set { defaultImage = value; NotifyPropertyChanged("DefaultImage"); } } 
 public class SelectedMedia : INotifyPropertyChanged { private ImageSource images = null; public ImageSource Images { get { return images; } set { images = value; NotifyPropertyChanged("Images"); } } 
 public virtual event PropertyChangedEventHandler PropertyChanged; protected virtual void NotifyPropertyChanged(params string[] propertyNames) { if (PropertyChanged != null) { foreach (string propertyName in propertyNames) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); PropertyChanged(this, new PropertyChangedEventArgs("HasError")); } } 

    2 answers 2

    It works for me like this:

     <ItemsControl ItemsSource="{Binding}"> <ItemsControl.Resources> <BitmapImage x:Key="DefaultImageSource">D:\Loading.png</BitmapImage> </ItemsControl.Resources> <ItemsControl.ItemTemplate> <DataTemplate> <Image Source="{Binding Image, TargetNullValue={StaticResource DefaultImageSource}}" /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> 

    Instead of D:\Loading.png you need, of course, a real picture (probably pack URI, if you add to resources).


    If you really want to put the default picture in VM and attach to it via Binding , the following code will do:

     <ItemsControl ItemsSource="{Binding}"> <ItemsControl.Resources> <local:FirstNonNullValueConverter x:Key="FirstNonNullValueConverter"/> </ItemsControl.Resources> <ItemsControl.ItemTemplate> <DataTemplate> <Image Height="50"> <Image.Source> <MultiBinding Converter="{StaticResource FirstNonNullValueConverter}"> <Binding Path="Image"/> <Binding Path="DefaultImage"/> </MultiBinding> </Image.Source> </Image> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> 

    You will need to add the converter to the code-behind:

     public class FirstNonNullValueConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { return values.SkipWhile(v => v == null).FirstOrDefault(); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotSupportedException(); } } 

    ( PriorityBinding does almost what it takes, but almost .)

    • Thank you all very much for your help, everything worked out for me, there was another variant of writing through triggers, but everything worked for me. Thank you very much!! - A. Mikhail

    I propose to change the DataTemplate so that the loading image covers the placeHolder:

      <DataTemplate> <Grid> <Image x:Name="imgHolder" Source="Assets/placeHolderImage.jpg" Height="100" Width="100" /> <Image Source="{Binding Path=Images, IsAsync=True, TargetNullValue=DefaultImage}" Height="100" Width="100" /> </Grid> </DataTemplate>