2016-10-22 3 views
2

내 아래 코드를보고 모든 작업이 완료되면 내 UI가 업데이트되는데 어떤 문제가 있는지 알려주세요. 코드별로 루틴이 작업에 의해 호출 될 때 레이블 값을 업데이트한다고 가정합니다. . 내 코드에서 무엇을 바꿀 것인가.모든 작업이 완료되면 내 UI가 업데이트 됨

예를 들어 DoSomething1이 호출되면 사용자 앞에 label3을 업데이트하고 반영해야한다고 말합니다. 내가 TaskScheduler에 익숙 해요하지만이 UI 스레드에서 모든 작업을 예약하는 것처럼

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 개체에 올바르게 액세스하기위한 하나의 옵션입니다.

그러나 현재로서는 모든 코드를 수정하여 현재 async/await 패러다임에서 더 관용적 인 것으로 보입니다. 예 :

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

uuScheduler 및 token'을 사용하거나 전달하지 않았습니다. 그럼 왜 이걸 만들지? – Mou

+0

'uiScheduler'를 사용하는 것이 가장 먼저 코드에서 잘못된 점이었습니다. 코드를 사용하고 코드 작업을 할 수는 없습니다. 코드는 실제로 당신을'token '으로 보이지 않았다. (당신은'StartNew()'에 그것을 전달했지만 자신의 코드는 결코 그것을 사용하지 않으므로 당신의 작업은 취소 될 수 없다.) 그래서 내가 어떻게 그것을 알 수있는 방법은 없다. 다른 예에서 사용해야하므로 방금 나갔습니다. 내 코드 예제의 주석에서 볼 수 있듯이 작업을 취소 할 수 있도록하려면 취소 할 수있는 작업에이 작업을 전달해야합니다. –

+0

만약 내가이 줄을 주석한다면'TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); ' – Mou

2

가 보인다. 이 UI 스레드에 당신의 UI 작업을 호출합니다

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

:

은 UI 업데이트가 같은 것을 사용 할 다음, 스케줄러를 사용하지 마십시오.

+0

정확하고 유용합니다. 그러나 IMHO' async' /'await'으로 끝내는 것이 낫다. 그리고 BeginInvoke()와 같은 것들이 필요 없다. (최소한이 예제에서는 그렇지 않다.) [내 대답] (http://stackoverflow.com/a/40199065)를 참조하십시오. –

+0

BeginInvoke()를 사용하지만 BeginInvoke()없이 UI를 어떻게 업데이트 할 수 있는지 알고 싶습니다. – Mou

관련 문제