Images in Background Workers in WPF Application

后端 未结 1 817
傲寒
傲寒 2020-12-22 08:24

I have the following code snippet that I use to create a List to add to a scrollviewer as a binding in a WPF application:

private void LoadThumbs(object send         


        
相关标签:
1条回答
  • 2020-12-22 09:13

    Do not create Image elements in code behind. Instead, use an ItemControl with an appropriate ItemTemplate:

    <ScrollViewer>
        <ItemsControl ItemsSource="{Binding Images}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Image Source="{Binding}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </ScrollViewer>
    

    Bind it to a view model like shown below, which is capable of asynchronously loading the image files. It is important that the BitmapImages are frozen to make them cross-thread accessible.

    public class ViewModel
    {
        public ObservableCollection<ImageSource> Images { get; }
            = new ObservableCollection<ImageSource>();
    
        public async Task LoadImagesAsync(IEnumerable<string> filenames)
        {
            foreach (var filename in filenames)
            {
                Images.Add(await Task.Run(() => LoadImage(filename)));
            }
        }
    
        public ImageSource LoadImage(string filename)
        {
            var bitmap = new BitmapImage();
            bitmap.BeginInit();
            bitmap.CacheOption = BitmapCacheOption.OnLoad;
            bitmap.DecodePixelWidth = 200;
            bitmap.UriSource = new Uri(filename);
            bitmap.EndInit();
            bitmap.Freeze();
            return bitmap;
        }
    }
    

    which is initialized like this:

    private ViewModel viewModel = new ViewModel();
    
    public MainWindow()
    {
        InitializeComponent();
        DataContext = viewModel;
    }
    
    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        ...
        await viewModel.LoadImagesAsync(..., "*.jpg"));
    }
    

    An alternative view model method could load the BitmapImages directly from a FileStream instead of an Uri:

    public ImageSource LoadImage(string filename)
    {
        using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read))
        {
            var bitmap = new BitmapImage();
            bitmap.BeginInit();
            bitmap.DecodePixelWidth = 200;
            bitmap.CacheOption = BitmapCacheOption.OnLoad;
            bitmap.StreamSource = stream;
            bitmap.EndInit();
            bitmap.Freeze();
            return bitmap;
        }
    }
    
    0 讨论(0)
提交回复
热议问题