WPF GUI에서 비동기 작업을 실행하고 상호 작용하는 방법
저는 WPF GUI를 가지고 있는데, 작업 기간 동안 창을 고정하지 않고 긴 작업을 시작하기 위해 버튼을 누르고 싶습니다.작업이 실행되는 동안 진행 상황에 대한 보고서를 받고, 원하는 시간에 작업을 중지할 수 있는 다른 버튼을 통합하고 싶습니다.
비동기/대기/작업을 사용하는 올바른 방법을 찾을 수 없습니다.제가 시도한 모든 것을 포함할 수는 없지만, 현재 제가 가지고 있는 것은 이것입니다.
WPF 창 클래스:
public partial class MainWindow : Window
{
readonly otherClass _burnBabyBurn = new OtherClass();
internal bool StopWorking = false;
//A button method to start the long running method
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
Task slowBurn = _burnBabyBurn.ExecuteLongProcedureAsync(this, intParam1, intParam2, intParam3);
await slowBurn;
}
//A button Method to interrupt and stop the long running method
private void StopButton_Click(object sender, RoutedEventArgs e)
{
StopWorking = true;
}
//A method to allow the worker method to call back and update the gui
internal void UpdateWindow(string message)
{
TextBox1.Text = message;
}
}
작업자 방법에 대한 클래스:
class OtherClass
{
internal Task ExecuteLongProcedureAsync(MainWindow gui, int param1, int param2, int param3)
{
var tcs = new TaskCompletionSource<int>();
//Start doing work
gui.UpdateWindow("Work Started");
While(stillWorking)
{
//Mid procedure progress report
gui.UpdateWindow("Bath water n% thrown out");
if (gui.StopTraining) return tcs.Task;
}
//Exit message
gui.UpdateWindow("Done and Done");
return tcs.Task;
}
}
이것은 실행되지만 worker 메서드가 시작되면 WPF 함수 창은 여전히 차단됩니다.
비동기/대기/작업 선언을 허용하는 방법을 알아야 합니다.
GUI 창을 막지 않는 worker 방법
worker를 .
GUI 창에서 인터럽트를 중지하고 worker 메서드를 중지합니다.
어떠한 도움말이나 조언도 감사합니다.
긴 이야기 요약:
private async void ButtonClickAsync(object sender, RoutedEventArgs e)
{
// modify UI object in UI thread
txt.Text = "started";
// run a method in another thread
await HeavyMethodAsync(txt);
// <<method execution is finished here>>
// modify UI object in UI thread
txt.Text = "done";
}
// This is a thread-safe method. You can run it in any thread
internal async Task HeavyMethodAsync(TextBox textBox)
{
while (stillWorking)
{
textBox.Dispatcher.Invoke(() =>
{
// UI operation goes inside of Invoke
textBox.Text += ".";
// Note that:
// Dispatcher.Invoke() blocks the UI thread anyway
// but without it you can't modify UI objects from another thread
});
// CPU-bound or I/O-bound operation goes outside of Invoke
// await won't block UI thread, unless it's run in a synchronous context
await Task.Delay(51);
}
}
Result:
started....................done
은신당 (1) 쓰법알 (1) 는을아합니 (1) 야다알합 (1) 법▁to야 (1) 는▁about▁write (1) ▁( (1) ▁you (1) 쓰당을async코드 (2) 다른 스레드에서 UI 작업을 실행하는 방법 및 (3) 작업을 취소하는 방법.
저는 이 게시물에서 (3) 취소 메커니즘에 참여하지 않을 것입니다.당신이 만들 수 있다는 것만 알아두십시오.CancellationTokenSource그것은 당신에게 줍니다.CancellationToken어떤 방법으로든 전달할 수 있습니다.소스를 취소하면 모든 토큰이 알 수 있습니다.
async그리고.await:
의 기본 async그리고.await
은 오직 신은오만 가능합니다.
await순식간에async방법.은 오직 신은오만 가능합니다.
await수 있는 물건 대기즉, 물물대Task,ValueTask,Task<T>,IAsyncEnumerable<T>이은 ① ② ③ ③ ④ ④ ④ ③ ③ ④ ③ ④ ③ ④ ④ ③ ④ ④ ④ ③ ④ ④ ④ ③ ④ ④ ④ ④ ③ ④ ④async및 방법await키워드를 사용하여 랩을 해제합니다.(포장 및 포장 풀기 섹션 참조)비동기 메서드 이름은 항상 다음으로 끝나야 합니다.
Async가독성을 높이고 실수를 방지합니다.// Synchronous method: TResult MethodName(params) { } // Asynchronous method: async Task<TResult> MethodNameAsync(params) { }
의 async그리고.await
그
async-await구문 기능, 컴파일러가 포기하고 제어권을 되찾기 위해 상태 기계를 사용합니다.awaited Task순식간에async방법.시간은 다음과 같습니다.
await작업을 완료하고 주 스레드를 차단하지 않고 결과를 반환합니다.Task.Run을 서다Task스레드 풀에서. (순수한 작업이 아닌 한.) 즉, 메서드가 다른 스레드에서 실행되지 않습니다.async그 자체로는 스레드 생성과 아무런 관련이 없습니다.
그렇게
를 실행할 때(예:Task.Run(action)해당 작업에 스레드를 사용합니다.그리고 당신은 그 작업을 다음과 같이 넣을 수 있습니다.async흐름을 제어하는 방법.를 .async메소드 서명에서 컴파일러에게 상태 기계를 사용하여 해당 메소드의 흐름을 제어하도록 지시합니다(이것은 스레드화를 전혀 의미하지 않습니다).그리고 옆에서await태스크에서 해당 메서드 내의 실행 흐름이 다음을 통과하지 못하도록 합니다.awaitUI 스레드를 차단하지 않는 ed 문입니다.만약 당신이 그 흐름을 발신자에게 전달하고 싶다면, 그 다음에.async가 법방 그가될수있다습니체자가 될 수 .Task따라서 동일한 패턴을 발신자에게 캐스케이드할 수 있습니다.
async Task Caller() { await Method(); }
async Task Method() { await Inner(); }
async Task Inner() { await Task.Run(action); }
이벤트 핸들러는 아래 코드와 같습니다.
가존재가능있경우의 서명에서 두 ExecuteLongProcedure 1 및 2)및 (사례 1 및 2) ①MyButton_ClickAsync와 B는 다음과 같이 설명됩니다
private async void MyButton_ClickAsync(object sender, RoutedEventArgs e)
{
//queue a task to run on threadpool
// 1. if ExecuteLongProcedure is a normal method and returns void
Task task = Task.Run(()=>
ExecuteLongProcedure(this, intParam1, intParam2, intParam3)
);
// or
// 2. if ExecuteLongProcedure is an async method and returns Task
Task task = ExecuteLongProcedureAsync(this, intParam1, intParam2, intParam3);
// either way ExecuteLongProcedure is running asynchronously here
// the method will exit if you don't wait for the Task to finish
// A. wait without blocking the main thread
// -> requires MyButton_ClickAsync to be async
await task;
// or
// B. wait and block the thread (NOT RECOMMENDED AT ALL)
// -> does not require MyButton_ClickAsync to be async
task.Wait();
}
비동기 메서드 반환 유형:
다음과 같은 선언이 있다고 가정합니다.
private async ReturnType MethodAsync() { ... }
한다면
ReturnType이라Task그리고나서await MethodAsync();아온다를 합니다.void한다면
ReturnType이라Task<T>그리고나서await MethodAsync();형식 값을 반환합니다.T이를 포장 해제라고 합니다. 다음 섹션(포장 해제 및 포장 해제)을 참조하십시오.
한다면
ReturnType이라void그럴수는 없어요.await그것- 만약 당신이 글을 쓰려고 한다면,
await MethodAsync();다음과 같은 컴파일 오류가 발생합니다.
공허함을 기다릴 수 없습니다.
- 실행하고 잊어버릴 수만 있습니다. 즉, 일반적으로 메서드를 호출합니다.
MethodAsync();그리고 나서 당신의 삶을 계속하세요. - 그
MethodAsync, 는 실은동것입다니때, 그있기문에것이그나러를 가지고 있기 입니다.async그것은 당신이 마법을 이용할 수 있게 해줄 것입니다. 즉, 당신은 글을 쓸 수 있습니다.await task실행 흐름을 제어하는 방법 내에서. - 이것은 WPF가 버튼 클릭 이벤트 핸들러를 처리하는 방법입니다. 이벤트 핸들러가 반환되기 때문입니다.
void.
- 만약 당신이 글을 쓰려고 한다면,
형식은 비기메반환형다식음같합니다아야과은의서동드▁be▁of합다니여야 합니다.
void,Task,Task<T>타입, 작과같유형은업,,▁a업형유,IAsyncEnumerable<T>또는IAsyncEnumerator<T>
포장 및 포장 해제:
포장:
async을 메드소는로값을묶다로 .Task.
예를 들어, 이 메서드는 다음을 수행합니다.Task int다음을 반환:
// async Task<int>
private async Task<int> GetOneAsync()
{
int val = await CalculateStuffAsync();
return val;
// returns an integer
}
포장 풀기:
내부에 감긴 값을 검색하거나 랩을 해제하려면 다음과 같이 하십시오.Task<>:
- 옵션: 비기옵션:
await - 옵션: 동식옵 션기:
task.Result또는task.GetAwaiter().GetResult()또는task.WaitAndUnwrapException()또는 C#의 동기 메서드에서 비동기 메서드를 호출하는 방법을 읽으십시오.
예await을 벗기다int에서 .Task:
Task<int> task = GetOneAsync();
int number = await task;
//int <- Task<int>
포장 및 포장 해제 방법:
private Task<int> GetNumber()
{
Task<int> task;
task = Task.FromResult(1); // the correct way to wrap a quasi-atomic operation, the method GetNumber is not async
task = Task.Run(() => 1); // not the best way to wrap a number
return task;
}
private async Task<int> GetNumberAsync()
{
int number = await Task.Run(GetNumber); // unwrap int from Task<int>
// bad practices:
// int number = Task.Run(GetNumber).GetAwaiter().GetResult(); // sync over async
// int number = Task.Run(GetNumber).Result; // sync over async
// int number = Task.Run(GetNumber).Wait(); // sync over async
return number; // wrap int in Task<int>
}
아직도 혼란스럽습니까?MSDN에서 비동기 반환 형식을 읽습니다.
작업 결과의 랩을 해제하려면 항상 사용 시도
await에.Result그렇지 않으면 비동기적인 이점은 없고 비동기적인 단점만 있을 것입니다."sync over async"는 "sync"입니다.
참고:
await이며 비기식 다니다와는 .task.Wait() 있습니다.하지만 그들은 둘 다 작업이 끝나기를 기다리는 같은 일을 합니다.
await이며 비기식 다니다와는 .task.Result 일을 . 입니다.하지만 둘 다 작업이 끝나기를 기다렸다가 포장을 풀고 결과를 반환하는 것과 같은 일을 합니다.
값을 랩된값가항다상사수있다용습니할음을면핑을을 할 수 .Task.FromResult(1)에 용하여새생성대신는하를레드스사를 사용합니다.Task.Run(() => 1).
Task.Run버전입니다(.및.5)의 단순 버전Task.Factory.StartNew
WPF GUI:
여기서 UI 작업을 다른 스레드에서 실행하는 방법을 설명합니다.
차단:
WPF 비동기 이벤트 처리기에 대해 알아야 할 첫 번째 사항은Dispatcher동기화 컨텍스트를 제공합니다.여기에 설명됨
바인딩된 작업(예: "CPU 바인딩된" CPU "IO 바인딩된" 작업Sleep그리고.task.Wait()의 메서드로 호출되더라도 스레드를 차단하고 소비합니다.async 키드. 지만하. 워만.await Task.Delay()상태 컴퓨터에 스레드의 실행 흐름을 중지하여 스레드가 사용하지 않도록 합니다. 즉, 스레드 리소스를 다른 곳에서 사용할 수 있습니다.
private async void Button_Click(object sender, RoutedEventArgs e)
{
Thread.Sleep(1000);//stops, blocks and consumes threadpool resources
await Task.Delay(1000);//stops without consuming threadpool resources
Task.Run(() => Thread.Sleep(1000));//does not stop but consumes threadpool resources
await Task.Run(() => Thread.Sleep(1000));//literally the WORST thing to do
}
스레드 안전:
비동기적으로 GUI)ExecuteLongProceduremethod), 안전하지 않은 객체에 대한 수정을 포함하는 모든 작업을 참조하십시오.예를 들어 WPF GUI 개체는 다음을 사용하여 호출해야 합니다.DispatcherGUI 스레드와 연결된 개체:
void UpdateWindow(string text)
{
//safe call
Dispatcher.Invoke(() =>
{
txt.Text += text;
});
}
그러나 View Model에서 속성이 변경된 콜백으로 인해 작업이 시작된 경우에는Dispatcher.Invoke콜백이 실제로 UI 스레드에서 실행되기 때문입니다.
비 UI 스레드의 컬렉션에 액세스
WPF를 사용하면 컬렉션을 생성한 스레드 이외의 스레드에서 데이터 컬렉션에 액세스하고 수정할 수 있습니다.이렇게 하면 백그라운드 스레드를 사용하여 데이터베이스와 같은 외부 소스에서 데이터를 수신하고 UI 스레드에 데이터를 표시할 수 있습니다.다른 스레드를 사용하여 컬렉션을 수정하면 사용자 인터페이스는 사용자 상호 작용에 계속 반응합니다.
INOTIFY에 의해 발생한 값 변경변경된 속성은 자동으로 디스패처에 다시 마셜됩니다.
기하세요.async메서드 자체가 메인 스레드에서 실행됩니다.따라서 이것은 유효합니다.
private async void MyButton_ClickAsync(object sender, RoutedEventArgs e)
{
txt.Text = "starting"; // UI Thread
await Task.Run(()=> ExecuteLongProcedure1());
txt.Text = "waiting"; // UI Thread
await Task.Run(()=> ExecuteLongProcedure2());
txt.Text = "finished"; // UI Thread
}
UI 스레드에서 UI 작업을 호출하는 또 다른 방법은 를 사용하는 것입니다.SynchronizationContext여기에 기술된 바와 같이 SynchronizationContext는 보더 강한추니다입화상보다 더 입니다.Dispatcher크로스 플랫폼입니다.
var uiContext = SynchronizationContext.Current;
while (stillWorking)
{
uiContext.Post(o =>
{
textBox.Text += ".";
}, null);
await Task.Delay(51);
}
패턴:
화재 및 망각 패턴:
WPF GUI 예: GUI 이벤트 처리기)는과 같습니다.Button_ClickAsync호출됩니다.
void Do()
{
// CPU-Bound or IO-Bound operations
}
async void DoAsync() // returns void
{
await Task.Run(Do);
}
void FireAndForget() // not blocks, not waits
{
DoAsync();
}
발사 및 관찰:
처리되지 않은 예외가 트리거되므로 작업 반환 방법이 더 좋습니다.
void Do()
{
// CPU-Bound or IO-Bound operations
}
async Task DoAsync() // returns Task
{
await Task.Run(Do);
}
void FireAndWait() // not blocks, not waits
{
Task.Run(DoAsync);
}
스레드 리소스를 낭비하면서 동시에 실행 및 대기:
이를 비동기 동기화라고 하며, 동기화 작업이지만 둘 이상의 스레드를 사용하여 굶주림을 유발할 수 있습니다.이것은 당신이 전화할 때 발생합니다.Wait()또는 직접 결과를 읽으려고 시도합니다.task.Result작업이 완료되기 전에
(이 패턴은 피함)
void Do()
{
// CPU-Bound or IO-Bound operations
}
async Task DoAsync() // returns Task
{
await Task.Run(Do);
}
void FireAndWait() // blocks, waits and uses 2 more threads. Yikes!
{
var task = Task.Run(DoAsync);
task.Wait();
}
그게 다야?
아요에 대해 배울 이 더 . 더 많은 것들을 배울 것이 있습니다.async그것의 맥락과 그것의 연속.이 블로그 게시물은 특히 추천합니다.
작업이 스레드를 사용합니까?확실합니까?
꼭 그렇다고 할 수는 없죠.이 답변을 읽고 의 실제 얼굴에 대해 자세히 알아보십시오.async.
Stephen Cleary가 설명했습니다.async-await더할 나위 없이그는 또한 자신의 다른 블로그 게시물에서 스레드가 관련되지 않은 경우에 대해 설명합니다.
더 읽기
비동기식, 병렬 및 동시 실행의 차이를 알아야 합니다.
또한 간단한 비동기 파일 작성기를 읽어 동시에 사용해야 하는 위치를 알 수 있습니다.
동시 네임스페이스 조사
궁극적으로, 이 전자책을 읽어보세요: Patterns_of_Parallel_Programming_CS 샤프
의 TaskCompletionSource<T>틀렸습니다. TaskCompletionSource<T>비동기 작업을 위한 TAP 호환 래퍼를 만드는 방법입니다.당신의ExecuteLongProcedureAsync메서드, 샘플 코드는 모두 CPU 바인딩되어 있습니다(즉, 본질적으로 동기식이지 비동기식이 아닙니다).
그래서 글을 쓰는 것이 훨씬 더 자연스럽습니다.ExecuteLongProcedure동시적인 방법으로또한 표준 동작, 특히 진행률 업데이트 및 취소에 사용하는 표준 유형을 사용하는 것이 좋습니다.
internal void ExecuteLongProcedure(int param1, int param2, int param3,
CancellationToken cancellationToken, IProgress<string> progress)
{
//Start doing work
if (progress != null)
progress.Report("Work Started");
while (true)
{
//Mid procedure progress report
if (progress != null)
progress.Report("Bath water n% thrown out");
cancellationToken.ThrowIfCancellationRequested();
}
//Exit message
if (progress != null)
progress.Report("Done and Done");
}
이제 적절한 규칙을 사용하는 재사용 가능한 유형(GUI 종속성 없음)이 추가되었습니다.다음과 같이 사용할 수 있습니다.
public partial class MainWindow : Window
{
readonly otherClass _burnBabyBurn = new OtherClass();
CancellationTokenSource _stopWorkingCts = new CancellationTokenSource();
//A button method to start the long running method
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
var progress = new Progress<string>(data => UpdateWindow(data));
try
{
await Task.Run(() => _burnBabyBurn.ExecuteLongProcedure(intParam1, intParam2, intParam3,
_stopWorkingCts.Token, progress));
}
catch (OperationCanceledException)
{
// TODO: update the GUI to indicate the method was canceled.
}
}
//A button Method to interrupt and stop the long running method
private void StopButton_Click(object sender, RoutedEventArgs e)
{
_stopWorkingCts.Cancel();
}
//A method to allow the worker method to call back and update the gui
void UpdateWindow(string message)
{
TextBox1.Text = message;
}
}
에 다은다음사예입다니용을 사용한 .async/await,IProgress<T>그리고.CancellationTokenSource이것들은 현대의 C# 및 입니다.사용해야 하는 NetFramework 언어 기능입니다.다른 해결책들은 제 눈에 피를 좀 흘리게 합니다.
코드 기능
- 10초 동안 100까지 카운트
- 진행률 표시줄에 진행률 표시
- UI를 차단하지 않고 장시간 실행되는 작업('대기' 기간)
- 사용자 트리거 취소
- 증분 진행률 업데이트
- 사후작업현황보고서
뷰
<Window x:Class="ProgressExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" SizeToContent="WidthAndHeight" Height="93.258" Width="316.945">
<StackPanel>
<Button x:Name="Button_Start" Click="Button_Click">Start</Button>
<ProgressBar x:Name="ProgressBar_Progress" Height="20" Maximum="100"/>
<Button x:Name="Button_Cancel" IsEnabled="False" Click="Button_Cancel_Click">Cancel</Button>
</StackPanel>
</Window>
코드
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private CancellationTokenSource currentCancellationSource;
public MainWindow()
{
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
// Enable/disabled buttons so that only one counting task runs at a time.
this.Button_Start.IsEnabled = false;
this.Button_Cancel.IsEnabled = true;
try
{
// Set up the progress event handler - this instance automatically invokes to the UI for UI updates
// this.ProgressBar_Progress is the progress bar control
IProgress<int> progress = new Progress<int>(count => this.ProgressBar_Progress.Value = count);
currentCancellationSource = new CancellationTokenSource();
await CountToOneHundredAsync(progress, this.currentCancellationSource.Token);
// Operation was successful. Let the user know!
MessageBox.Show("Done counting!");
}
catch (OperationCanceledException)
{
// Operation was cancelled. Let the user know!
MessageBox.Show("Operation cancelled.");
}
finally
{
// Reset controls in a finally block so that they ALWAYS go
// back to the correct state once the counting ends,
// regardless of any exceptions
this.Button_Start.IsEnabled = true;
this.Button_Cancel.IsEnabled = false;
this.ProgressBar_Progress.Value = 0;
// Dispose of the cancellation source as it is no longer needed
this.currentCancellationSource.Dispose();
this.currentCancellationSource = null;
}
}
private async Task CountToOneHundredAsync(IProgress<int> progress, CancellationToken cancellationToken)
{
for (int i = 1; i <= 100; i++)
{
// This is where the 'work' is performed.
// Feel free to swap out Task.Delay for your own Task-returning code!
// You can even await many tasks here
// ConfigureAwait(false) tells the task that we dont need to come back to the UI after awaiting
// This is a good read on the subject - https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
// If cancelled, an exception will be thrown by the call the task.Delay
// and will bubble up to the calling method because we used await!
// Report progress with the current number
progress.Report(i);
}
}
private void Button_Cancel_Click(object sender, RoutedEventArgs e)
{
// Cancel the cancellation token
this.currentCancellationSource.Cancel();
}
}
이것은 Bijan이 여기서 가장 인기 있는 대답의 단순화된 버전입니다.저는 스택 오버플로에서 제공하는 멋진 포맷을 사용하여 문제를 생각할 수 있도록 Bijan의 답변을 단순화했습니다.
Bijan의 게시물을 주의 깊게 읽고 편집함으로써 저는 마침내 다음을 이해했습니다.비동기 메서드가 완료될 때까지 기다리는 방법은 무엇입니까?
저의 경우, 그 다른 게시물에 대한 선택된 답변은 궁극적으로 제가 문제를 해결하도록 이끈 것입니다.
"피회"를 피합니다async void를 반환하도록 .Task에 void그러면 할 수 있습니다.await."
Bijan의 (훌륭한) 답변에 대한 저의 단순화된 버전은 다음과 같습니다.
비동기를 사용하여 작업을 시작하고 대기합니다.
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
// if ExecuteLongProcedureAsync has a return value
var returnValue = await Task.Run(()=>
ExecuteLongProcedureAsync(this, intParam1, intParam2, intParam3));
}
비동기적으로 실행하는 방법은 다음과 같습니다.
bool stillWorking = true;
internal void ExecuteLongProcedureAsync(MainWindow gui, int param1, int param2, int param3)
{
//Start doing work
gui.UpdateWindow("Work Started");
while (stillWorking)
{
//put a dot in the window showing the progress
gui.UpdateWindow(".");
//the following line blocks main thread unless
//ExecuteLongProcedureAsync is called with await keyword
System.Threading.Thread.Sleep(50);
}
gui.UpdateWindow("Done and Done");
}
gui에서 속성을 포함하는 작업을 호출합니다.
void UpdateWindow(string text)
{
//safe call
Dispatcher.Invoke(() =>
{
txt.Text += text;
});
}
아니면.
void UpdateWindow(string text)
{
//simply
txt.Text += text;
}
종료 의견) 대부분의 경우 두 가지 방법이 있습니다.
첫 번째 방법(
Button_Click_3는 두 하고 )을 .async컴파일러에 해당 메서드에 대해 스레드화를 활성화하도록 지시하는 수식자입니다.Thread.Sleep순식간에async메서드는 주 스레드를 차단하지만 작업 대기는 차단하지 않습니다.- 은 스두에드레서중스실다니지의됩행레드의 현재 스레드(두 번째 스레드)에서 중지됩니다
await작업이 완료될 때까지 문을 표시합니다. - 사용할 수 없습니다.
awaitasync방법
두 번째 방법(
ExecuteLongProcedureAsync인 )을 반환합니다.Task<original return type>을 추가하여 비동기적으로 처리하도록 할 수await그 전에- 이 메서드의 모든 항목이 비동기식으로 실행되었습니다.
중요:
리에로는 중요한 문제를 꺼냈습니다.요소를 ViewModel 속성에 바인딩하는 경우 속성 변경 콜백이 UI 스레드에서 실행됩니다.그래서 사용할 필요가 없습니다.Dispatcher.InvokeINOTIFY에 의해 발생한 값 변경변경된 속성은 자동으로 디스패처에 다시 마셜됩니다.
언급URL : https://stackoverflow.com/questions/27089263/how-to-run-and-interact-with-an-async-task-from-a-wpf-gui
'programing' 카테고리의 다른 글
| Python 유형 힌트: 입력.매핑 대 입력.딕트 (0) | 2023.05.04 |
|---|---|
| 브라우저에 잘못된 파일 저장소 URL이 표시됨머리글 값 (0) | 2023.04.29 |
| Ubuntu에 설치된 MongoDB 버전 (0) | 2023.04.29 |
| 실행 중인 SQL Server 포트를 찾는 방법은 무엇입니까? (0) | 2023.04.29 |
| C#에서 Excel 열 문자를 가장 빠르게 생성하는 기능 (0) | 2023.04.29 |