我正在尝试在我的程序中实施不确定的进度条。我是线程新手,但据我所知,这里最好的选择之一就是添加一个异步方法,等待" 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在加载窗口时运行,显示一个不确定的LW loadingWindow,并运行InitializeFilter()方法(较重的一个)。最后,当填充并加载网格时,会触发一个事件,允许LW窗口关闭并关闭它(如果我没有使它无法关闭,有趣的用户可以关闭它点击或使用F4,这是不太好)。
系统工作正常,一切都按预期工作,但是加载栏被冻结,没有显示进度。在MainWindow中使用相同的LW栏进行类似的设置我缺少什么?提前致谢!
答案 0 :(得分:1)
据我所知,这里最好的选择之一就是添加一个异步方法,等待" heavy"功能来执行其结果
最好的选择是使用Task.Run
将繁重的处理移动到线程池,并使用await
检索其结果。
当前的代码使用Task.Run
移动到线程池,然后立即转身并使用Dispatcher
在执行繁重处理之前移回UI线程。因此,它阻止了UI线程。
这个特定的DataGrid显示的是CollectionView,它不是线程安全的。
是的,您无法从线程池线程更新数据绑定对象。
最佳解决方案是将重处理与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();
}
}
答案 1 :(得分:0)
不要使用您的调度员。微软有远见使用它的魔力(SynchronizationContext)能够更新在异步上下文中执行的方法中的UI线程。这在他们的async / await示例here
中得到了证明在以前/其他情况下,您必须编组回主(UI)线程以更新UI线程,或者等到完成并从共享状态的对象检索结果。由于您使用的是async / await,因此您可以不使用调度程序,并直接更新UI。