在启用了自动滚动(WPF)(C#)的用户界面中切换到其他选项卡时,仍然使用UI冻结用户界面

问题描述 投票:-1回答:1

Hi All,

我目前正在用C#开发我的第一个WPF程序(将文件自动移动到结构化文件夹路径的基本工具),并且几乎完成了。但是我遇到了一个问题。我的用户界面由三个不同的选项卡组成,它们显示一个主页(带有用户控件),一个日志页面和一个关于页面。在日志文本框上启用自动滚动后,切换到“日志”选项卡时,UI冻结。程序使用基本的textboxoutputter.

输出到日志

启用自动滚动的代码包括:

TXTBX_Log Xaml:

<TextBox x:Name="TXTBX_Log" Grid.Column="1" Grid.ColumnSpan="7" Grid.Row="1" Grid.RowSpan="7" Background="#FF3F3F46" Foreground="White" VerticalContentAlignment="Bottom" IsReadOnly="True" TextChanged="ScrollToEnd" />

TXTBX_Log TextChanged事件:

private void ScrollToEnd(object sender, TextChangedEventArgs e)
    {
        TXTB_MainWindow.ScrollToEnd();
    }

UI看起来像这样:

The UI

当用户按下开始按钮时,我将启动后台工作人员。这个想法是,在用户按下Start之后,他/他可以切换到“日志”选项卡以关注程序的运行情况。我用来完成此操作的代码粘贴在下面:

开始按钮fullAutomation设置为TRUE:

private void BTN_Start_Click(object sender, RoutedEventArgs e)
    {
        Console.WriteLine("Opdracht wordt uitgevoerd");
        if (fullAutomation == false)
        {
            archivingWorker = new BackgroundWorker();
            archivingWorker.DoWork += ArchivingWorker_DoWork;
            archivingWorker.RunWorkerCompleted += ArchivingWorker_RunWorkerCompleted;
            archivingWorker.RunWorkerAsync();
        }
        else
        {
            fullAutomationWorker = new BackgroundWorker();
            fullAutomationWorker.DoWork += FullAutomationWorker_DoWork;
            fullAutomationWorker.RunWorkerCompleted += FullAutomationWorker_RunWorkerCompleted;
            fullAutomationWorker.RunWorkerAsync();
        }
    }

我的问题是,后台线程运行时UI线程冻结,并且启用自动滚动时用户切换到日志选项卡。有人知道为什么会这样吗?

c# wpf windows backgroundworker desktop
1个回答
0
投票

@@ pot RunWorkerAsync()在不同的线程上启动工作程序,因此UI不会冻结。 ArchivingWorker尚不包含任何代码,因为它在程序的当前状态下没有使用。

猜测它不是在不同的Thread上启动,而是异步地使用Event处理程序。因此,您需要async事件处理程序才能实现真正的异步效果。

1)将事件处理程序类型更改为async void

private void FullAutomationWorker_DoWork(object sender, DoWorkEventArgs e)

to

private async void FullAutomationWorker_DoWork(object sender, DoWorkEventArgs e)

2)将延迟更改为异步延迟

Thread.Sleep(waitTime);

to

await Task.Delay(waitTime);

精确地await使方法调用异步,并且await中只能使用awaitable方法。

注: async void仅对事件处理程序有用,而对任何不好的async方法都没有用。建议将async Task用于其他方法。

// returns nothing
private async Task MyMethodAsync()
{
    // do async job
    await Task.Delay(10); // awaitable call
}

// returns string
private async Task<string> MyMethod2Async()
{
    string result = "example result";
    // do async job
    await Task.Delay(10);
    return string;
}

async方法中的用法

await MyMethodAsync();

string text = await MyMethod2Async();

在常规同步代码中使用,甚至不需要这种方法,它称为“异步同步”。

MyMethodAsync().GetAwaiter().GetResult();

string text = MyMethod2Async().GetAwaiter().GerResult();

并在与同步代码不同的线程中运行异步方法。

Task task = Task.Run(MyMethodAsync); // run it
// do job here while Task is running
task.Wait(); // wait for completion


Task<string> task2 = Task.Run(MyMethodAsync2); // run it
// do job here while Task is running
text = task2.GetAwaiter().GetResult(); // wait for completion and get result
© www.soinside.com 2019 - 2024. All rights reserved.