Laden...

Laden von Bildern über das Netzerk dauert zu lange. Async laden?

Erstellt von KPhoenix vor 10 Jahren Letzter Beitrag vor 10 Jahren 2.385 Views
K
KPhoenix Themenstarter:in
175 Beiträge seit 2011
vor 10 Jahren
Laden von Bildern über das Netzerk dauert zu lange. Async laden?

Hallo
Ich habe ein Datagrid mit DetailView und im Detail wird ein Bild angezeigt. Die Bilder werden über das Netzwerk gelasen, was das Scrollen des Datagrid extrem verlangsamt. Für das Erzeugen der Bilder verwende ich einen Converter


    [ValueConversion(typeof(string), typeof(BitmapImage))]
    public class ImageConverter : IValueConverter
    {        
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                string path = value.ToString();
                if(File.Exists(path))
                    return new BitmapImage(new Uri(path));
                else
                    return new BitmapImage(new Uri("/Images/NoImage.jpg", UriKind.Relative));
            }
            catch
            {
                return new BitmapImage(new Uri("/Images/NoImage.jpg", UriKind.Relative));
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

Gibt es eine Möglichkeit, die Bilder async zu laden oder das Laden zu beschleunigen? Oder evtl das Laden in einen eigenen Thread zu verlagern?

Vielen Dank schon mal

16.833 Beiträge seit 2008
vor 10 Jahren

Macht es sinn immer und immer wieder das gleiche Bild zu laden? Eher nicht.
Warum liegen Bilder im Netzwerk, und nicht in den Ressourcen?
Was machst Du wenn das Netzwerk nicht erreichbar ist? Dann stürzt die Anwendung aktuell ab.
Bilder vorladen ja; und nicht mehrfach. Anschließend die Bitmaps im DG kopieren.

K
KPhoenix Themenstarter:in
175 Beiträge seit 2011
vor 10 Jahren

Die Bilder liegen im Netzwerk, weil auch andere Anwendungen darauf zugreifen müssen. Ich hab ja schon einen Fallback eingebaut, dass ein anderes Bild angezeigt wird, falls das Bild nicht gefunden wird.

Hab aber jetzt auch die Lösung gefunden. Beim Binding im Xaml-Code hab ich einfach IsAsync auf true gesetzt.


Source="{Binding Path=Row.URLPicture, Converter={StaticResource ImageConverter}, IsAsync=True}"

Und den Converter hab ich so angepasst.


[ValueConversion(typeof(string), typeof(BitmapImage))]
    public class ImageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                string path = value.ToString();
                if (File.Exists(path))
                {
                    return LoadImage(path);
                }
                else
                    return new BitmapImage(new Uri("/Images/NoImage.jpg", UriKind.Relative));
            }
            catch
            {
                return new BitmapImage(new Uri("/Images/NoImage.jpg", UriKind.Relative));
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        public BitmapImage LoadImage(string path)
        {
            try
            {
                BitmapImage bi = new BitmapImage();
                bi.BeginInit();
                bi.UriSource = new Uri(path);
                bi.EndInit();
                return bi;
            }
            catch
            {
                return null;
            }
        }
    }

Ist das eine vernünftige Lösung oder total witzlos? Was meinst du mit das Bild immer wieder laden? Wird somit das Bild jedesmal neu geladen?

Danke auf jeden Fall

4.221 Beiträge seit 2005
vor 10 Jahren

Mach Dir doch noch ein static Dictionary<string, BitmapImage> rein...

Jedes geladene Bild haust Du in das Dict rein... und wenn Du es schon drin hast, dann kannst Du es aus dem Dict holen statt vom Netzwerk.

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

2.207 Beiträge seit 2011
vor 10 Jahren

Hallo KPhoenix,

na, was glaubst du, was das Wort "new" macht? Es macht dir jedesmal eine neue Instanz eines bitmapimages. Bau dir einen Cache. Wenn du am Anfang alles einliest hast du die Bilder schonmal schneller. Wenn nicht, mach dir einen Cache, der sie beim erzeugen hinzufügt. Dann wächst der mit dem Laufe der Anwendung. Ist das bild im Cache: Nimm es daher, sonst mache eben ein neues: new BitmapImage.

EDIT: So, wie Programmierhans auch sagt 😃

Gruss

Coffeebean

K
KPhoenix Themenstarter:in
175 Beiträge seit 2011
vor 10 Jahren

Vielen vielen Dank für die Tipps. Ich hab meinen Converter jetzt angepasst.
Macht es jetzt mehr Sinn oder gibt es noch Verbesserungsbedarf?


        private static readonly string NO_IMAGE = "NoImage";

        private static IDictionary<string, BitmapImage> m_ImageChache;

        static ImageConverter()
        {
            m_ImageChache = new Dictionary<string, BitmapImage>();
            m_ImageChache.Add(NO_IMAGE, new BitmapImage(new Uri("/Images/NoImage.jpg", UriKind.Relative)));
        }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                string path = value.ToString();
                if (File.Exists(path))
                {
                    if (m_ImageChache.ContainsKey(path))
                    {
                        BitmapImage bi = m_ImageChache[path];
                        return bi == null ? m_ImageChache[NO_IMAGE] : bi;
                    }
                    else
                    {
                        BitmapImage bi = LoadImage(path);
                        m_ImageChache.Add(path, bi);
                        return bi == null ? m_ImageChache[NO_IMAGE] : bi;
                    }
                }
                else
                    return m_ImageChache[NO_IMAGE];
            }
            catch
            {
                return m_ImageChache[NO_IMAGE];
            }
        }

T
314 Beiträge seit 2013
vor 10 Jahren

Hi,

so wird der Cache nur genutzt, wenn der Pfad "erreichbar" ist.

Die äußere If macht in meinen Augen nur Sinn, wenn die File nicht im Cache ist.

PS: Gibt es merkliche Verzögerung wenn ein File.Exists auf einen Netzwerkpfad ausgeführt wird? In diesem Fall wäre ggf. auch ein Timeout pro nicht erreichbaren Pfad sinnvoll.

Gruß
t0ms3n

4.221 Beiträge seit 2005
vor 10 Jahren

Das geht doch kürzer 😃


public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
         {
             string path=null;
             try
             {
                 path = value.ToString();
                 if (!m_ImageChache.ContainsKey(path) && File.Exists(path))
                 {
                     m_ImageChache.Add(path, LoadImage(path));
                 }
             }
             finally
             {
                 return m_ImageChache.ContainsKey(path) ? m_ImageChache[path] : m_ImageChache[NO_IMAGE];
             }
         } 

Nachtrag: Das hat zudem den Vorteil, dass Du bei einem Netzwerkunterbruch schon vorhandene Bilder sehen kannst.. nicht vorhandene werden als NO_IMAGE angezeigt... und sobald das Netz wieder verfügbar ist siehst Du das echte Bild.

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

K
KPhoenix Themenstarter:in
175 Beiträge seit 2011
vor 10 Jahren

Vielen Dank für die Hilfe. Das Programm flutscht jetzt richtig schön dahin 👍