programing

Dispatcher를 사용하여 WPF 컨트롤을 비메인 스레드에서 변경합니다.호출하다

oldcodes 2023. 4. 9. 22:21
반응형

Dispatcher를 사용하여 WPF 컨트롤을 비메인 스레드에서 변경합니다.호출하다

저는 최근에 WPF에서 프로그래밍을 시작했는데 다음과 같은 문제에 부딪혔습니다.어떻게 사용하는지 모르겠어요.Dispatcher.Invoke()방법.스레드화 경험이 있으며, 간단한 Windows Forms 프로그램을 몇 개 만들었습니다.

Control.CheckForIllegalCrossThreadCalls = false;

네, 그게 좀 재미없다는 건 알지만 이것들은 단순한 감시 어플리케이션이었습니다.

이 시점에서 백그라운드에서 데이터를 취득하는 WPF 애플리케이션을 작성하고 새로운 스레드를 시작하여 (웹 서버에서) 데이터를 취득하는 콜을 발신하고 WPF 폼에 표시합니다.문제는 이 스레드에서 컨트롤이 안 된다는 거예요.라벨이나 뭐 그런 것도 없어요.이 문제를 어떻게 해결할 수 있을까요?

답변 코멘트:
@Jalfp:
그럼 데이터를 얻을 때 '새로운 디딤판'에 디스패처 방식을 사용하는 건가요?또는 백그라운드워커에게 데이터를 가져와 필드에 삽입하고 이 필드가 채워질 때까지 대기하는 새로운 스레드를 시작하여 디스패처를 호출하여 취득한 데이터를 컨트롤에 표시해야 합니까?

우선 Dispatcher는 긴 차단 작업(WebServer에서 데이터 가져오기 등)을 실행하도록 설계되지 않았습니다.UI 스레드에서 실행되는 작업(예: 진행률 표시줄 값 업데이트)을 실행하려는 경우 디스패처를 사용할 수 있습니다.

백그라운드워커에서 데이터를 취득하여 ReportProgress 메서드를 사용하여 UI 스레드의 변경을 전파할 수 있습니다.

Dispatcher를 직접 사용해야 하는 경우에는 다음과 같이 매우 간단합니다.

Application.Current.Dispatcher.BeginInvoke(
  DispatcherPriority.Background,
  new Action(() => this.progressBar.Value = 50));

japf가 정답을 맞췄습니다.만약 당신이 여러 줄의 동작을 보고 있다면 다음과 같이 쓸 수 있습니다.

Application.Current.Dispatcher.BeginInvoke(
  DispatcherPriority.Background,
  new Action(() => { 
    this.progressBar.Value = 50;
  }));

성능에 대해 알고 싶은 다른 사용자를 위한 정보:

고성능을 위해 코드를 작성해야 할 경우 CheckAccess 플래그를 사용하여 먼저 호출이 필요한지 여부를 확인할 수 있습니다.

if(Application.Current.Dispatcher.CheckAccess())
{
    this.progressBar.Value = 50;
}
else
{
    Application.Current.Dispatcher.BeginInvoke(
      DispatcherPriority.Background,
      new Action(() => { 
        this.progressBar.Value = 50;
      }));
}

CheckAccess() 메서드는 Visual Studio 2015에서 숨겨져 있으므로 인텔리센스가 이를 표시할 것으로 예상하지 않고 작성하십시오.Check Access에는 퍼포먼스에 대한 오버헤드가 있습니다(몇 나노초만에 오버헤드가 발생합니다).어떤 대가를 치르더라도 호출을 실행하는 데 필요한 마이크로초를 절약하고 싶을 때만 이 방법이 더 좋습니다.또한 호출 메서드가 UI 스레드에 있는지 확인할 때 두 개의 메서드를 만드는 옵션이 항상 있습니다(호출이 있는 경우 및 없는 경우).발송 담당자의 이런 면을 봐야 할 경우는 극히 드문 경우입니다.

스레드가 실행 중일 때 현재 스레드에 의해 차단된 기본 UI 스레드를 실행하려면 다음을 사용하십시오.

현재 스레드:

Dispatcher.CurrentDispatcher.Invoke(MethodName,
    new object[] { parameter1, parameter2 }); // if passing 2 parameters to method.

기본 UI 스레드:

Application.Current.Dispatcher.BeginInvoke(
    DispatcherPriority.Background, new Action(() => MethodName(parameter)));

위의 @japf 답변은 정상적으로 동작하고 있으며, 제 경우 CEF 브라우저가 페이지 로드를 마치면 마우스 커서를 Spining Wheel에서 일반 Arrow로 되돌리고 싶었습니다.누군가에게 도움이 될 수 있는 경우, 코드는 다음과 같습니다.

private void Browser_LoadingStateChanged(object sender, CefSharp.LoadingStateChangedEventArgs e) {
   if (!e.IsLoading) {
      // set the cursor back to arrow
      Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,
         new Action(() => Mouse.OverrideCursor = Cursors.Arrow));
   }
}

언급URL : https://stackoverflow.com/questions/1644079/change-wpf-controls-from-a-non-main-thread-using-dispatcher-invoke

반응형