Was ist der beste Weg, um asynchron ein BitmapImage in C# mit WPF zu laden?
BackgroundWorker ist im System.ComponentModel-Namensraum der System.dll definiert, nicht in Windows Forms, so ist es in Ordnung, es für WPF zu verwenden.
Was ist der beste Weg, um asynchron ein BitmapImage in C# mit WPF zu laden?
Ich habe mir das gerade angeschaut und musste meinen Senf dazugeben, wenn auch ein paar Jahre nach dem ursprünglichen Beitrag (nur für den Fall, dass jemand anderes nach der gleichen Sache sucht, die ich mir angeschaut habe).
Ich habe eine Bild Steuerelement, dessen Bild im Hintergrund geladen werden muss, mit einer Stream und dann angezeigt.
Das Problem, auf das ich immer wieder gestoßen bin, ist, dass die BitmapSource ist es Stream Quelle und die Quelle Bild Die Kontrollen mussten alle im selben Thread stattfinden.
In diesem Fall führt die Verwendung einer Bindung und die Einstellung IsAsynch = true zu einer threadübergreifenden Ausnahme.
Ein BackgroundWorker ist großartig für WinForms, und Sie können dies in WPF verwenden, aber ich ziehe es vor, die WinForm-Assemblies in WPF zu vermeiden (Aufblähung eines Projekts wird nicht empfohlen, und es ist auch eine gute Faustregel). Dies sollte eine ungültige Querverweis Ausnahme in diesem Fall auch werfen, aber ich habe es nicht getestet.
Es hat sich herausgestellt, dass eine Zeile Code ausreicht, um alle diese Funktionen auszuführen:
//Create the image control
Image img = new Image {HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch, VerticalAlignment = System.Windows.VerticalAlignment.Stretch};
//Create a seperate thread to load the image
ThreadStart thread = delegate
{
//Load the image in a seperate thread
BitmapImage bmpImage = new BitmapImage();
MemoryStream ms = new MemoryStream();
//A custom class that reads the bytes of off the HD and shoves them into the MemoryStream. You could just replace the MemoryStream with something like this: FileStream fs = File.Open(@"C:\ImageFileName.jpg", FileMode.Open);
MediaCoder.MediaDecoder.DecodeMediaWithStream(ImageItem, true, ms);
bmpImage.BeginInit();
bmpImage.StreamSource = ms;
bmpImage.EndInit();
//**THIS LINE locks the BitmapImage so that it can be transported across threads!!
bmpImage.Freeze();
//Call the UI thread using the Dispatcher to update the Image control
Dispatcher.BeginInvoke(new ThreadStart(delegate
{
img.Source = bmpImage;
img.Unloaded += delegate
{
ms.Close();
ms.Dispose();
};
grdImageContainer.Children.Add(img);
}));
};
//Start previously mentioned thread...
new Thread(thread).Start();
BackgroundWorker ist im System.ComponentModel-Namensraum der System.dll definiert, nicht in Windows Forms, so ist es in Ordnung, es für WPF zu verwenden.
Angenommen, Sie verwenden Datenbindung und setzen Binding.IsAsync Eigenschaft auf True zu setzen, scheint ein Standardweg zu sein, um dies zu erreichen. Wenn Sie die Bitmap in der Code-Behind-Datei mit Hintergrund-Thread + Dispatcher-Objekt laden ist ein gemeinsamer Weg, um UI asynchron zu aktualisieren
@Jmix90: Es ist nicht klar, auf welchen Teil der Antwort Sie sich beziehen. Wie auch immer: mit Binding.IsAsync
erlaubt die Angabe eines Uri/Pfades in einer Image.Source
und lassen Sie das Bild automatisch asynchron laden. WPF kümmert sich in diesem Szenario um alle Thread-übergreifenden Probleme. Wenn man Bitmaps in einem Hintergrund-Thread erstellt, muss man einfach Freeze()
auf das Bitmap-Objekt, bevor es an den UI-Thread weitergegeben wird. Es wird nur eine Ausnahme geworfen, wenn Sie es falsch machen.
Dadurch können Sie das BitmapImage auf dem UI-Thread erstellen, indem Sie den HttpClient verwenden, um das asynchrone Herunterladen durchzuführen:
private async Task<BitmapImage> LoadImage(string url)
{
HttpClient client = new HttpClient();
try
{
BitmapImage img = new BitmapImage();
img.CacheOption = BitmapCacheOption.OnLoad;
img.BeginInit();
img.StreamSource = await client.GetStreamAsync(url);
img.EndInit();
return img;
}
catch (HttpRequestException)
{
// the download failed, log error
return null;
}
}
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.