다음을 통해 공유


메신저

인터페이스는 IMessenger 서로 다른 개체 간에 메시지를 교환하는 데 사용할 수 있는 형식에 대한 계약입니다. 참조되는 형식에 대한 강력한 참조를 유지하지 않고도 애플리케이션의 여러 모듈을 분리하는 데 유용할 수 있습니다. 토큰으로 고유하게 식별되는 특정 채널로 메시지를 보내고 애플리케이션의 다른 섹션에 다른 메신저를 가질 수도 있습니다. MVVM 도구 키트는 기본적으로 WeakReferenceMessenger 두 가지 구현을 제공합니다. 즉 StrongReferenceMessenger, 전자는 내부적으로 약한 참조를 사용하여 받는 사람에게 자동 메모리 관리를 제공하는 반면, 후자는 강력한 참조를 사용하며 개발자가 더 이상 필요하지 않을 때 받는 사람을 수동으로 구독 취소해야 합니다(메시지 처리기를 등록 취소하는 방법에 대한 자세한 내용은 아래에서 찾을 수 있음).

플랫폼 API: , ,WeakReferenceMessenger, IRecipient<TMessage>StrongReferenceMessenger, MessageHandler<TRecipient, TMessage>ObservableRecipient, RequestMessage<T>, AsyncRequestMessage<T>CollectionRequestMessage<T>AsyncCollectionRequestMessage<T>.IMessenger

작동 방식

구현되는 IMessenger 형식은 상대 메시지 처리기를 사용하여 받는 사람(메시지 수신자)과 등록된 메시지 형식 간의 링크를 유지 관리합니다. 모든 개체는 해당 형식의 메시지를 보내는 데 인스턴스를 사용할 때마다 IMessenger 호출되는 메시지 처리기를 사용하여 지정된 메시지 형식의 받는 사람으로 등록할 수 있습니다. 또한 여러 모듈이 충돌을 일으키지 않고 동일한 유형의 메시지를 교환할 수 있도록 특정 통신 채널(각각 고유 토큰으로 식별됨)을 통해 메시지를 보낼 수도 있습니다. 토큰 없이 보낸 메시지는 기본 공유 채널을 사용합니다.

인터페이스를 통해 IRecipient<TMessage> 또는 메시지 처리기 역할을 하는 대리자를 사용하여 MessageHandler<TRecipient, TMessage> 메시지 등록을 수행하는 두 가지 방법이 있습니다. 첫 번째에서는 모든 처리기를 확장에 대한 단일 호출로 등록할 RegisterAll 수 있습니다. 이 호출은 선언된 모든 메시지 처리기의 받는 사람을 자동으로 등록하는 반면, 후자는 유연성이 더 필요하거나 간단한 람다 식을 메시지 처리기로 사용하려는 경우에 유용합니다.

StrongReferenceMessenger 또한 WeakReferenceMessenger 패키지에 Default 기본 제공된 스레드로부터 안전한 구현을 제공하는 속성을 노출합니다. 필요한 경우 여러 메신저 인스턴스를 만들 수도 있습니다. 예를 들어 다른 메신저 인스턴스가 DI 서비스 공급자와 함께 앱의 다른 모듈에 삽입되는 경우(예: 동일한 프로세스에서 실행되는 여러 창)

참고 항목

형식은 WeakReferenceMessenger 사용하기가 더 간단하고 라이브러리에서 MvvmLight 메신저 형식의 동작과 일치하므로 MVVM 도구 키트의 ObservableRecipient 형식에서 사용되는 기본 형식입니다. StrongReferenceType 인스턴스를 해당 클래스의 생성자에 전달하여 계속 사용할 수 있습니다.

메시지 송수신

다음을 고려하십시오.

// Create a message
public class LoggedInUserChangedMessage : ValueChangedMessage<User>
{
    public LoggedInUserChangedMessage(User user) : base(user)
    {        
    }
}

// Register a message in some module
WeakReferenceMessenger.Default.Register<LoggedInUserChangedMessage>(this, (r, m) =>
{
    // Handle the message here, with r being the recipient and m being the
    // input message. Using the recipient passed as input makes it so that
    // the lambda expression doesn't capture "this", improving performance.
});

// Send a message from some other module
WeakReferenceMessenger.Default.Send(new LoggedInUserChangedMessage(user));

현재 기록된 사용자의 사용자 이름 및 프로필 이미지가 있는 헤더, 대화 목록이 있는 패널 및 현재 대화의 메시지가 있는 다른 패널(선택한 경우)을 표시하는 간단한 메시징 애플리케이션에서 이 메시지 유형이 사용되고 있다고 상상해 보겠습니다. 이러한 세 섹션은 각각 및 ConversationsListViewModel ConversationViewModel 형식에서 HeaderViewModel지원한다고 가정해 보겠습니다. 이 시나리오 LoggedInUserChangedMessage 에서는 로그인 작업이 완료된 후 메시지가 전송 HeaderViewModel 될 수 있으며, 다른 두 viewmodel 모두 해당 처리기를 등록할 수 있습니다. 예를 들어 새 ConversationsListViewModel 사용자에 대한 대화 목록을 로드하고 ConversationViewModel 현재 대화가 있는 경우 현재 대화만 닫습니다.

인스턴스는 IMessenger 등록된 모든 받는 사람에게 메시지를 배달합니다. 받는 사람은 특정 유형의 메시지를 구독할 수 있습니다. 상속된 메시지 형식은 MVVM 도구 키트에서 제공하는 기본 IMessenger 구현에 등록되지 않습니다.

