【问题标题】:Updating Image control from another thread从另一个线程更新图像控件
【发布时间】:2016-09-12 11:03:44
【问题描述】:

我想要一个应用程序来监控某个文件夹并显示该文件夹中出现的新图像。我成功地使用FileSystemWatcher 类检测到新图像,但是我在显示它们时遇到了问题。我有以下代码:

public partial class MainWindow : Window
    {
        FileSystemWatcher watcher = new FileSystemWatcher();
        public MainWindow()
        {
            InitializeComponent();
            watcher.Path = "C:/Users/maciejt/Pictures";
            watcher.Filter = "*.jpg";
            watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
                | NotifyFilters.FileName | NotifyFilters.DirectoryName;
            watcher.Created += new FileSystemEventHandler(OnCreated);
            watcher.EnableRaisingEvents = true;
        }
        private void OnCreated(object source, FileSystemEventArgs e)
        {
            Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
            image.Dispatcher.Invoke(new Action(() => { image.Source = new BitmapImage(new Uri(e.FullPath)); }));
        }        
    }

它适用于大约 10-20 个小 (~100kB) 图像和 1-2 个大 (~4MB) 图像。稍后它会抛出图像被另一个进程使用的异常。我还在调试器中观察到,应用程序使用的内存随着每个新图像而急剧增加,就像以前的图像没有被释放一样。

创建BitmapImage 并将其显示在Image 控件中的正确方法是什么?

编辑:

我已经尝试了一个可能重复的解决方案,但是这仍然给了我同样的异常,这次甚至没有工作一次。下面是修改后的代码:

private void OnCreated(object source, FileSystemEventArgs e)
        {
            Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);            
            image.Dispatcher.Invoke(new Action(() => { image.Source = LoadBitmapImage(e.FullPath); }));
        }

public static BitmapImage LoadBitmapImage(string fileName)
        {
            using (var stream = new FileStream(fileName, FileMode.Open))
            {
                var bitmapImage = new BitmapImage();
                bitmapImage.BeginInit();
                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
                bitmapImage.StreamSource = stream;
                bitmapImage.EndInit();
                bitmapImage.Freeze();
                return bitmapImage;
            }
        }

【问题讨论】:

标签: c# multithreading user-interface


【解决方案1】:

我已经设法找到一个可行的解决方案:

private void OnCreated(object source, FileSystemEventArgs e)
    {
        Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
        image.Dispatcher.Invoke(new Action(() => { image.Source = LoadBitmapImage(e.FullPath); }));

    }

public static BitmapImage LoadBitmapImage(string fileName)
    {
        while (!IsFileReady(fileName))
        {
            Thread.Sleep(100);
        }
        using (var stream = new FileStream(fileName, FileMode.Open))
        {
            var bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
            bitmapImage.StreamSource = stream;
            bitmapImage.EndInit();
            bitmapImage.Freeze();
            return bitmapImage;
        }
    }
public static bool IsFileReady(String sFilename)
        {
            // If the file can be opened for exclusive access it means that the file
            // is no longer locked by another process.
            try
            {
                using (FileStream inputStream = File.Open(sFilename, FileMode.Open, FileAccess.Read, FileShare.None))
                {
                    return (inputStream.Length > 0);   
                }
            }
            catch (Exception)
            {
                return false;
            }
        }

我的猜测是FileSystemWatcher 在检查任何修改时会获得文件的所有权一段时间。当我等待一段时间时,文件已解锁并准备好安全处理。不过,如果有人有更深入的解释或更好的解决方案,我会很乐意看到。

【讨论】:

  • 我认为这对您有用,因为当您在 WHILE 循环中等待时,垃圾收集器会释放您创建的位图对象。因此,您可以使用相同的文件创建新的位图。
【解决方案2】:

您可能会遇到此问题,因为您没有处理您创建的位图对象。尝试以下解决方案。这将在创建新位图时处理您以前的位图。

BitmapImage _image;
private void OnCreated(object source, FileSystemEventArgs e)
{
    if (_image != null)
    {
      FreeMemoryAcquiredByImage(_image);
      _image = null;
    }

    _image = new BitmapImage(new Uri(e.FullPath));
    //You may have to freeze _image here.

    image.Dispatcher.Invoke(new Action(() => { image.Source = _image; }));
}

【讨论】:

  • WPF 中是否存在Bitmap 类?不能用……而且ImageBitmapImage类没有Dispose()方法。
猜你喜欢
  • 1970-01-01
  • 2023-03-29
  • 2013-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-04
  • 1970-01-01
相关资源
最近更新 更多