Laden...

Bild kann nicht gelöscht werden, während es angezeigt wird

Erstellt von ASommer vor 2 Jahren Letzter Beitrag vor 2 Jahren 638 Views
A
ASommer Themenstarter:in
6 Beiträge seit 2022
vor 2 Jahren
Bild kann nicht gelöscht werden, während es angezeigt wird

Hallo,

vielleicht kann mir jemand helfen zu WPF MVVM

Ich habe eine Klasse (Bilder) erstellt, dazu eine ObservableCollection in einem ViewModel. Diese Speichert Informationen zu Bildern die auf dem Laufwerk liegen.

String Pfad {get; set;}
String Bildname {get; set;}
usw.

In der Klasse wird der Pfad zu den Bildern gespeichert z.B. Ablageort = C:// Bilder/meinBild.jpg

Die ObservableCollection wird dann in XAML (View) als Liste angezeigt.
<Image Source="{Binding Klasse.Bild}"

Das klappt auch alles
Die Liste mit den Bildinformationen sicher ich dann in einer xml Datei.

Wenn ich aber nun versuche das Bild zu löschen, dann bekomme ich die Fehlermeldung, dass das Bild noch verwendet wird. Ich bekomme es einfach nicht hin, das Bild als Kopie zu öffnen, damit der Zugriff auf die Bilddatei möglich ist. Der Bildordner soll nicht als Ressource im Projekt eingebunden werden.

Mein Problem ist bei MVVM.... wie kann ich im ViewModel das Bild als Image holen und an die View übergeben?

Danke für eure Hilfe

Gruß
ASommer

16.806 Beiträge seit 2008
vor 2 Jahren

Das hat mit MVVM nichts zutun, sondern wie Resourcen in .NET verwaltet werden bzw wie Betriebssysteme funktionieren. Das kannst Du auch alles in der Doku nachlesen:

  • Image erstellt ein Handle, um auf das Bild zugreifen zu können bzw. die Inhalte zu lesen.
  • Durch das Handle (Handles und Objekte - Win32 apps) weiß das Betriebssystem, dass das Bild in Verwendung ist
  • Den Löschaufruf verweigert das Betriebssystem, weil darauf zugegriffen wird
  • Du erhälst in .NET deswegen eine Fehlermeldung

Willst Du das Bild löschen, während Du es anzeigst, dann musst Du das Bild zuerst in den RAM laden, zB. mit Hilfe eines Memory Streams.

PS: Du suchst nach Hilfe, daher beachte in Zukunft bitte [Hinweis] Wie poste ich richtig?

  • Erstell das Thema im richtigen Bereich (Du redest schließlich von WPF; dann erstell doch auch im WPF Bereich das Thema...?)
  • Verwende ein Titel, der zum Thema passt, das macht es für alle einfacher und Du bekommst evtl. mehr Hilfe
A
ASommer Themenstarter:in
6 Beiträge seit 2022
vor 2 Jahren

Verstanden soweit.

Leider fehlt mir das wissen wie ich das mit dem Memory Stream mache.
Wo mache ich das am besten im View , im ViewModel oder XAML?

16.806 Beiträge seit 2008
vor 2 Jahren

Dann musst Dir das Wissen aneignen, zB. weil andere Leute schon das Problem hatten 🙂Google Suche nach "c# image memorystream"

Du kannst es alternativ auch direkt als Byte Array lesen, und dann ImageSource nutzen.
Steht alles auch in der Doku. Um das Lesen kommst leider nicht drum herum 🙂Google Suche nach "wpf image byte array"

Die Umsetzung wäre im ViewModel, siehe auch [Artikel] MVVM und DataBinding für die Verantwortlichkeiten.

A
ASommer Themenstarter:in
6 Beiträge seit 2022
vor 2 Jahren

Ich habe mir erstmal damit beholfen.
Das Bild wird dann in xml gespeichert und wieder gelesen somit muss ich das Original nicht löschen.
Muss jetzt nur noch schauen, dass ich die Bilder verkleinert bekomme, damit die xml nicht zu groß wird.


System.IO.File.ReadAllBytes(filePath);

Mit dem lesen... konnte ich ein wenig mehr darüber erfahren, aber so richtig schlau bin ich daraus noch nicht geworden.

16.806 Beiträge seit 2008
vor 2 Jahren

XML für Binärdaten? Hört sich nich gerade nach einer schlauen Lösung an.
Willst vielleicht einfach mal erzählen, was Du überhaupt machen willst und was die Anforderungen sind?

A
ASommer Themenstarter:in
6 Beiträge seit 2022
vor 2 Jahren

