2014-12-04 2 views
0

wpf 응용 프로그램이 통신 파이프를 통해 기존 응용 프로그램에 연결됩니다. WPF 응용 프로그램을 사용하면 인터페이스의 단추를 사용하여지도에서 위치를 그릴 수 있습니다. 따라서 사용자가 WPF 응용 프로그램 사용자 인터페이스에서 버튼을 클릭하면 파이프 메시지가 레거시 응용 프로그램으로 전송되어 사용자가지도에 위치를 표시 할 수 있습니다. 사용자가 마우스를 사용하여지도에 그림을 그릴 때 좌표는 양방향 통신 파이프를 사용하여 wpf 응용 프로그램으로 다시 전송됩니다. 내 wpf 응용 프로그램이 좌표를 받으면 그에 따라 워크 플로를 처리하고 수행해야합니다. 일부 오류가 표시 될 수 있으므로 응용 프로그램에서 오류 메시지를 표시해야 할 수도 있습니다. 또는 경우에 따라 응용 프로그램 주 스레드에서 만든 모음을 지울 수도 있습니다. 따라서 좌표를받을 때 실행되는 코드의 전체 부분이 있습니다.메인 스레드의 wpf 응용 프로그램에서 호출 처리

좌표를 받으면 메시지 상자 표시 등과 같은 사용자 작업을 수행 할 수 있도록 내 WPF 응용 프로그램을 주 스레드로 다시 가져올 수 있습니까?

지금 "컬렉션이 다른 스레드에서 생성되었습니다"와 같은 예외가 발생합니다.

은 내가 메인 스레드에서 메시지 또는 명확한 컬렉션

Application.Current.Dispatcher.Invoke((Action)(() => { PointsCollection.Clear(); })); 

Application.Current.Dispatcher.Invoke((Action)(() => { MessageBox.Show("Error"); })); 

하지만, 단위 테스트에서이 실 거예요 작업을 표시하려면이 코드를 사용할 수 있으며, 내가 장소를 많이에서이 작업을 수행해야합니다 알고 있습니다. 거기에 더 좋은 방법이 있습니까?

public void PipeClientMessageReceived(int type, string message) 
{ 
    var command = (PipeCommand)type; 
    switch (command) 
    { 
     case PipeCommand.Points: 
      { 
       string[] tokens = message.Split(':'); 
       var x = Convert.ToDouble(tokens[0]); 
       var y = Convert.ToDouble(tokens[1]); 
       SetSlotCoordinates(new Point2D(x, y)); 
      } 
      break; 
    } 
} 

SetSlotCoordinates 방법은 실제로 좌표를 처리 할 수있는 모든 작업을 수행합니다. Application.Current.Dispatcher에서이 호출을 시도했지만 성공하지 못했습니다.

Application.Current.Dispatcher.Invoke((Action)(() => { SetSlotCoordinates(new Point2D(x, y)); })); 

답변

1

불행히도, 그 질문은 명확하지 않습니다. 단위 테스트에 어떤 문제가있어 Dispatcher.Invoke()을 사용할 수 없습니까? SetSlotCoordinates()으로 전화를 걸어 Dispatcer.Invoke()을 사용해 보았을 때, 어떤 방법으로 "성공하지 못했습니까?" 당신이 할 수 있다면 당신은. 그러나, 나는 새로운 async/await 패턴을 사용하는 것이 좋습니다에 대한

기본적으로, Dispatcher.Invoke() (또는 비동기 형제의 사용은, Dispatcher.BeginInvoke()가 작업을 수행해야합니다.

을 완전한없이 코드 예제, 그것은 당신에게 정확한 코드를 제공하는 것은 불가능하지만은 다음과 같이 보일 것이다.

async Task ReceiveFromPipe(Stream pipeStream, int bufferSize) 
{ 
    byte[] buffer = new byte[bufferSize]; 
    int byteCount; 

    while ((byteCount = await pipeStream.ReadAsync(buffer, 0, buffer.Length)) > 0)  
    { 
     int type; 
     string message; 

     if (TryCompleteMessage(buffer, byteCount, out type, out message)) 
     { 
      PipeClientMessageReceived(type, message); 
     } 
    } 
} 

이 기술을 사용하고 ReceiveFromPipe() 방법은 UI 스레드에서 호출된다고 가정하면, 이미에있을 것이다 읽은 UI 스레드 파이프에서 완료, 다른 모든 "그냥 일하는"만들기.

참고 : 전체 메시지를 수신 할 때까지 들어오는 데이터의 버퍼를 얼마나 정확하게 유지하는지 등의 세부 정보를 살펴 보았습니다 ... 가상의 TryCompleteMessage() 방법으로 캡슐화되었다고 가정했습니다. 위의 그림은 설명의 목적을위한 것이며, 당연히 자신 만의 특정 코드에 적응해야합니다.

또한 백그라운드 스레드에서 처리하는 것이 더 효과적이라는 것을 알 수 있습니다.이 경우 실제 수신 및 처리를 별도의 async 메소드에 넣습니다. 이 경우 해당 메서드는 여전히 ReadAsync()을 호출하지만 반환 값으로 ConfigureAwait(false)을 호출 할 수 있으므로 해당 async 메서드가 반환 될 때까지 UI 스레드로 다시 전환되지 않았습니다. 예를 들어 위의 예에서

async Task ReceiveFromPipe(Stream pipeStream, int bufferSize) 
{ 
    Action action; 

    while ((action = await ReceivePoint2D(pipeStream, bufferSize)) != null) 
    { 
     action(); 
    } 
} 

async Task<Action> ReceivePoint2D(Stream pipeStream, int bufferSize) 
{ 
    byte[] buffer = new byte[bufferSize]; 
    int byteCount; 

    while ((byteCount = await pipeStream 
     .ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) > 0)  
    { 
     int type; 
     string message; 

     if (TryCompleteMessage(buffer, byteCount, out type, out message)) 
     { 
      return PipeClientMessageReceived(type, message); 
     } 
    } 

    return null; 
} 

public Action PipeClientMessageReceived(int type, string message) 
{ 
    var command = (PipeCommand)type; 
    switch (command) 
    { 
     case PipeCommand.Points: 
      { 
       string[] tokens = message.Split(':'); 
       var x = Convert.ToDouble(tokens[0]); 
       var y = Convert.ToDouble(tokens[1]); 
       return() => SetSlotCoordinates(new Point2D(x, y)); 
      } 
      break; 
    } 
} 

, 비동기 코드는 SetSlotCoordinates()에 대한 호출을 제외한 모든 작업을 수행합니다. 이를 위해 Action 대리자에서 호출을 래핑하여 UI 스레드로 반환하고 UI 스레드는이를 호출 할 수 있습니다. 물론 Action 대리자를 반환 할 필요는 없습니다. 그것은 이미 가지고있는 코드를 적용하기 위해 가장 편리한 방법이었습니다. 어떤 값이나 객체도 반환 할 수 있으며 UI 스레드가 적절하게 처리하도록 할 수 있습니다.

마지막으로, 위의 모든 내용과 관련하여 코드의 어디에도 UI 스레드에 대한 명시 적 종속성이 없습니다. 단위 테스트와 관련하여 어떤 문제가 있는지 확신 할 수 없지만 위의 내용은 Dispatcher이 없거나 어떤 이유로 사용하지 않는 단위 테스트 시나리오에 훨씬 쉽게 적용되어야합니다.

Dispatcher을 명시 적으로 사용하려면 정확하게 작동하지 않는 것에 대해보다 구체적으로 설명해야합니다.

관련 문제