2017-11-28 32 views
0

편집 : 선명도를 위해 편집 : 유니버설 윈도우 플랫폼 응용 프로그램에서 작동해야합니다. 어쩌면 관련이 없지만 Thread.Start()와 같은 것들은 사용할 수 없습니다.UI 버튼을 한 번 클릭 한 이벤트 순서 (C#, UWP, XAML)

텍스트 블록을 아래 코드에 표시된대로 업데이트하려고합니다.

그러나 텍스트 블록은 "Btn_Click()"이 완료된 후에 만 ​​업데이트됩니다.

어떻게하면됩니까?

private void Btn_Click() 
{ 
    TextBlock1.Text = "Work started." 
    DoWork(); 
    TextBlock1.Text = "Work done." 
} 

private void DoWork() 
{ 
    myTextBlock2.Text = "Step 1" 
    Step1(); 
    myTextBlock2.Text = "Step 2" 
    Step2(); 
    myTextBlock2.Text = "" 
} 

답변

0

이것은 고전적인 비동기 문제입니다.

DoWork 기능을 비동기로 설정하고 await을 사용하여 호출해야합니다. 이렇게

private async void Btn_Click() 
{ 
    TextBlock1.Text = "Work started." 
    await DoWork(); 
    TextBlock1.Text = "Work done." 
} 

비동기 프로그래밍에 대한 질문이있을 경우

방문이 문서화 :

https://docs.microsoft.com/en-us/dotnet/csharp/async

https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

https://docs.microsoft.com/en-us/dotnet/standard/async-in-depth

편집 :

이것은 비동기 프로그램을 구현하는 방법에 대한 예제입니다. 당신이해야 할 일은

private async void Btn_Click() 
{ 
    TextBlock1.Text = "Work started." 
    await DoWork(); 
    TextBlock1.Text = "Work done." 
} 

private async Task DoWork() 
{ 
    myTextBlock2.Text = "Requesting html from the web."; 

    HttpClient _httpClient = new HttpClient(); 
    string data = await _httpClient.GetStringAsync("example.com/stringdata.html"); 
    //here the function stops executing, and doesn't continue until GetStringAsync returns a value. 
    //While this, it gives back control to the callee (AKA the UI thread, so it doesn't block it, 
    //and can process data like mouse movement, and textblock text changes.) 

    myTextBlock2.Text = "Processing data"; 
    string outputData = await Task.Run(() => HighCPUBoundWork(data)); 

    //The CPU bound work doesn't block the UI thread, because we created a new thread for it. 
    //When it completes, we continue. 

    myTextBlock2.Text = "Writing output data to file"; 

    using (StreamWriter writer = File.CreateText("output.txt")) 
    { 
     await writer.WriteAsync(outputData); 
     //Same thing applies here, we are waiting for the OS to write to the specified file, 
     //and while it is doing that, we can get back to the UI. 
    } 
} 

private string HighCPUBoundWork(string data) 
{ 
    //Here you can do some high cpu intensity work, like computing PI to the 1000000000th digit, or anything. 
    //The html files processing would be more likely tho.. :) 
    //Notice, that this function is not async. 

    return modifiedInputData; 
} 
+0

내 질문에 답변 해 주셔서 감사합니다. 이 경우 정확하게 구현하는 방법에 대해 더 자세히 설명 할 수 있습니까? 나는이 질문을 게시하기 전에 연구를 해왔고 Task Asynchronous Pattern을 사용하여 문제를 해결하는 데 많은 어려움을 겪었다. 그 질문에 대한 명백한 답을 구하려고 시도하면서, 나는 우리가 여기서 본 것에 대한 질문을 어리석게 끝내었다. – Dpt

+0

나는 그것을 구축 할 수 있도록 명시 적 응답을 요청합니다. 그냥 비동기 권고 문제는 컴파일러가 void를 반환하기 때문에 DoWork를 기다릴 수 없다는 불평을한다. 음, 알았어 .- DoWork를 비동기 작업으로 바꾼다.그러나 문제는 계속해서 예상대로 작동하지 않으며 문제 해결을 통해 매우 복잡하고 기능이 완벽하지 않은 솔루션으로 이어집니다. 이것은 내 질문에 대한 링크입니다. 자세한 내용은 다음과 같습니다. (잘 받아 들여지지 않았고 실행 가능한 솔루션을 찾지 못했습니다.) https://stackoverflow.com/questions/47520701/c-sharp -uwp-xaml-updating-controls-synchronousously – Dpt

+0

나는 그 질문을 보았다.하지만 원래 Step1()과 Step2() 함수를 보여 주면 비동기로 만드는 법을 보여줄 수 있다고 생각한다. – rokkerboci

-1

에서는 Windows Forms 컨트롤에 메이크업 스레드 - 안전 통화로 비동기를 사용하는 것입니다.

private async void button1_Click_1(object sender, EventArgs e) 
    { 
     button1.Text = "Work started."; 
     Task myTask = new Task(DoWork); 
     myTask.Start(); 
     await myTask; 
     button1.Text = "Work done."; 
    } 

private void DoWork() 
    { 
     this.SetMessageText("Step 1"); 
     Thread.Sleep(2000); // --> you can replace it with your actual method 
     this.SetMessageText("Step 2"); 
     Thread.Sleep(2000); // --> you can replace it with your actual method 
     this.SetMessageText(" "); 
    } 

이 대표는 TextBox 컨트롤에 텍스트 속성을 설정하기위한 비동기 호출을 할 수 있습니다 : 이것은 또한이 코드를 시도

Microsft Example에 의해 좋은 예입니다.

delegate void StringArgReturningVoidDelegate(string text); 

이 메서드는 Windows Forms 컨트롤에서 스레드로부터 안전한 호출을 만들기위한 패턴을 보여줍니다.

호출하는 스레드가 TextBox 컨트롤을 만든 스레드와 다른 경우이 메서드는 StringArgReturningVoidDelegate를 만들고 Invoke 메서드를 사용하여 비동기 적으로 호출합니다.

호출하는 스레드가 TextBox 컨트롤을 만든 스레드와 같으면 Text 속성이 직접 설정됩니다.

private void SetMessageText(string text) 
    { 
     // InvokeRequired required compares the thread ID of the 
     // calling thread to the thread ID of the creating thread. 
     // If these threads are different, it returns true. 
     if (this.label1.InvokeRequired) 
     { 
      StringArgReturningVoidDelegate d = new StringArgReturningVoidDelegate(SetMessageText); 
      this.Invoke(d, new object[] { text }); 
     } 
     else 
     { 
      this.label1.Text = text; 
     } 
    } 
+0

응답 해 주셔서 대단히 감사합니다! 제안을 구현하려고 할 때 Visual Studio에서 다음과 같이 불평하는 이유를 생각해 볼 수 있습니까? " 'TextBlock'에는 'InvokeRequired'에 대한 정의가없고 'InvokeRequired'형식의 첫 번째 인수를 허용하지 않는 정의가 없습니다. 'TextBlock'을 (를) 찾을 수 있습니다. Visual Studio에서 "this.Invoke (d, new object [] {text})"와 비슷한 불만 사항이 있습니다. 이것이 UPW의 한계입니까, 아니면 실수입니까? – Dpt

+0

TextBlock이 레이블 또는 텍스트 상자입니까? .NET Framework의 어떤 버전을 사용하고 있습니까? – behdad

+0

예제에서 "TextBlock1"개체의 클래스는 "TextBlock"입니다. 나는 당신의 질문에 대답했으면 좋겠지 만, 내가하지 않으면 알려 주시면 다시 시도 할 수 있습니다. .NET Framework의 버전을 잘 모르겠습니다. 내가 Visual Studio 2017을 설치하고 UWP 응용 프로그램을 작성하기 시작했기 때문에 나는 모른다. 버전이 아마도이 질문과 관련이 있다는 것을 이해합니다. 최대한 빠른 시일 내에 해당 질문에 대해 답변 드리겠습니다. – Dpt