1

さて、これになりました。私はこのウェブサイトを他の多くのサイトで検索しましたが、誰も私に正直な答えを与えることができないように思われるので、私はただ率直に尋ねてみるつもりです。この問題に約3日間携わっていますが、これ以上時間を無駄にするわけにはいきません。

目標:私が構築しているアプリはWPFにあり、私の設計チームのプロジェクトのバグトラッカーとして使用される予定であり、まもなく着手します。C ++でゲームを構築するので、発生するエラーのほとんどは視覚的な要素を持っているので、ユーザーがリストにバグを追加したときに問題のエラーのイメージを提供する機能を含めました。次に、そのイメージを取得して、ローカルディレクトリに保存します(テスト用)。これで、Errorオブジェクトのイメージパスは、ローカルディレクトリにつながるパスを指します。この機能はテスト済みで、正常に動作します。リストからバグを削除したいときに問題が発生します。削除したい画像が別のプロセスで使用されているという非常に悪名高い「IO例外」が発生しています。

これまでのところ:最初は非常に洗練されたソリューションを試しましたが、他のすべての場合と同様に、まったく機能するかどうかを確認したいところまで来ています。ですから、私が使用しているコードのほとんどが実験的で過激なものになっています。ですから、それを見るときは、使用されているコードが絶望的ではないことに注意してください。したがって、「単純な」解決策はおそらくすでに試されています(これを行うのは嫌なので、私はこれをたくさん研究しました)。私が頭の中で考えることができるのは、不条理な量の廃棄と強制的なガベージコレクションが呼び出されていることです。したがって、この慣行の否定的な性質についてコメントしないでください。私はよく知っています:)。

コード

画像をローカルディレクトリに保存しています

public void OnBrowseClick()
    {
        Microsoft.Win32.OpenFileDialog openBox = new Microsoft.Win32.OpenFileDialog();

        // Show dialog box to user and grab output
        Nullable<bool> result = openBox.ShowDialog();

        if (result == true)
        {
            // Create temp variable to hold local path string
            string localPath = Directory.GetCurrentDirectory();      

            // Grab the extension of the specified file path
            string extension = openBox.FileName.Substring(openBox.FileName.LastIndexOf("\\"));

            // Add extension to local path
            localPath += extension;

            // Create local copy of image at given file path (being ridiculous at this point)
            using (Stream stream = new FileStream(openBox.FileName, FileMode.Open, FileAccess.ReadWrite))
            {
                using (Bitmap bmp = LoadImage(stream))
                {
                    using (Bitmap temp = (Bitmap)bmp.Clone())
                    {
                        temp.Save(localPath);
                        temp.Dispose();
                    }

                    bmp.Dispose();
                }

                stream.Dispose();
            }

            // Set the URL in the image text box (UI stuff)
            LocalError.ImagePath = localPath;   
        }
    }

以下は、上記の関数で使用されるLoadImage関数です。

private Bitmap LoadImage(Stream stream)
    {
        Bitmap retval = null;

        using (Bitmap bitmap = new Bitmap(stream))
        {
            retval = new Bitmap(bitmap.Width, bitmap.Height, bitmap.PixelFormat);

            using (Graphics gdi = Graphics.FromImage(retval))
            {
                gdi.DrawImageUnscaled(bitmap, 0, 0); 
                gdi.Flush();
                gdi.Dispose();
                bitmap.Dispose();
            }
        }

        // Garbage collection here to be safe
        GC.WaitForPendingFinalizers();
        GC.Collect();

        return retval;
    } 

そして最後に、画像を削除しようとするところに到達します

