WPF:如何在UI线程中进行异步调用

vin*_*nmm 1 c# wpf xaml multithreading

我在xaml中有一个按钮,其鼠标点击连接到委托命令.在委托命令中,我调用另一个创建位图并将其保存为pdf的方法.此方法需要几秒钟(通常超过10秒),在此期间应用程序进入无响应状态,无法访问UI.在此期间,我想展示一些已经在xaml中定义的动画.但是在调用time-taking-function之前显示它并在之后隐藏它并不起作用.如果我不使用不同的线程,它会在时间执行功能执行结束时显示.

所以,我尝试使用创建一个不同的线程并调用此时间函数.动画加载正常但该函数实际上需要访问UI线程中的一些UI对象.它导致了这个异常:"调用线程无法访问此对象,因为不同的线程拥有它."

有没有办法实现它?即,在此功能执行期间显示动画?

一些代码片段:

private void OnExportPDFCommand()
    {
        PanelLoading = true;  // Flag to show animation
        Task.Factory.StartNew(() =>
            {
                CreatePDF();  //time-taking-function
                Application.Current.Dispatcher.Invoke(() => PanelLoading = false);
            });
    }
Run Code Online (Sandbox Code Playgroud)

请用一个小例子来解释.我是WPF的新手.谢谢.

Ren*_*ogt 9

你可以创建OnExportPDFCommand一个async方法,await然后Task开始:

private async void OnExportPDFCommand()
{
    PanelLoading = true;  // Flag to show animation
    await Task.Run(() =>
    {
            CreatePDF();  //time-taking-function
    });
    PanelLoading = false; // stop animation
}
Run Code Online (Sandbox Code Playgroud)

编译器将其转换为状态机.控制流将返回到await关键字处的调用者(UI).当Task完成后,执行最终恢复的下一个语句PanelLoading = false.

通过这种方式,调用PanelLoading是在 UI线程一次也不例外应该提高.

如果您需要对UI(内部CreatePDF)进行其他调用,则可以使用Application.Current.Dispatcher.Invoke(...)在UI线程上调用这些调用.


作为旁注:您可能希望禁用在开头处启动此按钮的按钮,OnExportPDFCommand()并在结束时再次启用它.这样,您可以避免多次启动操作并与动画混淆.

  • @vinmm作为一个旁白.`bool PanelLoading`模式可能不是一个好主意.如果多次调用`OnExportPDFCommand()`,则可能会出现有关`PanelLoading`标志的意外行为.用int替换`bool PanelLoading`可能更好,你可以使用`Interlocked.Increment`和`Interlocked.Decrement`. (3认同)