【问题标题】:Loading Images in background while not locking the files在后台加载图像而不锁定文件
【发布时间】:2012-02-23 18:18:51
【问题描述】:

我的应用程序在 BackgroundWorker 中加载了大量图像以保持可用。我的图像控件绑定到名为“ImageSource”的属性。如果为 null,则会在后台加载并再次引发。

    public ImageSource ImageSource
    {
        get
        {
            if (imageSource != null)
            {
                return imageSource;
            }

            if (!backgroundImageLoadWorker.IsBusy)
            {
                backgroundImageLoadWorker.DoWork += new DoWorkEventHandler(bw_DoWork);
                backgroundImageLoadWorker.RunWorkerCompleted +=
                    new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                backgroundImageLoadWorker.RunWorkerAsync();
            }

            return imageSource;
        }
    }

    void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        bitmap = new BitmapImage();
        bitmap.BeginInit();
        try
        {
              bitmap.CreateOptions = BitmapCreateOptions.DelayCreation;
              bitmap.DecodePixelWidth = 300;

              MemoryStream memoryStream = new MemoryStream();
              byte[] fileContent = File.ReadAllBytes(imagePath);
              memoryStream.Write(fileContent, 0, fileContent.Length);
              memoryStream.Position = 0;
              bitmap.StreamSource = memoryStream;                            

         }
         finally
         {
             bitmap.EndInit();
         }
        bitmap.Freeze();
        e.Result = bitmap;
    }

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        BitmapSource bitmap = e.Result as BitmapSource;

        if (bitmap != null)
        {
            Dispatcher.CurrentDispatcher.BeginInvoke(
                (ThreadStart)delegate()
                {
                    imageSource = bitmap;
                    RaisePropertyChanged("ImageSource");
                }, DispatcherPriority.Normal);
        }
    }

到目前为止一切都很好,但我的用户可以更改有问题的图像。他们在 OpenDialog 中选择了一个新图像,旧图像文件被新图像覆盖,并且 ImageSource 再次被提升,再次加载具有相同文件名的新图像:

    public string ImagePath
    {
        get { return imagePath; }
        set
        {
            imagePath= value;
            imageSource = null;
            RaisePropertyChanged("ImageSource");
        }
    }

在某些系统上,覆盖旧文件会导致异常:

    "a generic error occured in GDI+" and "The process cannot access the file..."

我尝试了很多方法,例如使用 BitmapCreateOptions.IgnoreImageCache 和 BitmapCacheOption.OnLoad 加载。这会在加载它们时引发异常:

   Key cannot be null.
   Parameter name: key

如果我在 UI 线程上没有 BackgroundWorker 的情况下尝试此操作,它可以正常工作。难道我做错了什么?是否可以在保持文件解锁的同时在后台加载图像?

【问题讨论】:

  • 请发布您的“这会导致对 ImageSource 的新调用,它会再次加载具有相同文件名的新图像”。怎么又加载了。为什么不直接使用已有的图像并覆盖文件?
  • @BalamBalam 这实际上只是在设置新的(或现有的)文件路径后再次调用 RaisePropertyChanged("ImageSource") 。如果我不再次加载 ImageSource 并且只复制文件,则更改在 UI 中不可见,并且仍然会发生错误。据我了解,复制新文件时会发生错误,因为我的应用程序锁定了缓存文件。
  • 为什么要设置 imageSource = null;和 RaisePropertyChanged("ImageSource"); ?你能不能只将用户指定的文件加载到 imageSource,RaisePropertyChanged("ImageSource")(它将使用 imageSource,因为它不为空),然后使用后台线程到 File.WriteAllBytes ?
  • 感谢您的评论,但这会导致类似的例外情况。我现在有一个解决我这个房子问题的方法(见答案)。

标签: wpf multithreading image


【解决方案1】:

好吧,看来以上所有方法都有效。我简化了该问题的示例,但不知何故丢失了问题。

我可以在我的代码中看到的唯一区别是图像本身的加载被委托给特定的图像加载器类,该类以某种方式产生了问题。当我删除此依赖项时,错误消失了。

【讨论】:

    猜你喜欢
    • 2011-10-30
    • 2017-01-03
    • 1970-01-01
    • 2015-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-18
    • 2023-04-06
    相关资源
    最近更新 更多