public void OnDeleteClick()
    {
        // Ask user to make sure they want to delete selected item(s)
        MessageBoxResult result = MessageBox.Show("Are you sure you want to delete selected item(s) from the list?",
                                "Delete", MessageBoxButton.YesNo);

        if (result == MessageBoxResult.Yes)
        {
            for( int i = 0; i < Parent.ErrorListControl.ErrorDataGrid.SelectedItems.Count; ++i)
            {
                // Get path to image
                string path = (Parent.ErrorListControl.ErrorDataGrid.SelectedItems[i] as Error).ImagePath;

                // Even tried calling garbage collection here!!!!!
                System.GC.WaitForPendingFinalizers();
                System.GC.Collect();
                File.Delete(path);

                // Remove the error from the error list
                Parent.ErrorListVM.ErrorList.Remove((Error)Parent.ErrorListControl.ErrorDataGrid.SelectedItems[i]);

                // Decrement counter because we altered the list while in a loop
                i--;
            }
        }
    }

注:誰かが私にさらに何かを説明したい場合、または私が省略したことを知る必要がある場合は、できるだけ早くあなたに連絡するように頼んでください!どんな提案もこの時点で役に立ちます。私は絶対に私が何を間違っているのか分かりません。私は通常、C ++環境でのみプログラミングするので、自分のメモリを管理する傾向があります。この「ガベージコレクション」全体が、プロジェクトに大きな影響を及ぼしています。(オフトピックノート:なぜ色が強調表示されないのかわからないので、これを読むのに時間を割いてくださった方にはお詫び申し上げます)。

4

2 に答える 2

0

あなたのLoadImage方法は画像の単純なコピーを行うので、File.Copy(source, dest)すべてのビットマップ、描画などを使用して避けてみませんか?ローカルビットマップの作成後に変更することが目標かもしれませんが、コピー後も変更できます。

また、ブロックを使用する場合、ブロックが自動的に行うためusing、明示的.Dispose()は必要ありません。using

using (var obj = new SomeDisposableObject())
{
    // code here
    // obj.Dispose(); <-- not needed, since...
} // ...at this point obj.Dispose is called automatically.
于 2012-09-14T15:40:00.500 に答える
0

これがあなたがやりたいことをする簡単な方法です。この例では、Path.GetTempFileName()を使用して、ローカルユーザーの一時ディレクトリにランダムなファイル名を生成しています。ファイルを永続化する必要がない場合は、一時的に保存するのに適した場所です。また、ユーザーは理論的には同じ名前の2つのファイルをインポートできます。したがって、競合を回避するために、ある種のランダムなファイル名生成またはその他のメカニズムを使用する必要があります。

private void browseButton_Click(object sender, RoutedEventArgs e)
{
    var openFileDialog = new Microsoft.Win32.OpenFileDialog();

    if (openFileDialog.ShowDialog(this) == true)
    {
        using (Bitmap originalImage = new Bitmap(openFileDialog.FileName))
        {
            string tempFileName = System.IO.Path.GetTempFileName();

            originalImage.Save(tempFileName);

            // LocalError.LocalPath
            LocalPath = tempFileName;
        }
    }
}

private void deleteButton_Click(object sender, RoutedEventArgs e)
{
    if (File.Exists(LocalPath))
    {
        File.Delete(LocalPath);
    }
}

正しいパスがあれば、単純なFile.Copyで十分ですが、私はあなたの質問に一致するソリューションを提供していました。

編集: 実際には、現在のディレクトリはOpenFileDialogによって変更されていないようです。ある時点でそれが行われたことを誓うことができました。ですから、これはあなたの問題ではないと思います。とにかく、このコードはまだ私のために機能し、これよりも複雑なものは必要ありません。

編集#2: ロックは、実際には画像がビューにデータバインドされており、おそらくBitmapSourceによってロックされていることが原因のようです。ファイルをロックせずに作成できるはずです。通常、これは遅いので、ファイルを変更または削除できる必要がない限り、この方法で実行しないでください。

bitmapSource = new BitmapImage();
bitmapSource.BeginInit();
bitmapSource.CacheOption = BitmapCacheOption.OnLoad;
bitmapSource.CreateOption = BitmapCreateOptions.IgnoreImageCache;
bitmapSource.UriSource = new Uri(ImagePath, UriKind.Absolute);
bitmapSource.EndInit();
于 2012-09-14T15:44:57.973 に答える