如何使用 WPF 中的任务正确刷新网格中的数据
How to correctly refresh data in a grid using Task in WPF
我的小 WPF 代码给我这个错误
调用线程无法访问此对象,因为另一个线程拥有它
我知道它到底在说什么,但我无法理解如何修复它。我尝试了不同的东西但没有运气,我承认我在任务库中表现不佳。
这就是我想要达到的目标。
- 加载 WPF 表单时加载数据 - 这没问题
- 在表单上,用户将按下 刷新 按钮以刷新数据库中的数据。
这是我的代码
public partial class DocListView : UserControlListBase
{
private ScecoBillDataScope _scecoBillDataScope;
public EntityCollection<ScecoBillEntity> ScecoBills = new EntityCollection<ScecoBillEntity>();
public DocListView()
{
InitializeComponent();
LoadData();
}
private async void LoadData()
{
await Task.Run(() =>
{
_scecoBillDataScope.FetchData();
});
var collectionView = CollectionViewSource.GetDefaultView(_scecoBillDataScope.ScecoBills);
await Dispatcher.BeginInvoke(new ThreadStart(()=> LayoutRoot.DataContext = collectionView));
}
private void BbiRefresh_ItemClick(object sender, DevExpress.Xpf.Bars.ItemClickEventArgs e)
{
_scecoBillDataScope.Reset();
LoadData();
e.Handled = true;
}}
实际上,当我在这一行单击刷新按钮时出现错误 _scecoBillDataScope.FetchData();
请指教。
你的问题是这一行:
await Dispatcher.BeginInvoke(new ThreadStart(()=> LayoutRoot.DataContext = collectionView));
你只是在创建一个新线程,你必须在 GUI 线程上实际调度:
Application.Current.Dispatcher.Invoke(() =>
{
LayoutRoot.DataContext = collectionView;
});
您似乎想在 UI 话题中做点什么。
如您所知,您可以使用 Dispatcher
class。
但是还有另一种方法可以向 UI 线程提问。
var uiThread = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
{
// I assumed that It returns boolean value
_scecoBillDataScope.FetchData();
}).ContinueWith(x =>
{
// Here you can put the code to work on the UI thread.
if (x.Result)
{
var collectionView = CollectionViewSource.GetDefaultView(_scecoBillDataScope.ScecoBills);
LayoutRoot.DataContext = collectionView;
}
}, uiThread);
希望对您有所帮助。
谢谢。
由于您的 collection 项目是与您的视图绑定的数据,因此您必须将它们视为 UI 的一部分。
尝试从 Task.Run
中加载新的 collection,然后在 UI 线程中将它们复制到现有项目上。所以,新的collection建立在一个线程池线程(Task.Run
)上,然后data-boundcollection项是从UI线程修改的。
我的小 WPF 代码给我这个错误 调用线程无法访问此对象,因为另一个线程拥有它 我知道它到底在说什么,但我无法理解如何修复它。我尝试了不同的东西但没有运气,我承认我在任务库中表现不佳。
这就是我想要达到的目标。
- 加载 WPF 表单时加载数据 - 这没问题
- 在表单上,用户将按下 刷新 按钮以刷新数据库中的数据。
这是我的代码
public partial class DocListView : UserControlListBase
{
private ScecoBillDataScope _scecoBillDataScope;
public EntityCollection<ScecoBillEntity> ScecoBills = new EntityCollection<ScecoBillEntity>();
public DocListView()
{
InitializeComponent();
LoadData();
}
private async void LoadData()
{
await Task.Run(() =>
{
_scecoBillDataScope.FetchData();
});
var collectionView = CollectionViewSource.GetDefaultView(_scecoBillDataScope.ScecoBills);
await Dispatcher.BeginInvoke(new ThreadStart(()=> LayoutRoot.DataContext = collectionView));
}
private void BbiRefresh_ItemClick(object sender, DevExpress.Xpf.Bars.ItemClickEventArgs e)
{
_scecoBillDataScope.Reset();
LoadData();
e.Handled = true;
}}
实际上,当我在这一行单击刷新按钮时出现错误 _scecoBillDataScope.FetchData(); 请指教。
你的问题是这一行:
await Dispatcher.BeginInvoke(new ThreadStart(()=> LayoutRoot.DataContext = collectionView));
你只是在创建一个新线程,你必须在 GUI 线程上实际调度:
Application.Current.Dispatcher.Invoke(() =>
{
LayoutRoot.DataContext = collectionView;
});
您似乎想在 UI 话题中做点什么。
如您所知,您可以使用 Dispatcher
class。
但是还有另一种方法可以向 UI 线程提问。
var uiThread = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
{
// I assumed that It returns boolean value
_scecoBillDataScope.FetchData();
}).ContinueWith(x =>
{
// Here you can put the code to work on the UI thread.
if (x.Result)
{
var collectionView = CollectionViewSource.GetDefaultView(_scecoBillDataScope.ScecoBills);
LayoutRoot.DataContext = collectionView;
}
}, uiThread);
希望对您有所帮助。
谢谢。
由于您的 collection 项目是与您的视图绑定的数据,因此您必须将它们视为 UI 的一部分。
尝试从 Task.Run
中加载新的 collection,然后在 UI 线程中将它们复制到现有项目上。所以,新的collection建立在一个线程池线程(Task.Run
)上,然后data-boundcollection项是从UI线程修改的。