C# 无法删除之前在 Window 中打开的 pdf

C# Unable to delete a pdf that was previously open in a Window

我有一个在 window 中打开的 PDF 文件。 window 已关闭,然后我尝试删除该文件并收到正在使用的错误。由于打开它的 window 已关闭,因此不应再锁定它。任何建议将不胜感激。

我有一个本地变量 _window

private Window _window;

我有以下代码可以在 window

中打开 PDF
_window = new Window
{
     Title = "PDF Viewer",
     Content = new WebBrowserView(),
     DataContext = new WebBrowserViewModel
     {
          Uri = _pdfPathFull
     },
     IsEnabled = false
 };

 _window.Show();

window关闭如下

private void ClosePDF()
{
     if (_window != null)
     {
          window.DataContext = new WebBrowserViewModel
          {
               Uri = "about:blank"
          };
          _window.Close();
          _window = null;
      }
}

我有以下代码试图删除在 window 中打开的文件,它总是失败并显示错误 "The process cannot access the file \ServerName\FileName.pdf because it is being used by another process."

ClosePDF();

bool fileDeleted = false;
int tryCount = 0;

FileInfo targetFile = new FileInfo(_pdfPathFull);
while (!fileDeleted && tryCount <= 50)
{
    System.Threading.Thread.Sleep(500);
    try
    {
        targetFile.Delete();
        fileDeleted = true;
    }
    catch(Exception ex)
    {
        if (tryCount == 50)
            throw (ex);
    }
    tryCount++;
}

这是 WebBrowserViewModel 的定义。这是所有遗留代码,我只是被要求添加删除功能。

public class WebBrowserViewModel : AppViewModel
{
    private string _uri = string.Empty;

    public WebBrowserViewModel()
    {

    }

    public string Uri
    {
        get { return _uri; }
        set { Set("Uri", ref _uri, value); }
    }
}

我认为问题出在这里:

这样做:

DataContext = new WebBrowserViewModel
 {
      Uri = _pdfPathFull
 },

在内存中创建一个对象,即使在 DataContext 设置为 "about:blank"

时,该对象也会继续保存 pdf 引用

我建议取一个参考变量并改用它。确保在 Window 关闭后取消引用它。确保 Window 对象也从调用函数中清除。

这就是我更新代码的方式:

添加一个新的私有变量:

private Window _window;
private FrameworkElement _fwElement;

下一组更改:

_fwElement = new FrameworkElement();
_fwElement.DataContext = new WebBrowserViewModel { Uri = _pdfPathFull };
_window = new Window
{
     Title = "PDF Viewer",
     Content = new WebBrowserView(),
     DataContext = _fwElement.DataContext,
     IsEnabled = false
 };

 _window.Show();

现在当我们关闭 Window:

private void ClosePDF()
{
     if (_window != null)
     {
          if(_fwElement != null)
          {
             _fwElement.DataContext = null;

          }
          window.DataContext = new WebBrowserViewModel
          {
               Uri = "about:blank"
          };
          _fwElement = null;
          _window.Close();
          _window = null;
          GC.Collect();
      }
}

你有什么问题?

如果您想知道哪个进程正在锁定您的文件,一个简单的方法是 运行 openfiles /query /fo table,然后解析输出。有关如何获取输出的信息,请参阅 ProcessStartInfo.RedirectStandardOutput。如果是本地进程,则需要设置一次,openfiles /local on 并重新启动。

顺便说一句,由于网络延迟,它可以锁定在插座的两端,甚至可以锁定在您的 PC 和 \ServerName 之间。

对临时文件使用网络共享很少是个好主意。请改用本地目录。如果由于法律或其他要求而不能,请使用 RAM 而不是磁盘,例如为嵌入式浏览器实施自定义 URI 方案,并以自定义方案 URL.

提供 pdf

更简单但不太可靠的解决方法是在延迟一段时间后重试删除该文件。我会使用 100-500 毫秒的延迟并重试 5-10 秒。

我在 WinForms 中遇到了这个问题,我发现解决这个问题的唯一可靠方法是制作 PDF 的临时副本并显示副本,这样原件就不会被锁定。

据我所知,没有直接的方法可以指示网络浏览器关闭文件。

当然,您仍然需要删除临时副本,但您可以在您的应用下次启动时删除,或者继续重试计时器等。

将 DataContext 分配给其他东西只会孤立旧的,当程序绕过它时将其丢弃,而您的删除循环中的任何内容都不会这样做。

您这里有一个非托管资源,编译器不会为您清理。您必须明确地处理有问题的对象,并希望下面的代码编写得足够好。我从来没有用 PDF 文件尝试过这个,在我对 XPS 文件的有限尝试中,我最终得到了 SSS 的解决方案(临时副本可以是 identified/killed,下次程序是 运行。)