在后台填充数据网格

时间:2012-02-21 04:19:00

标签: wpf multithreading grid devexpress task

我试图在后台填充devexpress GridControl(它不是快速过程)。我是这样做的:

...
CreateGrid();
ShowMessageInsteadOfGridControl;
...
FillGrid(dataGrid, other UI params);
...

在网格中写入数据:

private void FillGrid(GridControl data, ...);
{
   Task.Factory.StartNew(() =>
                                 {
                                      Application.Current.Dispatcher.Invoke(new Action(() => FillData(gridControl,UIparamns)),
                                                        DispatcherPriority.Background);
                                  }).ContinueWith(c => HideUserMessage(UIparamns));
}

当我调用FillData时,会导致UI冻结。我不能使用常用的Task,因为网格从UI填充而且我有#34;调用线程无法访问此对象"。

如何在不冻结UI的情况下在后台进行此类数据混合处理?

2 个答案:

答案 0 :(得分:0)

调度程序调用调用将所有内容重新放回UI线程,您需要将操作拆分为可在后台完成的部分以及真正需要的部分在UI线程上完成,比如添加项目,只将这些操作传递给调度程序。

DispatcherPriority.Background只是意味着其他具有更高优先级的项目将首先执行,这与后台线程无关,每次调用UI线程的调度程序都会导致执行该操作早晚用UI线程说)

答案 1 :(得分:0)

通常,在处理与UI线程相关的代码时使用Task.Factory.StartNew(...)是危险的,因为它第一次检查TaskScheduler时发现没有TaskScheduler,并且会使用线程池Compute(3)。使用称为private void Form1_Load(object sender, EventArgs e) { Task.Factory.StartNew(A); } private static void A() { } private void Form1_Load(object sender, EventArgs e) { Compute(3); } private void Compute(int counter) { // If we're done computing, just return. if (counter == 0) return; var ui = TaskScheduler.FromCurrentSynchronizationContext(); Task.Factory.StartNew(() => A(counter)) .ContinueWith(t => { Text = t.Result.ToString(); // Update UI with results. // Continue working. Compute(counter - 1); }, ui); } private int A(int value) { return value; // CPU-intensive work. } 的函数完成线程的计算后,它将返回,但在这里将其编组回UI线程,然后将使用到目前为止的结果更新UI线程。

第二次和第三次调用Compute,因为SynchronizationContext已封送回UI,它将在UI线程上运行,从而阻塞您的UI。

Task.Run(() => A());

为避免此潜在问题,请改用 private readonly object _myDataLock = new object(); private FastObservableCollection<My20FieldsDataRecord> MyList = new FastObservableCollection<My20FieldsDataRecord>(); private CollectionViewSource MyListCollectionView = new CollectionViewSource(); public MyViewModelConstructor() : base() { // Other ctor code // ... // assign the data source of the collection views MyListCollectionView.Source = MyList; // Setup synchronization BindingOperations.EnableCollectionSynchronization(MyList, _myDataLock); } private async void LoadMyList() { // load the list await Task.Run(async () => { MyList.ReplaceAll(await MyRepository.LoadMyList()); } ); }

有关更多详细信息,请参阅https://blog.stephencleary.com/2013/08/startnew-is-dangerous.html和/或What is the difference between Task.Run() and Task.Factory.StartNew()上Stephen Stepheny的文章

这是我发现在不阻止UI的情况下在后台加载数据网格的数据的一种方法。

首先,创建一个锁对象,并启用集合同步,然后使用Task.Run()在后台线程上实际加载数据:

    public virtual async Task<IList<My20FieldsDataRecord>> LoadMyList()
    {
        var results = await this.DataContext.TwentyFieldDataRecords
           .OrderByDescending(x => x.MyDate).ToListAsync().ConfigureAwait(false);

        return results;
    }   

然后在您的存储库中,您可以编写:

<controls:DataGrid Name="MyListDataGrid" Grid.Row="1"
                   ....
                   ItemsSource="{Binding MyListCollectionView.View}" 
                   ... >

然后,您可以像这样在关联的视图中进行绑定:

turncount = 0

有关详细信息,请参阅: