1

有没有办法同时调用多个方法?我有一个 winforms 应用程序,它在加载时会加载大量数据:

private void form1_Load(object sender, EventArgs e)
{
    LoadValues1();
    LoadValues2();
    LoadValues3();
    LoadValues4();
    LoadValues5();
    LoadValues6();
    LoadValues7();
    LoadValues8();
}

这些方法检索数据并填充 DevExpress LookUpEdits(类似于 windows 下拉列表),所以它们看起来像这样:

DBContext dbContext = new DBContext();
ObservableCollection<string> values1 = 
    new ObservableCollection<string>((from i in dbContext.Items
                                      where i.Value1 != null
                                      && i.Value1.Length > 0
                                      orderby i.Value1
                                      select i.Value1).Distinct());

lookupValues1.Properties.DataSource = descModelYear;
DevExpress.XtraEditors.Controls.LookUpColumnInfoCollection colInfo = lookupValues1.Properties.Columns;
colInfo.Clear();
colInfo.Add(new DevExpress.XtraEditors.Controls.LookUpColumnInfo("Column"));
colInfo[0].Caption = "Values 1";

其中一些方法需要一段时间才能完成,但它们都不是相互依赖的,所以我想我可以同时完成它们:

Task.Factory.StartNew(() => LoadValues1());
Task.Factory.StartNew(() => LoadValues2());
etc.

但是当第二个任务运行时我不断收到错误,说不能从与创建它的线程不同的线程访问控件。

任何帮助表示赞赏!

4

3 回答 3

2

正如其他人指出的那样,您需要确保在访问 UI 元素时需要确保您在正确阅读时进行操作。使用任务并行库很容易做到这一点,如下所示:

private TaskScheduler m_TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();

拥有 TaskScheduler 后,您可以安排任务在 UI 线程上运行,如下所示:

Task.Factory.StartNew(() => 
{
     LoadValues1();
}, CancellationToken.None, TaskCreationOptions.None, m_TaskScheduler);

这里需要注意的是,在 UI 线程上运行您的所有任务可能仍会锁定您。我建议您创建某种类或一组集合,您可以将相关信息填充到其中,然后一旦所有数据都存在,您就可以在 UI 线程上调用另一个方法,该方法只是将您的控件绑定到数据或执行您需要的任何 UI 特定操作。

于 2013-03-26T18:06:03.143 回答
1

操作 UI 控件时,您必须在创建控件的同一线程上执行此操作。在这种情况下,您应该只运行那些同步修改 UI 的方法。如果所有方法都修改了 UI,您应该拆分工作,以便在 UI 线程上调用修改 UI 的代码。

通常,您可以使用InvokeRequired来检查您是否在正确的线程上,并Invoke在 UI 线程上运行方法。

于 2013-03-26T18:01:42.133 回答
0

您应该将您的逻辑分离到不同的单元中,并尝试将您的 UI 逻辑放在一个地方。

//private fields
private readonly DBContext _dbContext = new DBContext();

private Task<ICollection<string>> GetValues1()
{
    return Task.Run(() =>
            {
                return (from i in _dbContext.Items
                        where i.Value1 != null
                        && i.Value1.Length > 0
                        orderby i.Value1
                        select i.Value1)
                        .Distinct()
                        .ToList();
             };
}

private void LoadUIElements1(ICollection<string> values)
{
    var observableValues = new ObservableCollection<string>(values);

    lookupValues1.Properties.DataSource = descModelYear;
    DevExpress.XtraEditors.Controls.LookUpColumnInfoCollection colInfo = lookupValues1.Properties.Columns;
    colInfo.Clear();
    colInfo.Add(new DevExpress.XtraEditors.Controls.LookUpColumnInfo("Column"));
    colInfo[0].Caption = "Values 1";
}

private async void form1_Load(object sender, EventArgs e)
{
    var tasks = new List<Task>();

    // Start each UI task so they will complete independently.
    var uiTask1 =  GetValues1()
          .ContinueWith(t =>
                LoadUIElements1(t.Result),
                CancellationToken.None,
                TaskCreationOptions.None,
                TaskScheduler.FromCurrentSynchronizationContext());
    tasks.Add(uiTask1);

    // Wait for all the tasks to complete
    Task.WaitAll(tasks.ToArray());
    tasks.Clear();
}
于 2013-03-26T18:20:18.747 回答