Reputation: 261
Why leaps exception in the load method? If it is to make simultaneous , everything works well . Tell me, please , what is the problem and how to fix it ?
public class MainViewModel : ViewModelBase
{
private readonly List<string> _listImageUri;
private int _currentIndex;
private ImageSource _currentImage;
public ObservableCollection<Image> CustomControls { get; set; } = new ObservableCollection<Image>();
public MainViewModel()
{
_listImageUri = new List<string>();
Load("путь к папке");
}
private async void Load(string s)
{
await Task.Run(() =>
{
foreach (var fileInfo in new DirectoryInfo(s).GetFiles())
{
_listImageUri.Add(fileInfo.FullName);
Image img = new Image(); // exception
img.Height = 100;
img.Margin = new Thickness(5);
img.Width = 100;
BitmapImage bmp = new BitmapImage();
bmp.BeginInit();
bmp.UriSource = new Uri(fileInfo.FullName);
bmp.DecodePixelWidth = 100;
bmp.EndInit();
img.Source = bmp;
CustomControls.Add(img);
OnPropertyChanged(nameof(CustomControls));
}
});
}
}
Exception
An unhandled exception of type 'System.InvalidOperationException' occurred in mscorlib.dll
Additional information: The calling thread must be STA, because many UI components require this.
Upvotes: 0
Views: 955
Reputation: 128096
Do not create Image
controls in your view model, especially not when you load images asynchronously.
Change your view model to have an ObservableCollection of ImageSource
:
public ObservableCollection<ImageSource> Images { get; set; }
= new ObservableCollection<ImageSource>();
Then in your load method make sure that adding images to the collection is done in the UI thread. To make the BitmapImages cross-thread accessible, you also have to freeze them:
var bitmap = new BitmapImage(new Uri(fileInfo.FullName));
bitmap.Freeze();
Application.Current.Dispatcher.BeginInvoke(new Action(() => Images.Add(bitmap)));
Finally display the images by means of an ItemsControl with an appropriate ItemTemplate:
<ItemsControl ItemsSource="{Binding Images}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
That said, you may also replace the ObservableCollection<ImageSource>
by an ObservableCollection<string>
, which would hold the image file paths. This is possible because WPF provides built-in conversion from string
(and Uri
) to ImageSource
. Consequently, you would then also not need any asynchronous task anymore.
Upvotes: 3
Reputation: 480
You run your code in a thread. But updating UI components need to run on the WPF UI thread.
So invoke the critical line(s) using Dispatcher.Invoke so that your code is using the UI-Thread
Upvotes: -2