How to load and show images asynchronously

后端 未结 1 567
面向向阳花
面向向阳花 2020-12-12 04:24

I\'m new to WPF but I\'ve done C# for quite some time now and I am currently developing a simple window (Windows Desktop) that should visualize all photos in a directory. Th

相关标签:
1条回答
  • 2020-12-12 05:06

    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();
        }
    }
    
    0 讨论(0)
提交回复
热议问题