2016-10-22 58 views
2

看到我的下面的代碼,並告訴我什麼是錯誤的,當我的用戶界面更新時,所有任務完成,但根據代碼更新標籤值時,我的例程正在調用任務。在我的代碼中改變什麼。當所有任務完成時,我的用戶界面得到更新

例如說當DoSomething1被調用時,則需要在用戶之前更新和反映label3。

private void button1_Click(object sender, EventArgs e) 
{ 
    TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 
    var token = Task.Factory.CancellationToken; 

    var tasks = new[] 
    { 
     Task.Factory.StartNew(DoSomething1,token,TaskCreationOptions.None, uiScheduler), 
     Task.Factory.StartNew(DoSomething2,token,TaskCreationOptions.None, uiScheduler), 
     Task.Factory.StartNew(DoSomething3,token,TaskCreationOptions.None, uiScheduler) 
    }; 
    Task.WaitAll(tasks); 
    //var things = Task.WhenAll(tasks); 

    int x=0; 
} 

public void DoSomething1() 
{ 
    //this.label3.BeginInvoke(new Action(() => 
    //{ 
    // this.label3.Text = "DoSomething1 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId; 
    //})); 
    this.label3.Text = "DoSomething1 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId; 
    System.Threading.Thread.Sleep(1000); 
} 

public void DoSomething2() 
{ 
    //this.label4.BeginInvoke(new Action(() => 
    //{ 
    // this.label4.Text = "DoSomething2 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId; 
    //})); 
    this.label4.Text = "DoSomething2 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId; 
    System.Threading.Thread.Sleep(1000); 
} 

public void DoSomething3() 
{ 
    //this.label5.BeginInvoke(new Action(() => 
    //{ 
    // this.label5.Text = "DoSomething3 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId; 
    //})); 
    this.label5.Text = "DoSomething3 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId; 
    System.Threading.Thread.Sleep(1000); 
} 

回答

2

The other answer是正確的,就目前而言。使用FromCurrentSynchronizationContext()會導致正在使用的調度程序始終使用當前線程來運行任務。即UI線程。這些任務應該與Task.Run()一起運行,並且不需要特定的調度程序(它將默認爲線程池調度程序)。 BeginInvoke()是正確訪問Label對象的一種選擇。

但是,在我看來,修復所有的代碼會更好,因此它在當前的範例中更具慣用性。例如:

private async void button1_Click(object sender, EventArgs e) 
{ 
    // Your original example didn't show how you used this value, 
    // so I don't have anything in this example that uses it. But you 
    // would probably want to pass it to the "DoSomething..." methods 
    // so that those methods can then pass the token to whatever async 
    // operation they are actually doing. See additional comment below. 
    var token = Task.Factory.CancellationToken; 

    var tasks = new[] 
    { 
     DoSomething1(), 
     DoSomething2(), 
     DoSomething3() 
    }; 
    await Task.WhenAll(tasks); 

    int x=0; 
} 

public async Task void DoSomething1() 
{ 
    this.label3.Text = "DoSomething1 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId; 
    // replace with `Task.Run()` or whatever already-asynchronous 
    // operation you need/want. Likewise in the other methods. 
    // Don't forget to pass the CancellationToken to these methods, 
    // and then on to whatever tasks you actually are running. 
    await Task.Delay(1000); 
} 

public async Task DoSomething2() 
{ 
    this.label4.Text = "DoSomething2 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId; 
    await Task.Delay(1000); 
} 

public async Task DoSomething3() 
{ 
    this.label5.Text = "DoSomething3 -- " + System.Threading.Thread.CurrentThread.ManagedThreadId; 
    await Task.Delay(1000); 
} 
+0

你沒有使用或通過'uiScheduler和令牌'那麼爲什麼你創造這個? – Mou

+0

首先,使用'uiScheduler'是你的代碼主要的錯誤。這是不可能的使用它,仍然有代碼工作。你的代碼並沒有顯示你實際上使用了'token'(你把它傳遞給'StartNew()',但你自己的代碼從未使用它,所以你的任務不能被取消),所以我沒有辦法知道它是如何應該在任何替代的例子中使用,所以我只是把它排除在外。正如你可以從我的代碼示例中的註釋中看到的,如果你想要取消任務,你必須將它傳遞給你想要取消的任務。 –

+0

如果我評論這一行然後會發生什麼'TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();' – Mou

2

雖然我不熟悉TaskScheduler它看起來像它的調度所有任務的UI線程。

不要使用調度,然後做你的UI更新,使用這樣的:

 var threadId = System.Threading.Thread.CurrentThread.ManagedThreadId; 
     this.BeginInvoke(() => { 
      this.label3.Text = "DoSomething1 -- " + threadId ; 
     }); 

這將調用你的UI操作到UI線程。

+0

這是正確和有用的。但恕我直言,最好是用'async' /'await'完成所有的工作,然後不需要像'BeginInvoke()'這樣的東西(至少在本例中不是這樣)。請參閱[我的答案](http://stackoverflow.com/a/40199065) –

+0

我使用BeginInvoke(),但我試圖知道如何更新UI沒有BeginInvoke() – Mou

相關問題