从后台进程打开 window 并在 WPF 中获取用户的输入
From background process open window and take input from user in WPF
在我的 C# WPF 应用程序中,我正在使用 BackgroundWorker 进行某些异步报告工作。我可以使用 ProgressChanged 事件从 backgroundWorker 更新 UI。
但是,我需要在此过程中请求用户输入,在后台进程的某些点我需要打开 window 请求用户输入,根据该输入,后台进程将进一步继续。
我可以从后台进程中打开一些 window,然后在用户对该 window 做出响应后继续该进程吗?
你应该把它分成不同的后台工作者。当您到达需要用户输入的过程中的某个点时,finish/complete 您的后台工作人员然后在 UI 线程上收集输入,然后使用输入启动下一个工作人员。
我建议为此使用 Task / async / await 方法而不是后台工作者。它将使这种过程更容易编写和理解:
private void async RunTheJob()
{
// Run Part1 async and wait for the result
var result1 = await Part1();
// Now collect your UI input based on result1
var uiInput = ......;
// Run Part2 async and wait for the result
var result2 = await Part2(uiInput);
}
private Task<Part1ReturnObjectTypeHere> Part1()
{
Part1ReturnObjectTypeHere result = null;
...do async work here to populate result...
return result;
}
你基本上有两个选择:
- (最佳实践)正如其他人所指出的,最佳实践是使用 async / await 链来异步完成您的工作,而不是后台工作者。您只需将所有后台作业代码放入一个异步方法中,然后使用 await 关键字调用它。
这是一个示例,可用于提示无限次提示并在之后继续作业。
//You can bind this to a Button or any other WPF event,
// the point is that it should be run from UI thread
private async void JobStartEvent()
{
JobResult jobResult = new JobResult
{
JobStatus = JobStatus.NotStarted
};
while (jobResult.JobStatus != JobStatus.Done)
{
jobResult = await DoLongJob(jobResult.ContinuationInfo);
if (jobResult.JobStatus == JobStatus.UserPromptRequired)
{
jobResult.ContinuationInfo.PromptResult = PromptAndGetResult(jobResult.PromptInfo);
}
}
}
private async Task<JobResult> DoLongJob(JobContinuationInfo continuationInfo)
{
//Do long stuff here
// continue the job using "continuationInfo"
//When prompt needed, Do:
{
return new JobResult
{
JobStatus = JobStatus.UserPromptRequired,
PromptInfo = new PromptInfo(), //Fill with information required for prompt
ContinuationInfo = new ContinuationInfo() //Fill with information required for continuing the job (can be a delegate to a local function to continue the job)
};
}
//When done, Do:
{
return new JobResult { JobStatus = JobStatus.Done};
}
}
private async JobResult DoLongJob()
{
return JobResult =
}
private enum JobStatus
{
NotStarted,
UserPromptRequired,
Done
}
internal class JobContinuationInfo
{
public PromptResult PromptResult { get; set; }
// Other properties to continue the job
}
private class JobResult
{
public JobStatus JobStatus { get; set; }
public PromptInfo PromptInfo { get; set; }
public JobContinuationInfo ContinuationInfo { get; set; }
}
阅读更多:
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
- 要使用后台工作程序,您可以使用 Dispatcher.Invoke 方法并在那里传递 window 创建代码。 window的创建会在UI线程中完成,但是后台工作线程会等待它执行,得到结果(可以是你提示的结果)然后继续执行。
System.Windows.Threading.Dispatcher.Invoke<ResultType>(async () =>
{
return PromptUserAndGetResult();
});
阅读更多:
https://docs.microsoft.com/en-us/dotnet/api/system.windows.threading.dispatcher.invoke
在我的 C# WPF 应用程序中,我正在使用 BackgroundWorker 进行某些异步报告工作。我可以使用 ProgressChanged 事件从 backgroundWorker 更新 UI。
但是,我需要在此过程中请求用户输入,在后台进程的某些点我需要打开 window 请求用户输入,根据该输入,后台进程将进一步继续。
我可以从后台进程中打开一些 window,然后在用户对该 window 做出响应后继续该进程吗?
你应该把它分成不同的后台工作者。当您到达需要用户输入的过程中的某个点时,finish/complete 您的后台工作人员然后在 UI 线程上收集输入,然后使用输入启动下一个工作人员。
我建议为此使用 Task / async / await 方法而不是后台工作者。它将使这种过程更容易编写和理解:
private void async RunTheJob()
{
// Run Part1 async and wait for the result
var result1 = await Part1();
// Now collect your UI input based on result1
var uiInput = ......;
// Run Part2 async and wait for the result
var result2 = await Part2(uiInput);
}
private Task<Part1ReturnObjectTypeHere> Part1()
{
Part1ReturnObjectTypeHere result = null;
...do async work here to populate result...
return result;
}
你基本上有两个选择:
- (最佳实践)正如其他人所指出的,最佳实践是使用 async / await 链来异步完成您的工作,而不是后台工作者。您只需将所有后台作业代码放入一个异步方法中,然后使用 await 关键字调用它。
这是一个示例,可用于提示无限次提示并在之后继续作业。
//You can bind this to a Button or any other WPF event,
// the point is that it should be run from UI thread
private async void JobStartEvent()
{
JobResult jobResult = new JobResult
{
JobStatus = JobStatus.NotStarted
};
while (jobResult.JobStatus != JobStatus.Done)
{
jobResult = await DoLongJob(jobResult.ContinuationInfo);
if (jobResult.JobStatus == JobStatus.UserPromptRequired)
{
jobResult.ContinuationInfo.PromptResult = PromptAndGetResult(jobResult.PromptInfo);
}
}
}
private async Task<JobResult> DoLongJob(JobContinuationInfo continuationInfo)
{
//Do long stuff here
// continue the job using "continuationInfo"
//When prompt needed, Do:
{
return new JobResult
{
JobStatus = JobStatus.UserPromptRequired,
PromptInfo = new PromptInfo(), //Fill with information required for prompt
ContinuationInfo = new ContinuationInfo() //Fill with information required for continuing the job (can be a delegate to a local function to continue the job)
};
}
//When done, Do:
{
return new JobResult { JobStatus = JobStatus.Done};
}
}
private async JobResult DoLongJob()
{
return JobResult =
}
private enum JobStatus
{
NotStarted,
UserPromptRequired,
Done
}
internal class JobContinuationInfo
{
public PromptResult PromptResult { get; set; }
// Other properties to continue the job
}
private class JobResult
{
public JobStatus JobStatus { get; set; }
public PromptInfo PromptInfo { get; set; }
public JobContinuationInfo ContinuationInfo { get; set; }
}
阅读更多: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/
- 要使用后台工作程序,您可以使用 Dispatcher.Invoke 方法并在那里传递 window 创建代码。 window的创建会在UI线程中完成,但是后台工作线程会等待它执行,得到结果(可以是你提示的结果)然后继续执行。
System.Windows.Threading.Dispatcher.Invoke<ResultType>(async () =>
{
return PromptUserAndGetResult();
});
阅读更多: https://docs.microsoft.com/en-us/dotnet/api/system.windows.threading.dispatcher.invoke