0

現在、FileViewer コントロールを作成しようとしています。アイテム (アイコン付きのファイル名、サイズなど) を ListView (アイコン - ファイル名 - 拡張子 - サイズ) に追加した後、ファイルが画像かどうかも確認します (png /jpg など) ですが、これは別のスレッドで行います。

スレッドに対する私の期待は、メイン アプリケーションの横で実行されることですが、すべてのファイルを追加した後で、このスレッドを開始します。ListView 内のすべてのファイルをチェックし、それらのサムネイルを作成します。正しく行われた場合、ListView アイコンは読み込まれると 1 つずつ表示されるはずですが、そうではありません。それらはすべて同時に表示されます。

...スレッドがアクティブな間は何もできません。

なぜこれが起こっているのですか?以前にスレッドを扱ったことがありますが、常に機能していました。コールバックでメソッドを呼び出します。

スレッドの流れ:

  1. フォーマット ファイル キー = "C:\image.png" = "C_image_png"。
  2. 画像へのサムネイルが存在するかどうかを確認し(キーを確認して)、それを使用します
  3. それ以外の場合は、Image.FromFile().GetThumbnailImage() でサムネイルを読み込み、Listview の画像に Key で画像を追加します。
  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 に答える