07. ObservableRecipient
1. 참고자료
✔️ Microsoft Learn / Learn / .NET / MVVM

공유한 링크는 .NET Community Toolkit의 ObservableRecipient 클래스에 대한 문서입니다.
이 클래스는 ObservableObject와 IRecipient<TMessage>를 결합하여 만든 ViewModel 전용 수신자 기반 클래스입니다.
MVVM 아키텍처에서 메시지 기반 통신을 간편하게 사용할 수 있도록 도와줍니다.
2. ObservableRecipient 개요
✔️ 작동 방식
구성 |
요소설명 |
Messenger | WeakReferenceMessenger.Default로 메시지를 보내고 받음 |
IsActive | true일 때만 메시지를 수신할 수 있음 (디폴트: false) |
Receive(TMessage) | 메시지를 받았을 때 자동으로 실행되는 메서드 |
WeakReferenceMessenger.Default.RegisterAll(this) | 수신자 등록 – 자동 등록도 가능하지만 명시적 호출 권장 |
[MainViewModel] ---> (Messenger.Send)
↓
[ObservableRecipient]
↓
Receive(TMessage)
- 메시지는 전역 메신저 인스턴스를 통해 전달됨
- 수신자는 IsActive가 true여야 하고 Receive()를 구현해야 수신 가능
- 등록은 Register 혹은 RegisterAll로 수행 가능
✔️ 작동 방식
- CommunityToolkit.Mvvm.Input.RelayCommand는 ICommand 인터페이스를 자동으로 구현해주는 소스 생성기(SG) 기반 기능입니다.
- 버튼 클릭, 이벤트 실행, 단축키 처리 등 사용자 액션을 ViewModel의 메서드로 연결해줍니다.
- [RelayCommand] 특성을 메서드에 붙이면 자동으로 <메서드이름>Command 속성이 생성됩니다.
✔️ 왜 필요한가?
- ViewModel 간 결합도를 낮춘 메시지 기반 통신 가능
- ViewModel이 필요할 때만 메시지 수신 (IsActive 제어)
- INotifyPropertyChanged 기능 내장
적용 구조 | 목적 |
IsActive = false → 수신 안 됨 | 수신 조건 실험 |
ViewModel 간 직접 참조 ❌ | 낮은 결합도 설계 경험 |
Receive() 내부 로직 작성 | 메시지 처리 로직 설계 |
3. 예제1 (MainView → DetailView, LogView)
✔️ 동작 시나리오
- MainView.xaml.cs에 WeakReferenceMessenger 등록 → View에서도 메시지 수신
- 메시지 수신 시 MessageBox로 사용자에게 알림
- 뷰와 ViewModel이 함께 메시지를 수신하므로 메시지 흐름을 시각적으로 학습 가능
📁 프로젝트 구조
ObservableRecipientSample/
│
├── Models/
│ └── Student.cs
│
├── Messages/
│ └── StudentSelectedMessage.cs
│
├── ViewModels/
│ ├── MainViewModel.cs // 송신자
│ └── DetailViewModel.cs // 수신자1
│ └── MessageLogViewModel.cs // 수신자2
│
├── Views/
│ ├── MainView.xaml
│ └── DetailView.xaml
│ └── MessageLogView.xaml
│
└── App.xaml.cs
✔️ Model 클래스 만들기
public class Student
{
public string Name { get; set; } = string.Empty; // 학생 이름
public int Age { get; set; } // 학생 나이
}
✔️ ViewModel 클래스 만들기 (MainViewModel.cs)
//
✔️ XAML 화면 구성
<
✔️ 결과
- 항목 클릭 시 ViewModel.SelectedItem이 변경되며, 해당 항목의 IsSelected가 true가 됩니다.
- 트리거에 의해 선택된 항목만 배경색이 변경됩니다.
✔️ 소스코드
4. 예제2 (MainView → 선택 → DetailView )
✔️ 동작 시나리오
- 학생 리스트 → 선택 → 상세보기 구조
- DetailView를 Dialog로 전환
- Messenger로 객체(Student) 전체 전달
📁 프로젝트 구조
ObservableRecipientSample/
│
├── Models/
│ └── Student.cs
│
├── Messages/
│ └── StudentSelectedMessage.cs
│
├── ViewModels/
│ ├── MainViewModel.cs // 송신자
│ └── DetailViewModel.cs // 수신자
│
├── Views/
│ ├── MainView.xaml
│ └── DetailView.xaml
│
└── App.xaml.cs
✔️ Model 클래스 만들기
public class Student
{
public string Name { get; set; } = string.Empty; // 학생 이름
public int Age { get; set; } // 학생 나이
}
✔️ ViewModel 클래스 만들기 (MainViewModel.cs)
//
✔️ XAML 화면 구성
<
✔️ 결과
- 항목 클릭 시 ViewModel.SelectedItem이 변경되며, 해당 항목의 IsSelected가 true가 됩니다.
- 트리거에 의해 선택된 항목만 배경색이 변경됩니다.
✔️ 소스코드
5. 예제3 - (MainView → 선택 → DetailView // LogView)
✔️ 추가 구현 기능
기능 |
설명 |
ViewModel 간 양방향 메시지 전달 | Main → Detail Main → Log |
선택된 창(Target)에만 메시지 전달 | TargetView 문자열로 분기 처리 (DetailView, LogView) |
DI 확장 구조 준비 | 모든 View에서 ViewModel 바인딩 → 추후 DI 컨테이너로 대체 가능 (예: App.xaml.cs에서 IServiceProvider 등록) |
타이밍 보장 | 창 생성 후 Loaded 시점에 메시지 전송 |
📁 프로젝트 구조
ObservableRecipientSample/
│
├── Models/
│ └── Student.cs
│
├── Messages/
│ └── StudentSelectedMessage.cs
│
├── ViewModels/
│ ├── MainViewModel.cs // 송신자
│ └── DetailViewModel.cs // 수신자1
│ └── LogViewModel.cs // 수신자2
│
├── Views/
│ ├── MainView.xaml
│ └── DetailView.xaml
│ └── LogView.xaml
│
└── App.xaml.cs
✔️ Model 클래스 만들기
public class Student
{
public string Name { get; set; } = string.Empty; // 학생 이름
public int Age { get; set; } // 학생 나이
}
✔️ ViewModel 클래스 만들기 (MainViewModel.cs)
//
✔️ XAML 화면 구성
<
✔️ 결과
- 항목 클릭 시 ViewModel.SelectedItem이 변경되며, 해당 항목의 IsSelected가 true가 됩니다.
- 트리거에 의해 선택된 항목만 배경색이 변경됩니다.
✔️ 소스코드
6. 예제4 - (MainView → 선택 → DetailView)
7. 예제5 - DependencyInjection
추가 확장
- Prism, Autofac 또는 Microsoft.Extensions.DependencyInjection으로 DI 완성
- 창 재사용 구조 (싱글턴 View or ViewModel 보관소)