WPF 进度条工作但在 UI 线程中阻塞,即使使用异步
WPF Progress bar working but blocked in UI thread even using async
我正在尝试在我的程序中实现一个不确定的进度条。我是线程的新手,但据我所知,这里最好的选择之一是添加异步方法,并等待 "heavy" 函数执行其结果。所以我写了这个:
public void Window_Loaded(object sender, RoutedEventArgs e)
{
firstLoad();
}
private async void firstLoad()
{
LW.Title = "Loading...";
LW.Show();
filterTextBox.Text = defaultSearch;
await Task.Run(() => InitializeFilter());
}
private void InitializeFilter()
{
//Asynchronous???
Dispatcher.BeginInvoke(new Action(() => {
//... some lines of code that takes some time to run.
dataGrid.ItemContainerGenerator.StatusChanged += new EventHandler(closeLoadingWindow);
}));
private void closeLoadingWindow(object sender, EventArgs e)
{
if (LW != null)
{
LW.closable = true;
LW.Close();
}
}
firstLoad 在 window 加载时运行,显示不确定的 LW loadingWindow,运行 InitializeFilter() 方法(重的)。最后,当网格被填充和加载时,一个事件被触发,允许 LW window 被关闭并关闭它(如果我没有让它不可关闭,一个有趣的用户可以点击或使用 F4 关闭它,这不好)。
系统工作正常,在时间范围内一切都按预期进行,但加载栏被冻结,没有显示进度。相同的 LW 栏在具有类似设置的 MainWindow 中工作 我错过了什么?提前致谢!
不要使用您的调度员。 Microsoft 有先见之明,使用它的魔法 (SynchronizationContext) 能够在异步上下文中执行的方法中更新 UI 线程。这在他们的 async/await 示例中得到证明 here
而在 previous/other 情况下,您将不得不编组回主 (UI) 线程以更新 UI 线程,或者等到完成并检索结果来自共享状态的对象。由于您正在使用 async/await 那么您应该可以不使用调度程序,直接更新 UI。
as far as I know one of the best options here is to add an async method, and await the "heavy" function to perform its results
最佳选择是使用 Task.Run
将繁重的处理移至线程池,并使用 await
检索其结果。
目前的代码使用Task.Run
移动到线程池,然后立即转身使用Dispatcher
移动回UI线程,然后再进行繁重的操作加工。因此,它阻塞了 UI 线程。
what this particular DataGrid displays is a CollectionView, which is not thread-safe.
是的,您不能从线程池线程更新数据绑定对象。
最好的解决方案是 将繁重的处理与 UI 更新分开,像这样:
public async void Window_Loaded(object sender, RoutedEventArgs e)
{
await firstLoadAsync();
}
private List<FilterType> InitializeFilter()
{
//... some lines of code that takes some time to run.
}
private async Task firstLoadAsync()
{
LW.Title = "Loading...";
LW.Show();
filterTextBox.Text = defaultSearch;
var filterData = await Task.Run(() => InitializeFilter()); // Get the plain data on a background thread
myCollectionView = new CollectionView(filterData); // Update the UI
if (LW != null)
{
LW.closable = true;
LW.Close();
}
}
我正在尝试在我的程序中实现一个不确定的进度条。我是线程的新手,但据我所知,这里最好的选择之一是添加异步方法,并等待 "heavy" 函数执行其结果。所以我写了这个:
public void Window_Loaded(object sender, RoutedEventArgs e)
{
firstLoad();
}
private async void firstLoad()
{
LW.Title = "Loading...";
LW.Show();
filterTextBox.Text = defaultSearch;
await Task.Run(() => InitializeFilter());
}
private void InitializeFilter()
{
//Asynchronous???
Dispatcher.BeginInvoke(new Action(() => {
//... some lines of code that takes some time to run.
dataGrid.ItemContainerGenerator.StatusChanged += new EventHandler(closeLoadingWindow);
}));
private void closeLoadingWindow(object sender, EventArgs e)
{
if (LW != null)
{
LW.closable = true;
LW.Close();
}
}
firstLoad 在 window 加载时运行,显示不确定的 LW loadingWindow,运行 InitializeFilter() 方法(重的)。最后,当网格被填充和加载时,一个事件被触发,允许 LW window 被关闭并关闭它(如果我没有让它不可关闭,一个有趣的用户可以点击或使用 F4 关闭它,这不好)。
系统工作正常,在时间范围内一切都按预期进行,但加载栏被冻结,没有显示进度。相同的 LW 栏在具有类似设置的 MainWindow 中工作 我错过了什么?提前致谢!
不要使用您的调度员。 Microsoft 有先见之明,使用它的魔法 (SynchronizationContext) 能够在异步上下文中执行的方法中更新 UI 线程。这在他们的 async/await 示例中得到证明 here
而在 previous/other 情况下,您将不得不编组回主 (UI) 线程以更新 UI 线程,或者等到完成并检索结果来自共享状态的对象。由于您正在使用 async/await 那么您应该可以不使用调度程序,直接更新 UI。
as far as I know one of the best options here is to add an async method, and await the "heavy" function to perform its results
最佳选择是使用 Task.Run
将繁重的处理移至线程池,并使用 await
检索其结果。
目前的代码使用Task.Run
移动到线程池,然后立即转身使用Dispatcher
移动回UI线程,然后再进行繁重的操作加工。因此,它阻塞了 UI 线程。
what this particular DataGrid displays is a CollectionView, which is not thread-safe.
是的,您不能从线程池线程更新数据绑定对象。
最好的解决方案是 将繁重的处理与 UI 更新分开,像这样:
public async void Window_Loaded(object sender, RoutedEventArgs e)
{
await firstLoadAsync();
}
private List<FilterType> InitializeFilter()
{
//... some lines of code that takes some time to run.
}
private async Task firstLoadAsync()
{
LW.Title = "Loading...";
LW.Show();
filterTextBox.Text = defaultSearch;
var filterData = await Task.Run(() => InitializeFilter()); // Get the plain data on a background thread
myCollectionView = new CollectionView(filterData); // Update the UI
if (LW != null)
{
LW.closable = true;
LW.Close();
}
}