Ok. Delete all your code and start all over.
This is how you do that in WPF:
<Window x:Class="WpfApplication14.ItemsControlSample2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ItemsControlSample2" WindowState="Maximized">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="DarkGray" BorderBrush="Black" BorderThickness="1" CornerRadius="5"
Width="100" Height="100" Margin="10" >
<Grid>
<Image x:Name="img" Source="{Binding ImageSource}" Margin="2"/>
<TextBlock x:Name="txt" Text="Loading..." FontWeight="Bold"
VerticalAlignment="Center" HorizontalAlignment="Center"
Visibility="Collapsed" Foreground="AliceBlue"/>
</Grid>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsLoading}" Value="True">
<Setter TargetName="img" Property="Source" Value="{x:Null}"/>
<Setter TargetName="txt" Property="Visibility" Value="Visible"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer>
<WrapPanel IsItemsHost="True"/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
</Window>
Code Behind:
public partial class ItemsControlSample2 : Window
{
public ItemsControlSample2()
{
InitializeComponent();
//Make sure you change this path to a valid path in your PC where you have JPG files
var path = @"F:\Media\Images\My Drums";
var images = Directory.GetFiles(path,"*.jpg")
.Select(x => new ImageViewModel()
{
Path = x,
});
DataContext = images.ToList();
}
}
Data Item:
public class ImageViewModel : INotifyPropertyChanged
{
private bool _isLoading;
public bool IsLoading
{
get { return _isLoading; }
set
{
_isLoading = value;
OnPropertyChanged("IsLoading");
}
}
private ImageSource _imageSource;
public ImageSource ImageSource
{
get { return _imageSource; }
set
{
_imageSource = value;
OnPropertyChanged("ImageSource");
}
}
private string _path;
public string Path
{
get { return _path; }
set
{
_path = value;
OnPropertyChanged("Path");
LoadImageAsync();
}
}
private void LoadImageAsync()
{
IsLoading = true;
var UIScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
{
var bmp = new BitmapImage();
bmp.BeginInit();
bmp.UriSource = new Uri(Path, UriKind.Relative);
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.EndInit();
bmp.Freeze();
return bmp;
}).ContinueWith(x =>
{
ImageSource = x.Result;
IsLoading = false;
},UIScheduler);
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
Result:
-
Notice how I’m declaratively defining the UI in XAML as opposed to procedurally creating it in C# code. This is a much cleaner approach because it lets WPF do it’s job
-
I’m using an
ItemsControl
which is the appropiate approach for all “items”-based UIs in WPF. Regardless of their visual appearance. -
Also notice how I’m leveraging DataBinding in order to populate the UI with actual data and also
DataTriggers
in order to create a basic stateful behavior.- While the image is loading (
IsLoading == true
), theImage.Source
is null and theTextBlock
is shown. - When the image finished loading (
IsLoading == false
), theImage.Source
is bound to the ViewModel data and theTextBlock
is hidden.
- While the image is loading (
-
See how I’m using a
WrapPanel
for layout instead of manually placing the items. This gives you an “Explorer-like” behavior. Try resizing the Window to see the results. -
I strongly suggest you read the above linked documentation, mostly the ItemsControl stuff and also Rachel’s WPF Mentality post.
-
WPF Rocks. Just copy and paste my code in a
File -> New Project -> WPF Application
and see the results for yourself. -
I’m Using C# 4.0 and .Net 4.0, so I don’t have
async/await
. You should be able to remove all theTask
based code and replace that by this newer, cleaner async approach. -
Let me know if you need further help.