Let's take a look at a basic example without a UserControl.
The first step is to create a view model to enable data binding. You would make the Photo class implement the INotifyPropertyChanged
interface to update bindings when property values change.
The class below also declares an Image
property that holds an ImageSource
derived object, which is loaded asynchronously.
public class Photo : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(propertyName));
}
public string FileName { get; set; }
private string iso = string.Empty;
public string ISO
{
get { return iso; }
set
{
iso = value;
NotifyPropertyChanged(nameof(ISO));
}
}
private ImageSource image;
public ImageSource Image
{
get { return image; }
set
{
image = value;
NotifyPropertyChanged(nameof(Image));
}
}
public async Task Load()
{
Image = await Task.Run(() =>
{
using (var fileStream = new FileStream(
FileName, FileMode.Open, FileAccess.Read))
{
return BitmapFrame.Create(
fileStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
});
ISO = "1600";
}
}
The second part of the view model is a class that holds a collection of Photo
instances:
public class ViewModel
{
public ObservableCollection<Photo> Photos { get; }
= new ObservableCollection<Photo>();
}
For the typical data binding scenario, you would assign an instance of this class to the DataContext
of your Window, either in code or in XAML:
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
The last part is the declaration of the ListBox with a DataTemplate
that visualizes a Photo
:
<ListBox ItemsSource="{Binding Photos}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}" Width="100" Height="100"/>
<StackPanel>
<TextBlock Text="{Binding ISO, StringFormat=ISO: {0}}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now you could fill the Photos
collection for instance in an asynchronous Loaded
event handler of the MainWindow like this:
private async void Window_Loaded(object sender, RoutedEventArgs e)
{
var vm = (ViewModel)DataContext;
foreach (var file in Directory.EnumerateFiles(...))
{
vm.Photos.Add(new Photo { FileName = file });
}
foreach (var photo in vm.Photos)
{
await photo.Load();
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…