在用户看到之前在另一个线程中缓存图像

时间:2016-01-28 03:17:18

标签: c# wpf multithreading caching

我最近在WPF工作电子书程序,本书的页面都保存为.jpg格式。由于图像都是高质量的,因此程序在切换页面时会滞后。

我试图在用户在另一个线程中看到的当前图像之后缓存一些图像。但它给了我一个错误。

  

未处理的类型' System.InvalidOperationException'发生在WindowsBase.dll

中      

附加信息:调用线程无法访问此对象,因为另一个线程拥有它。

我可以通过添加Invoke来修复错误,但性能就像没有内存缓存一样。

但是没有Invoke,程序会显示上面的错误。而且我不知道如何解决它。

我试着让代码变得尽可能简单。

感谢任何帮助。

完整代码:

using System;
using System.Collections.Specialized;
using System.IO;
using System.Runtime.Caching;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;

namespace ThreadedMemoryCache_Test
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        MemoryCache memcache;
        int num = 0;
        Image img;
        int BufferPages = 2;

        public MainWindow()
        {
            InitializeComponent();
            //Change Content
            img = new Image();
            Content = img;
            //Mouse Events
            MouseDown += (s, e) =>
            {
                int add = 0;
                if (e.LeftButton == MouseButtonState.Pressed)
                    add--;
                else if (e.RightButton == MouseButtonState.Pressed)
                    add++;
                else
                    return;
                num += add;
                img.Source = GetBitmap(num);  //Error here
                Buffer();
            };
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            //Initiallize MemoryCache
            NameValueCollection CacheSettings = new NameValueCollection(3);
            CacheSettings.Add("CacheMemoryLimitMegabytes", Convert.ToString(1));
            CacheSettings.Add("physicalMemoryLimitPercentage", Convert.ToString(10));
            CacheSettings.Add("pollingInterval", Convert.ToString("00:00:10"));
            memcache = new MemoryCache("BitmapCache", CacheSettings);
            //Get First Photo
            img.Source = GetBitmap(num);
            Buffer();
        }
        BitmapImage GetBitmap(int num)
        {
            String id = num.ToString();
            BitmapImage cachebmp = memcache[id] as BitmapImage;
            if (cachebmp == null)
            {
                CacheItemPolicy policy = new CacheItemPolicy();
                String name = num.ToString() + ".jpg";
                FileInfo file = new FileInfo(name);
                if(!file.Exists)
                {
                    num = 0;
                    return GetBitmap(num);
                }
                cachebmp = new BitmapImage(new Uri(file.FullName));
                memcache.Set(id, cachebmp, policy);
            }
            return cachebmp;
        }
        void Buffer()
        {
            //Start Thread
            Thread cachethread = new Thread(() =>
            {
                for (int i = 1; i <= BufferPages; i++)
                {
                    //Adding invoke fixes the error, but it seems to delay the main thread and cause lag.
                    //this.Dispatcher.Invoke((Action)(() =>
                    //{
                    GetBitmap(num + i);
                    //}));
                }
            });
            cachethread.IsBackground = true;
            cachethread.Start();
        }
    }
}

2 个答案:

答案 0 :(得分:3)

您必须冻结BitmapImage以使其可跨线程访问:

cachebmp = new BitmapImage(new Uri(file.FullName));
cachebmp.Freeze();
memcache.Set(id, cachebmp, policy);

也就是说,您的代码可以通过多种方式得到改进。最好使用ThreadPool主题或BackgroundWorkerTask来执行后台任务。

除此之外,如果图片文件不存在,您不应该使用GetBitmap(num)递归num = 0。如果0.jpg也缺失会怎样?

答案 1 :(得分:0)

您应该使用BackgroundWorker类。

在MainThread中启动时加载一些初始图像,然后为其余图像启动BackgroundWorker

有用的链接:How to: Use a Background WorkerBackgroundWorker In Wpf