2

私はとOpenFileDialogPictureBoxユーザーが制御しています。問題をよりよく理解するために、このユーザーコントロールがどのように機能するかを簡単に説明します。ユーザーは、フォーム用に開く画像を選択できます。このイメージの名前はデータベースに保存され、イメージのファイルはデフォルトの場所にコピーされます。データベースに画像が保存されている場合、画像ボックスコントロールを含むフォームが読み込まれると、画像ボックスに画像が読み込まれます。ユーザーが別の画像を選択し、新しい画像でフォームを保存したい場合、デフォルトの場所から古い画像ファイルを削除するように注意する方法があり、そこで問題が発生します。

画像を読み込んで新しい画像を保存しようとすると、(実際には非常にまれですが)The resource is being used by another process..必要に応じて正確なエラーを貼り付けることができるというエラーが発生することがあります。問題はピクチャーボックスとそれが画像を扱う方法に起因していると思います。

これが私のコードです:

if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    if (MyImage != null)
                    {
                        MyImage.Dispose();

                    }
                    selectedFile = openFileDialog1.FileName;
                    selectedFileName = openFileDialog1.SafeFileName;

                    MyImage = new Bitmap(openFileDialog1.FileName);
                    pictureBox1.Image = (Image)MyImage;

                    int imageWidth = pictureBox1.Image.Width;
                    int picBoxWidth = pictureBox1.Width;

                    if (imageWidth != 0 && picBoxWidth > imageWidth)
                    {
                        pictureBox1.Width = imageWidth;
                    }
                    else
                    {
                        pictureBox1.Width = defaultPicBoxWidth;
                    }
                }
                catch (Exception ex)
                {
                    logger.Error(ex.ToString());
                    MessageBox.Show("Error loading image!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }

と私の削除方法:

public void DeleteImage(AppConfig imageInfo, string imageName)
        {
            string imgPath = imageInfo.ConfigValue.ToString();
            try
            {
                File.Delete(imgPath + "\\" + imageName);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

私は思った:

if (MyImage != null)
                        {
                            MyImage.Dispose();

                        }

この問題に対処しますが、それでも時々発生します。そして、それが常に重要であるとは限らないので、ある時点で私はそれを解決したと判断するかもしれませんが、実際にはしばらくの間幸運であるため、それに対処することがさらに重要です。

4

4 に答える 4

2
    MyImage = new Bitmap(openFileDialog1.FileName);
    pictureBox1.Image = (Image)MyImage;

はい、そのコードはファイルをロックします。ロックは、GDI +が作成するメモリマップトファイルオブジェクトによって生成され、ページングファイルにスペースを割り当てることなく、ファイルのピクセルデータをメモリに効率的にマップします。画像が画像ボックスに表示され、破棄されていない限り、ファイルを削除することはできません。ロックにより削除されません。ファイルを削除する前に、画像を破棄し、Imageプロパティをnullに戻す必要があります。

イメージのメモリ内コピーを作成することにより、ファイルがロックされるのを防ぐことができます。

    using (var temp = new Bitmap(openFileDialog1.FileName)) {
        pictureBox1.Image = new Bitmap(temp);
    }

もちろん、画像が大きい場合は避けるのはそれほど効率的ではありません。また、別のプロセスが実際にファイルに対して同様のロックを持っている可能性があることに注意してください。それについてあなたができることは何もありません。

于 2013-03-07T15:12:26.077 に答える
1

のようなものの主な難しさは、それが画像の唯一のユーザーであるかどうかを知る方法がないPictureBoxため、PictureBox結果として、画像が不要になったときにその画像を破棄する必要があるかどうかを知る方法がないことです。

したがって、画像ボックスを所有するコードはすべて、それに関連付けられた画像の所有権も取得する必要があります。そうするために私が提案できる3つのアプローチがあります:

  • PictureBox与えられた画像の所有権を引き継ぐものとして、ドキュメント自体から派生したコントロールを作成します。このようなコントロールは、おそらくimageプロパティをSetImageWithOwnershipメソッドに置き換える必要があります(画像がに渡されるとPictureOwningBox、ボックスはそれを「所有」することが期待され、ボックスがDisposedの場合、または別の場合に破棄されます。画像はボックスに表示されます)。

  • にイベントハンドラーをアタッチしてPictureBox、ボックスが破棄されるか、別のイメージが割り当てられるシナリオを処理します。

  • PictureBoxを破棄したり、別のイメージをロードしたりするコードを用意し、Image割り当てられたコードも破棄します。

While there may be cases where it would be appropriate to call GC.Collect and let the garbage-collector take care of things, such an approach is generally unsound.

于 2013-03-07T16:51:33.623 に答える
0

それを試してください:

                using(Bitmap MyImage = new Bitmap(openFileDialog1.FileName))
                {
                  pictureBox1.Image = (Image)MyImage;

                  int imageWidth = pictureBox1.Image.Width;
                  int picBoxWidth = pictureBox1.Width;

                  if (imageWidth != 0 && picBoxWidth > imageWidth)
                  {
                      pictureBox1.Width = imageWidth;
                  }
                  else
                  {
                      pictureBox1.Width = defaultPicBoxWidth;
                  }
                }
于 2013-03-07T15:09:29.970 に答える
0

私は以前にこのような問題を抱えていましたがDispose()、ガベージコレクターによる削除対象としてオブジェクトをマークするだけの、後でもリソースが解放されることを確認する1つの方法は、を使用することGC.Collect()です。リソースの廃棄を処理するためのよりクリーンな方法があると確信していますが、実行にかかる時間はGC.Collect()プログラムの妨げにはなりません。

于 2013-03-07T15:10:01.777 に答える