在用户关闭文件后终止打开文件的进程 [WPF 应用程序]

Kill a process that opened a file, after the file is closed by the user [WPF application]

我正在尝试通过单击 WPF 应用程序按钮有效地打开-关闭-重新打开 power bi 文件 (.pbix)。我的方法首先创建一个打开 pbix 文件的进程,然后在文件关闭时终止该进程,然后再次单击按钮时创建一个新进程以重新打开文件。

请在下面找到我用来执行上述步骤的代码。

namespace TestApp
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public int CheckFileIsOpen(string filenamepath)
        {
            try
            {
                using FileStream fs = new FileStream(filenamepath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
                return 0;
            }
            catch (Exception)
            {
                WindowEffect = new BlurEffect();
                Mouse.OverrideCursor = null;
                bool? Result = new CustomMessageBox($"File: {filenamepath.Split(@"\").Last()} in use!\nClose it and try again.", "File used by another process", MessageType.Error, MessageButtons.Ok).ShowDialog(); //this is a MessageBox object
                if (Result.Value)
                {
                    WindowEffect = null;
                    return 1;
                }
                else
                {
                    WindowEffect = null;
                    return 2;
                }
            }
        }

        private void OpenOnlineLocally(bool open_local)
        {
            Process p = new Process();
            string copy_name = "File_Copy.pbix";
            string path = AppDomain.CurrentDomain.BaseDirectory; //the directory the .exe file runs.
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;
                if (open_local == true)
                {
                    int IsPBIFileOpen = CheckFileIsOpen($@"{path}{copy_name}");
                    if (new[] { 1, 2 }.Contains(IsPBIFileOpen))
                    {
                        return;
                    }
                    
                    //Open the file using the system process
                    p.StartInfo = new ProcessStartInfo($"{path}{copy_name}")
                    {
                        UseShellExecute = true
                    };
                    p.Start();
                }
                else
                {
                    OpenUrl("https://app.powerbi.com/...");
                }
            }
            finally
            {
                if (p.HasExited) { p.Kill(); } //kill the process if the user closed the .pbix file
            }
        }

        public ICommand ExportPowerBICommand //binded to a button click command in xaml
        {
            get { return new DelegateCommand<object>(FuncExportPowerBI); }
        }
        public void FuncExportPowerBI(object parameter)
        {
            Mouse.OverrideCursor = Cursors.Wait;
            try
            {
                OpenOnlineLocally(true);
            }
            finally
            {
                Mouse.OverrideCursor = null;
            }
        }
    }
}

以上代码在 finally statement:

中生成此错误

System.InvalidOperationException: 'No process is associated with this object.'

实验后的一些笔记:

  1. 当用户关闭 .pbix 文件(即单击桌面应用程序右上角的 X 图标)时,该进程应该被终止。如果进程未被终止并且用户 重新单击 按钮以 重新打开 文件然后我得到一个错误,该文件已经被另一个进程打开和使用。

  2. 出于两个原因,我宁愿避免使用 process.WaitForExit() 的解决方案。首先,应用程序在用户使用文件时冻结。其次,桌面需要几秒钟的时间才能意识到进程已经退出,因此它可以 kill() 它(时间效率不高)。

因为您是 运行 .NET 5,所以有一个异步方法 Process.WaitForExitAsync()。异步操作不会阻塞 UI.

我已经对两种方法进行了更改

private async Task OpenOnlineLocally(bool open_local)
{
    Process p = new Process();
    string copy_name = "File_Copy.pbix";
    string dir = AppDomain.CurrentDomain.BaseDirectory; //the directory the .exe file runs.
    string path = Path.Combine(dir, copy_name);
    try
    {
        if (open_local == true)
        {
            int IsPBIFileOpen = CheckFileIsOpen(path);
            if (IsPBIFileOpen != 0)
            {
                return;
            }

            //Open the file using the system process
            p.StartInfo = new ProcessStartInfo(path)
            {
                UseShellExecute = true
            };
            p.Start();
            await p.WaitForExitAsync();
        }
        else
        {
            OpenUrl("https://app.powerbi.com/...");
        }
    }
    finally
    {
        if (!p.HasExited) { p.Kill(); } //kill the process if the user closed the .pbix file
    }
}

public async void FuncExportPowerBI(object parameter)
{
    Mouse.OverrideCursor = Cursors.Wait;
    try
    {
        await OpenOnlineLocally(true);
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex.Message); // handle possible exception here
    }
    Mouse.OverrideCursor = null;
}