받는 사람이 더 이상 필요하지 않은 경우 메시지 수신을 중지할 수 있도록 등록을 취소해야 합니다. 메시지 유형, 등록 토큰 또는 받는 사람별로 등록을 취소할 수 있습니다.

// Unregisters the recipient from a message type
WeakReferenceMessenger.Default.Unregister<LoggedInUserChangedMessage>(this);

// Unregisters the recipient from a message type in a specified channel
WeakReferenceMessenger.Default.Unregister<LoggedInUserChangedMessage, int>(this, 42);

// Unregister the recipient from all messages, across all channels
WeakReferenceMessenger.Default.UnregisterAll(this);

Warning

앞에서 설명한 것처럼 약한 참조를 사용하여 받는 사람을 추적하기 때문에 형식을 사용할 WeakReferenceMessenger 때는 반드시 필요하지 않습니다. 즉, 사용되지 않는 받는 사람은 여전히 활성 메시지 처리기가 있더라도 가비지 수집에 적합합니다. 하지만 구독을 취소하여 성능을 향상시키는 것은 여전히 좋은 방법입니다. 반면에 구현에서는 StrongReferenceMessenger 강력한 참조를 사용하여 등록된 받는 사람을 추적합니다. 이 작업은 성능상의 이유로 수행되며 메모리 누수 방지를 위해 등록된 각 수신자를 수동으로 등록 취소해야 합니다. 즉, 받는 사람이 등록된 한 사용 StrongReferenceMessenger 중인 인스턴스는 활성 참조를 유지하므로 가비지 수집기가 해당 인스턴스를 수집할 수 없게 됩니다. 수동으로 처리하거나 상속 ObservableRecipient할 수 있습니다. 기본적으로 받는 사람이 비활성화될 때 받는 사람에 대한 모든 메시지 등록을 자동으로 제거합니다(이에 대한 자세한 내용은 문서 ObservableRecipient 참조).

인터페이스를 사용하여 IRecipient<TMessage> 메시지 처리기를 등록할 수도 있습니다. 이 경우 각 수신자는 지정된 메시지 형식에 대한 인터페이스를 구현하고 다음과 같이 메시지를 받을 때 호출할 메서드를 제공해야 Receive(TMessage) 합니다.

// Create a message
public class MyRecipient : IRecipient<LoggedInUserChangedMessage>
{
    public void Receive(LoggedInUserChangedMessage message)
    {
        // Handle the message here...   
    }
}

// Register that specific message...
WeakReferenceMessenger.Default.Register<LoggedInUserChangedMessage>(this);

// ...or alternatively, register all declared handlers
WeakReferenceMessenger.Default.RegisterAll(this);

// Send a message from some other module
WeakReferenceMessenger.Default.Send(new LoggedInUserChangedMessage(user));

요청 메시지 사용

메신저 인스턴스의 또 다른 유용한 기능은 모듈에서 다른 모듈로 값을 요청하는 데 사용할 수도 있다는 것입니다. 이를 위해 패키지에는 다음과 같이 사용할 수 있는 기본 RequestMessage<T> 클래스가 포함됩니다.

// Create a message
public class LoggedInUserRequestMessage : RequestMessage<User>
{
}

// Register the receiver in a module
WeakReferenceMessenger.Default.Register<MyViewModel, LoggedInUserRequestMessage>(this, (r, m) =>
{
    // Assume that "CurrentUser" is a private member in our viewmodel.
    // As before, we're accessing it through the recipient passed as
    // input to the handler, to avoid capturing "this" in the delegate.
    m.Reply(r.CurrentUser);
});

// Request the value from another module
User user = WeakReferenceMessenger.Default.Send<LoggedInUserRequestMessage>();

클래스에는 RequestMessage<T> 포함된 개체로의 변환을 LoggedInUserRequestMessage 가능하게 하는 암시적 변환기가 포함되어 User 있습니다. 또한 메시지에 대한 응답이 수신되었는지 확인하고 그렇지 않은 경우 예외를 throw합니다. 이 필수 응답 보장 없이 요청 메시지를 보낼 수도 있습니다. 반환된 메시지를 지역 변수에 저장한 다음 응답 값을 사용할 수 있는지 여부를 수동으로 확인합니다. 이렇게 하면 메서드가 반환될 때 응답을 받지 못하면 자동 예외가 Send 트리거되지 않습니다.

동일한 네임스페이스에는 다른 시나리오에 대한 기본 요청 메시지도 포함됩니다. AsyncRequestMessage<T>CollectionRequestMessage<T> AsyncCollectionRequestMessage<T> 비동기 요청 메시지를 사용하는 방법은 다음과 같습니다.

// Create a message
public class LoggedInUserRequestMessage : AsyncRequestMessage<User>
{
}

// Register the receiver in a module
WeakReferenceMessenger.Default.Register<MyViewModel, LoggedInUserRequestMessage>(this, (r, m) =>
{
    m.Reply(r.GetCurrentUserAsync()); // We're replying with a Task<User>
});

// Request the value from another module (we can directly await on the request)
User user = await WeakReferenceMessenger.Default.Send<LoggedInUserRequestMessage>();

예제

  • 샘플 앱(여러 UI 프레임워크의 경우)을 확인하여 작동 중인 MVVM 도구 키트를 확인합니다.
  • 단위 테스트에서 더 많은 예제를 찾을 수도 있습니다.