异步加载的图像同时显示在UI中

时间:2017-04-05 11:36:05

标签: c# wpf xaml asynchronous

MediaImage类(型号)

public class MediaImage : INotifyPropertyChanged
{
    public MediaImage(FileSystemInfo file)
    {
        this.Uri = new Uri(file.FullName);
        this.Label = file.Name;

        var getThumbnail = this.LoadThumbnail(this.Uri);

        getThumbnail.ContinueWith(task =>
        {
            this.Thumbnail = task.Result;
        });
    }

    public Uri Uri { get; }

    public string Label { get; private set; }

    private BitmapImage thumbnail;

    public BitmapImage Thumbnail
    {
        get { return this.thumbnail; }
        private set
        {
            this.thumbnail = value;
            this.OnPropertyChanged();
        }
    }
    private async Task<BitmapImage> LoadThumbnail(Uri uri)
    {
        return await Task.Run(() => this.GenerateThumbnail(uri));
    }

    private BitmapImage GenerateThumbnail(Uri uri)
    {
        var sourceBitmap = new BitmapImage();

        sourceBitmap.BeginInit();
        sourceBitmap.CacheOption = BitmapCacheOption.OnLoad;
        sourceBitmap.DecodePixelWidth = 100;
        sourceBitmap.UriSource = uri;
        sourceBitmap.EndInit();
        sourceBitmap.Freeze();

        return sourceBitmap;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

MainWindow C#

public partial class MainWindow
{
    public MainWindow()
    {
        this.InitializeComponent();
    }

    private void OnLoadImagesClick(object sender, RoutedEventArgs e)
    {
        var dialog = new FolderBrowserDialog();
        if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
            this.MediaImageView.LoadImages(dialog.SelectedPath);
        }
    }
}

ImageView XAML (界面)

<Grid>
    <ListBox Style="{DynamicResource ImageViewListBoxStyle}"
             ItemsSource="{Binding Images}"
             ItemContainerStyle="{DynamicResource ImageViewListBoxItemStyle}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.RowDefinitions>
                            <RowDefinition Height="*" />
                            <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <TextBlock Panel.ZIndex="1000" Grid.Row="1" Text="{Binding Label}" Foreground="White" Width="100" Height="20" TextTrimming="CharacterEllipsis" VerticalAlignment="Center">
                        <TextBlock.Background>
                            <SolidColorBrush Opacity="0.50" Color="Black"/>
                        </TextBlock.Background>
                    </TextBlock>
                    <Image Grid.Row="0" Grid.RowSpan="2" Source="{Binding Thumbnail, UpdateSourceTrigger=PropertyChanged}" Width="100" Height="100"/>
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

ImageView C#(接口代码)

public partial class ImageView
{
    public ImageView()
    {
        this.InitializeComponent();
        this.Images = new ObservableCollection<MediaImage>();
        this.DataContext = this;
    }

    public ObservableCollection<MediaImage> Images { get; }

    public void LoadImages(string path)
    {
        this.Images.Clear();

        var option = SearchOption.TopDirectoryOnly;

        var files = new DirectoryInfo(path).EnumerateFiles("*", option);

        foreach (var file in files)
        {
            // Skip images already in our image collection
            if (this.Images.Any(x => x.Uri.AbsolutePath == file.FullName))
            {
                continue;
            }

            this.Images.Add(new MediaImage(file));
        }
    }
}

问题行为的Gif

enter image description here

备注

通过研究和学习,我的理解是通过在我的XAML中将UpdateSourceTrigger设置为PropertyChanged,当异步任务完成且Thumbnail属性触发时,每个Image都应更新它的绑定PropertyChanged事件。

ListBox中的每个图像都应该在异步任务完成时更新它的源代码(无论其他图像和任务如何)但似乎没有发生。在我当前的构建中,似乎所有图像在最后一个任务完成时都会更新。

问题

是否有一种简单的方法来修改我的代码,以便我的模型(MediaImage)异步更新某些属性,并且ListBox在任务完成时更新每个项目(最好通过PropertyChanged事件)?

1 个答案:

答案 0 :(得分:0)

我的解决方案简而言之:

首先,您必须将其可见性设置为false。 比你必须等待加载所有图像。 您可以使用FrameworkElement.Loaded事件(https://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.loaded(v=vs.110).aspx)。 最后,如果每个图像都已成功加载,请将其可见性设置为true。