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.

しかし、2番目のタスクを実行すると、作成されたスレッドとは異なるスレッドからコントロールにアクセスできないというエラーが発生し続けます。

どんな助けでも大歓迎です!

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ロジックを1か所にまとめる必要があります。

//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 に答える