Ganz Trivial eigentlich.

Beispiel: Eine ObservableCollection<Personen>

Diese ObservableCollection will ich als XML auf der Festplatte speichern, damit beim nächsten Programmaufruf die Daten wieder da sind.

Zu jeder Person gibt es ein Bild. Im ersten Ansatz hatte ich einen Ordner angelegt und dort eine Kopie des Bildes gespeichert wenn man eine neues Bild/Person hinzufügt.
Wenn ich aber aus der ObservableCollection den Eintrag lösche... war der Zugriff (von meinem Programm) auf dem Bild noch da, somit konnte ich das Bild nicht löschen.

Mit der jetzigen Methode, habe ich das Bild der Person in der XML der ObservableCollection gespeichert. Somit brauche ich keinen neunen Ordner wo die Bilder rein kommen.

Ob das der richtige weg ist weiß ich nicht... bin Newbie in der Sache was WPF und C# angeht.

16.806 Beiträge seit 2008
vor 2 Jahren

Dann hast Du Dir jetzt quasi mehr Arbeit gemacht und nicht die Ursache sondern nur das Sympton gelöst - aber neue Steine in Weg gelegt.
Lade Deine Bilder in den Speicher und binde den Speicher an Deine View - nicht das Bild direkt.
Bei den Personen speicherst Du nur den Pfad zum Bild ab - mehr nicht. Würde man so in "echten Datenbank" genau so machen, weil Binärdaten in der Masse absolut nichts in relationalen Datenbanken zu suchen haben.

Hättest also mit ~5 Zeilen Code einfach lösen können (via MemoryStream oder Byte-Array, wie oben genannt).
Das wäre auch die technisch bessere Variante gewesen als Binärdaten in einer XML.

A
ASommer Themenstarter:in
6 Beiträge seit 2022
vor 2 Jahren

Hallo Abt,

danke für deine Hilfe. Genauso will ich es und wollte ich es auch machen. Aber das Problem war darin, dass ich es nicht hinbekomme das Bild darzustellen.
Bin fleißig dran das Problem zu beheben, aber ein bisschen fehlt mir noch alles zu kapieren.

~5 Zeilen Code einfach lösen können (via MemoryStream oder Byte-Array, wie oben genannt).

Hättest du vielleicht ein Beispiel von dem MemoryStream?

Danke für deine Tipps.

Gruß
ASommer

187 Beiträge seit 2009
vor 2 Jahren

Ein Bild in den Speicher laden


using (MemoryStream ms = new MemoryStream())
using (FileStream file = new FileStream("file.bin", FileMode.Open, FileAccess.Read)) {
   byte[] bytes = new byte[file.Length];
   file.Read(bytes, 0, (int)file.Length);
   ms.Write(bytes, 0, (int)file.Length);
}

Im View Model eine Eigenschaft vom Typ byte[] anlegen


private byte[] userImage;

public byte[] UserImage
   {
       get { return userImage; }
       set
       {
           if (value != userImage)
           {
               userImage = value;
               OnPropertyChanged("UserImage");
           }
       }
   }

Und im Xaml darauf binden


<Image Source="{Binding UserImage}"/>

Alles ungetestet! Das Byte-Array muss noch mit der Eigenschaft UserImage verbunden werden.

16.806 Beiträge seit 2008
vor 2 Jahren

Hättest du vielleicht ein Beispiel von dem MemoryStream?

Wieso schaust nicht einfach in die Suchtreffer aus meinem ersten Beitrag? Da steht alles mit Erklärung und Co.
Oder einfach in die Dokumentation schauen.

@Caveman das sieht nach .NET 3.5 Code oder früher aus.
Seit .NET 4 kann man einfach CopyTo verwenden


    fileStream.CopyTo(memoryStream);

Den Magic String im Property Event braucht man mittlerweile auch nicht mehr; so ist die potentielle Fehlerquelle auch eliminiert.

187 Beiträge seit 2009
vor 2 Jahren

@Caveman das sieht nach .NET 3.5 Code oder früher aus.
Seit .NET 4 kann man einfach CopyTo verwenden

Ich habe in dem Fall einfach nur stur gegoogelt und die erstbesten Beispiele von StackOverflow kopiert.
Dass mit CopyTo habe ich gelesen, wollte es aber nicht posten, weil es dann keine 5 Zeilen Code geworden wären 😉

Deswegen hatte ich auch geschrieben, dass ich das selber nicht probiert hatte.

16.806 Beiträge seit 2008
vor 2 Jahren

weil es dann keine 5 Zeilen Code geworden wären 😉


using... 
using...
{
 CopyTo
}

🙂