在用户关闭文件后终止打开文件的进程 [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.'
实验后的一些笔记:
当用户关闭 .pbix 文件(即单击桌面应用程序右上角的 X 图标)时,该进程应该被终止。如果进程未被终止并且用户 重新单击 按钮以 重新打开 文件然后我得到一个错误,该文件已经被另一个进程打开和使用。
出于两个原因,我宁愿避免使用 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;
}
我正在尝试通过单击 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.'
实验后的一些笔记:
当用户关闭 .pbix 文件(即单击桌面应用程序右上角的 X 图标)时,该进程应该被终止。如果进程未被终止并且用户 重新单击 按钮以 重新打开 文件然后我得到一个错误,该文件已经被另一个进程打开和使用。
出于两个原因,我宁愿避免使用
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;
}