首页 > 解决方案 > 在用户关闭文件后终止打开文件的进程[WPF应用程序]

问题描述

我正在尝试通过单击 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:“没有进程与此对象关联。”

实验后的一些注意事项:

  1. 当用户关闭 .pbix 文件(即单击桌面应用程序右上角的 X 图标)时,应终止该进程。如果进程没有被杀死并且用户重新单击按钮以重新打开文件,那么我会收到一个错误,即该文件已被另一个进程打开并使用。

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

标签: c#wpf.net-5

解决方案


由于您正在运行 .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;
}

推荐阅读