0

我目前正在尝试创建一个 FileViewer 控件,在我将项目(带有图标的文件名、大小等)添加到我的 ListView(图标 - 文件名 - 扩展名 - 大小)之后,我还检查文件是否是图像(png /jpg 等),但我在不同的线程上执行此操作。

我对线程的期望是它在主应用程序旁边运行,但是在我添加了所有文件之后,我启动了这个线程。它检查 ListView 中的所有文件并为它们创建缩略图。如果操作正确,ListView 图标在加载时应该一个接一个出现 - 但它们不是。它们都同时出现。

...当线程处于活动状态时,我什么也做不了。

为什么会发生这种情况,我做错了什么?我之前处理过线程并且它总是有效的,我使用回调调用该方法。

线程流:

  1. 格式文件键 = "C:\image.png" = "C_image_png"。
  2. 检查图像的缩略图是否存在(通过检查它的键),然后使用它
  3. 否则使用 Image.FromFile().GetThumbnailImage() 加载缩略图,并将带有 Key 的图像添加到 Listview 的图像
  4. 最后更改 ListView 项的 ImageKey。

全部在一个线程中完成。

private void GetFiles()
{
   // Load all files in directory

   Thread t = new Thread(new ThreadStart(GetImageFiles));
   t.Priority = ThreadPriority.Lowest;
   t.Start();

}

delegate void GetImageFilesCallback();

    private void GetImageFiles()
    {
        if (this.IsHandleCreated)
        {
            if (files.InvokeRequired)
            {
                GetImageFilesCallback callback = new GetImageFilesCallback(GetImageFiles);
                this.Invoke(callback);
            }
            else
            {
                string extension = "";
                string key = "";

                foreach (string file in _files)
                {
                    extension = FileManager.GetExtension(file);
                    key = (DirectoryCurrent + file).Replace(":", "").Replace("\\", "_").Replace(".", "_");

                    foreach (string knownimages in _knownImageTypes)
                    {
                        if (extension.ToLower() == knownimages)
                        {
                            foreach (ListViewItem item in files.Items)
                            {
                                if (item.Text == file)
                                {
                                    if (files.SmallImageList != null)
                                    {
                                        if (files.SmallImageList.Images[key] == null)
                                        {
                                            files.SmallImageList.Images.Add(key, Image.FromFile(DirectoryCurrent + file).GetThumbnailImage(16, 16, null, IntPtr.Zero));
                                            files.LargeImageList.Images.Add(key, Image.FromFile(DirectoryCurrent + file).GetThumbnailImage(32, 32, null, IntPtr.Zero));
                                        }

                                        files.Items[item.Index].ImageKey = key;
                                    }
                                }
                            }
                        }
                    }
                }

                files.Refresh();
            }
        }
    }
4

2 回答 2

1

您的线程调用的方法是在主线程上调用自身,然后在该线程中完成所有工作,从而阻塞您的 UI。

您应该安排您的代码,以便线程代码不接触 ListView,而只是加载每个图像,然后调用主线程方法,传递位图,以便主线程可以将它们分配给 ListView。

这是我的意思的草图:

// this is your thread method
// it touches no UI elements, just loads files and passes them to the main thread
private void LoadFiles(List<string> filenames) {
   foreach (var file in filenames) {
      var key = filename.Replace(...);
      var largeBmp = Image.FromFile(...);
      var smallBmp = Image.FromFile(...);
      this.Invoke(new AddImagesDelegate(AddImages), key, largeBmp, smallBmp);
   }
}

// this executes on the main (UI) thread    
private void AddImages(string key, Bitmap large, Bitmap small) {
   // add bitmaps to listview
   files.SmallImageList.Images.Add(key, small);
   files.LargeImageList.Images.Add(key, large);
}

private delegate AddImagesDelegate(string key, Bitmap large, Bitmap small);
于 2012-09-13T23:31:06.917 回答
0

阅读以下内容:http: //www.codeproject.com/Articles/10311/What-s-up-with-BeginInvoke。Invoke 和 BeginInvoke 的重要之处在于它们都在主线程上运行。BeginInvoke 只是在返回控制之前不等待消息被处理。但最终,工作将发生在主线程上,并且会阻塞直到完成。

于 2012-09-13T23:34:19.617 回答