好吧,它已经到了这个地步。我在其他许多网站上搜索了这个网站,没有人能给我一个直接的答案,所以我会试着直接问。在这个问题已经持续了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 ++环境中编程,所以我倾向于管理我自己的内存,这整个“垃圾收集”的事情真的在我们的项目中挥了挥手! (非主题说明:我不知道为什么我没有得到任何颜色突出显示,所以我向任何花时间阅读此内容的人道歉。)
答案 0 :(得分: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.
答案 1 :(得分:0)
这是一种简单的方法来做你想要的。在这个例子中,我使用Path.GetTempFileName()在本地用户的临时目录中生成一个随机文件名。如果您不需要保留文件,那么它是暂时存储它们的好地方。此外,理论上用户可以导入两个具有相同名称的文件。因此,您希望使用某种随机文件名生成或其他机制来避免冲突。
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();