C# 异步调用多个方法

C# 异步调用多个方法,c#,threadpool,C#,Threadpool,有没有一种方法可以同时调用多个方法?我有一个winforms应用程序,可在加载时加载大量数据: private void form1_Load(object sender, EventArgs e) { LoadValues1(); LoadValues2(); LoadValues3(); LoadValues4(); LoadValues5(); LoadValues6(); LoadValues7(); LoadValues8

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

private void form1_Load(object sender, EventArgs e)
{
    LoadValues1();
    LoadValues2();
    LoadValues3();
    LoadValues4();
    LoadValues5();
    LoadValues6();
    LoadValues7();
    LoadValues8();
}
这些方法检索数据并填充DevExpress LookUpEdits(类似于windows DropDownList),因此它们看起来都是这样的:

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();
}, CancellationToken.None, TaskCreationOptions.None, m_TaskScheduler);
但是,当第二个任务运行时,我不断收到一个错误,说控件不能从与创建它的线程不同的线程访问


感谢您的帮助

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


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

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

private TaskScheduler m_TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
拥有TaskScheduler后,您可以将任务安排在UI线程上运行,如下所示:

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();
}, CancellationToken.None, TaskCreationOptions.None, m_TaskScheduler);

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

您应该在不同的单元,并尝试将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();
}
//私有字段
私有只读DBContext _DBContext=new DBContext();
私有任务GetValues1()
{
返回任务。运行(()=>
{
返回(来自_dbContext.Items中的i)
其中i.Value1!=null
&&i.Value1.Length>0
orderby i.Value1
选择i.Value1)
.Distinct()
.ToList();
};
}
专用void LoadUIElements1(ICollection值)
{
var observableValues=新的ObservableCollection(值);
lookupValues1.Properties.DataSource=descModelYear;
DevExpress.XtraEditors.Controls.LookUpColumnInfoCollection colInfo=lookupValues1.Properties.Columns;
colInfo.Clear();
添加(新的DevExpress.XtraEditors.Controls.LookUpColumnInfo(“Column”));
colInfo[0]。Caption=“值1”;
}
私有异步void form1\u加载(对象发送方,事件参数e)
{
var tasks=新列表();
//启动每个UI任务,使其独立完成。
var uiTask1=GetValues1()
.ContinueWith(t=>
荷载要素1(t.Result),
取消令牌。无,
任务创建选项。无,
TaskScheduler.FromCurrentSynchronizationContext());
任务。添加(uiTask1);
//等待所有任务完成
Task.WaitAll(tasks.ToArray());
任务。清除();
}

在方法
LoadValuesXXX
中,您正在尝试操作UI(现在来自另一个线程)这是不好的。关于这个主题有数百个现有的问题/答案。一旦你解决了跨线程问题,你可能想知道你可以使用一个速记在一个单独的线程中运行一系列操作,然后等待它们全部完成,就像这样:
Parallel.Invoke(action1,action2,action3,action4,action5)
谢谢,但是当我实现它时,我在声明“当前SynchronizationContext不能用作任务计划程序”中遇到以下错误当您尝试设置m_TaskScheduler时是否会发生这种情况?如果是这样,您在代码中的什么位置尝试获取当前同步上下文?我通常在winforms上使用WPF,但我认为它应该在您的表单LoadDecrime中…有一行我没有注释掉的旧代码,这是导致问题的原因。这工作正常。谢谢!哈哈,没问题!如果它让你走上正确的轨道,请随意投票并标记为答案:)在form_load事件中,你有
LoadUIElements1(t.Result)
,但我看不到它的定义。我尝试了
LoadValues1
,但它抱怨传入了t.Result。应该是
LoadValues1
。我更改了
LoadUIElements1
的签名。