2014-01-07 4 views
1

BeginInvoke를 올바르게 사용하는 방법을 배우고 있습니다. 필자는 콘솔 앱에 작은 테스트를 작성하여 BeginInvoke를 사용하여 제목이 표시된 100x100 창을 만들기 위해 함수를 호출하는 방법을 사용합니다. 나는 비참하게 실패하고있다. 여기에 내가 가지고있는 것이 있는데, 이것이 아마도 스레드 (내 강점이 아닌)에 대한 이해가 부족한 것임을 알지만, 멈추지 않고 창을 팝업하지 않습니다. 키 누르기를 기다리는 Main의 readline에서 끝납니다. 실행은 ThreadUITest에서 시작됩니다.Dispatcher.BeginInvoke 올바른 사용법?

static void ThreadUITest() 
{ 
    ThreadStart starter = new ThreadStart(threadFunc1); 
    Thread test = new Thread(starter); 
    test.IsBackground = true; 
    test.SetApartmentState(ApartmentState.STA); 
    test.Start(); 
} 

static void threadFunc1() 
{ 
    dispatcher = Dispatcher.CurrentDispatcher; //Statically declared earlier 
    ThreadStart starter = new ThreadStart(threadFunc2); 
    Thread test = new Thread(starter); 
    test.IsBackground = true; 
    test.Start(); 
} 

static void threadFunc2() 
{ 
    Action method = Draw; 
    Console.WriteLine("I'm here!"); 
    //dispatcher.BeginInvoke((Action)(() => {Draw();}),DispatcherPriority.Render, null); 
    dispatcher.BeginInvoke(method, DispatcherPriority.Send, null); 
} 

static void Draw() 
{ 
    Window win = new Window(); 
    win.Height = 100; 
    win.Width = 100; 
    win.Title = "A Window!"; 
    win.Show(); 
} 

도움 주셔서 감사합니다.

+0

'dispatcher.Invoke'를 사용할 때 작동합니까? –

+0

아니요, 그렇지 않습니다. –

답변

1

threadFunc1 끝에 Dispatcher.Run()으로 전화 해보세요.

+0

확인. 그랬어. 스레드와 함께 새로운 Dispatcher를 만들지 않습니까? 그렇다면 어리석은 일이 왜 그냥 돌아 가지 않을까요? –

+1

@AaronMarcus 스레드를 만들면 메시지 루프가 자동으로 생성되지 않습니다. 대부분의 스레드에는 메시지 루프가 없습니다. 즉, 프로그램에는이 한 줄을 추가하는 것만으로는 해결되지 않는 훨씬 더 큰 디자인 문제가 있습니다. – Servy

+0

저는 논리가 생성자와 속성이 차단해서는 안된다고 생각합니다. 그래서 Dispatcher.CurrentDispatcher는 디스패처를 생성 할 때 루프를 시작하지 않습니다. 하지만 네, Invoke가 시작하지 않는 것이 이상하게 보입니다. –

2

당신은 왜 그것을 해결 않는 threadFunc1

// statically declared earlier, although you don't need to keep a reference to it as 
// WPF will keep it in Application.Current 
application = new Application(); 
application.Run(); // thread1 is now our "UI" thread 

의 맨 아래에 다음을 추가해야합니까?

Dispatcher 개체는 스레드가 (BeginInvoke 또는 Invoke을 통해) 작업을 수행하도록하는 인터페이스를 제공합니다.
스레드가 "작동"메시지를 처리 ​​할 수 ​​있으려면 스레드가 일종의 이벤트 루프를 실행하고 있어야합니다.이 루프는 앉아서 다음 메시지 처리를 기다립니다. 그것은 아무 것도 처리 할 수 ​​없을 것이고, 그것은 막혔을 것입니다.

thread1에서 Dispatcher.CurrentDispatcher을 호출하면 해당 스레드에 새 Dispatcher가 만들어집니다. 이미 존재하지 않으면 [1] - 스레드에 메시지를 게시 할 우리 인터페이스를 제공합니다.
무엇이 dispatcher.BeginInvoke은 스레드가 메시지 루프를 아직 실행하고 있지 않지만 해당 스레드의 메시지 큐에 항목을 추가합니다. 메시지를 대기열에 넣을 수는 있지만 메시지를 가져 와서 실행하지 않습니다. 따라서 아무 일도 일어나지 않습니다.

그래서 우리는 그 스레드가 메시지 루프를 시작하도록해야합니다.
Application.Run() 메서드는 정확히 수행하는 WPF 프레임 워크 메서드입니다. Application.Run 메서드는 결코 반환하지 않습니다 (사용자가 Application.Shutdown을 호출 할 때까지) 메시지 처리를 시작하여 메시지 처리를 시작합니다. 스레드를 "인계"한다고 생각하는 것이 유용하다는 것을 알았습니다. 그것은 BeginInvoke 방법을 얻을,이 경우 (이 말 있잖아 -이 변경, dispatcher.BeginInvoke를 호출 thread2func이 Application.Run 내부 메시지 루프 코드가 "오 보면, 메시지, 나는 그것을 처리 할 것"간다와 지금

) 당신의 Draw 기능을 실행하고 모두가 잘


참고 : 그냥이 내부적으로 (Application.Run가하는 응용 프로그램 객체를 생성하지 않고 해당 스레드의 메시지 루프를 시작 Dispatcher.Run를 호출 할 수 있습니다 Ark-kun's answer 당으로) . 일반적으로 내가 그 더 "보통"의대로 더 좋은,하지만 응용 프로그램 개체를 만들 발견하고 예상 할 수 있습니다 나중에 쓸 수있는 몇 가지 다른 코드는 응용 프로그램 개체가 존재하는


[1] 참고로,이 이유 Dispatcher.CurrentDispatcher으로 전화하는 것은 위험하므로 피해야합니다. 기존 UI 스레드에서 Dispatcher.CurrentDispatcher으로 전화하면 올바른 발송자에 대한 참조가 반환됩니다.
실수로 다른 스레드에서 호출 한 경우 논리적으로 기존 디스패처에 대한 참조가 반환된다고 생각할 수 있습니다.그러나 아니요 - 대신 두 번째 디스패처를 만들고 다른 스레드를 가리키며 다른 스레드는 메시지 루프를 실행하지 않으며 다시 멈추게됩니다. 처음으로 제외하고 결코 Dispatcher.CurrentDispatcher으로 전화하지 말 것을 제안합니다.

응용 프로그램이 실행되고 나면 모든 WPF 객체 (창, 버튼 등)에 모두 Dispatcher 속성이 있으므로 어쨌든 올바른 발송자를 얻을 수 있으므로 일반적으로 응용 프로그램을 실행해야합니다.

+0

'Dispatcher '는 추상 이벤트 처리에 관한 것입니다. WPF에만 국한된 것이 아니며'WindowsBase.dll'에 있습니다. 'Application'은'PresentationFramework.dll'에 있으며'Windows','Resources'와 네비게이션에 관한 것입니다. 상황에 따라, 본격적인'Application' 대신에 최소한의 Dispatcher를 선호 할 수도 있습니다. –

+0

BeginInvoke를 제대로 사용하고 있는지 확인하기위한 테스트 프레임 워크 였기 때문에 상황이 조금 복잡해졌습니다. 그래서 나는 완전히 부풀린 응용 프로그램에 신경 쓰지 않았습니다. 추가 정보를 보내 주셔서 감사합니다! –