【问题标题】:From background process open window and take input from user in WPF从后台进程打开窗口并在 WPF 中从用户那里获取输入
【发布时间】:2019-12-06 03:24:17
【问题描述】:

在我的 C# WPF 应用程序中,我正在使用 BackgroundWorker 执行某些异步报告工作。我可以使用 ProgressChanged 事件从 backgroundWorker 更新 UI。

但是,我需要在此过程中要求用户输入,在后台进程中的某些点我需要打开窗口要求用户输入,根据该输入,后台进程将进一步继续。

我可以从后台进程打开一些窗口,然后在用户对该窗口做出响应后继续该进程吗?

【问题讨论】:

标签: c# wpf multithreading backgroundworker


【解决方案1】:

您应该将其拆分为不同的后台工作人员。当您在流程中到达需要用户输入的点时,完成/完成您的后台工作人员,然后在 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;
}

【讨论】:

    【解决方案2】:

    你基本上有两个选择:

    1. (最佳实践)正如其他人所指出的,最佳实践是使用 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/

    1. 要使用后台工作者,您可以使用 Dispatcher.Invoke 方法并在那里传递窗口创建代码。窗口创建将在 UI 线程中完成,但后台工作线程会等待它执行,获取结果(可以是您的提示的结果),然后继续执行。
        System.Windows.Threading.Dispatcher.Invoke<ResultType>(async () =>
        {
            return PromptUserAndGetResult();
        });
    

    了解更多: https://docs.microsoft.com/en-us/dotnet/api/system.windows.threading.dispatcher.invoke

    【讨论】:

      猜你喜欢
      • 2018-11-22
      • 2014-01-10
      • 2019-04-11
      • 2017-10-07
      • 2014-12-28
      • 2017-11-30
      • 1970-01-01
      • 1970-01-01
      • 2011-10-31
      相关资源
      最近更新 更多