16. INavigationService
1. INavigationService 개요
더보기
✔️ INavigationService
- INavigationService 인터페이스 기반으로 ViewModel 간 탐색이 가능한 구조로 확장
- INavigationService를 정의하고 NavigationService에서 SubWindow 열기 기능 구현
- MainViewModel에 INavigationService를 생성자 주입
- App.xaml.cs에서 IoC 컨테이너에 .AddSingleton<INavigationService, NavigationService>() 등록
- 이렇게 하면 ViewModel은 UI(Window)를 직접 알 필요 없이 Navigation 요청만 수행하므로 MVVM 원칙을 더욱 충실히 구현
📁 최종 WPF MVVM 프로젝트 구조
WPF_INavigationService01/
├── Messages/
│ └── LogUpdateMessage.cs ← View 간 메시지 전달 클래스
├── Services/
│ ├── ILoggerService.cs ← 로그 인터페이스
│ ├── Logger.cs ← Singleton Logger
│ ├── INavigationService.cs ← 탐색 인터페이스
│ └── NavigationService.cs ← Window 열기 구현
├── ViewModels/
│ ├── MainViewModel.cs ← Logger + Navigation 사용
│ └── SubViewModel.cs ← Logger 메시지 수신
├── Views/
│ ├── MainWindow.xaml ← 메인 뷰
│ ├── MainWindow.xaml.cs
│ ├── SubWindow.xaml ← 서브 뷰 (로그 공유 확인)
│ └── SubWindow.xaml.cs
└── App.xaml
└── App.xaml.cs ← IoC 컨테이너 구성
구성 | MVVM 패키지 사용 장점 |
Singleton Logger | 전역 상태 관리, 로그 공유 |
Messenger | ViewModel 간 통신 (느슨한 연결) |
IoC (Ioc.Default) | 테스트 가능하고 유지보수 쉬운 DI 구조 |
NavigationService | ViewModel에서 View 직접 접근 없이 탐색 |
📦 NuGet 패키지 설치 필요 항목
CommunityToolkit.Mvvm
Microsoft.Extensions.DependencyInjection
🔁 동작 흐름
- App.xaml.cs에서 DI 컨테이너에 서비스 및 ViewModel 등록
- MainWindow는 MainViewModel을 IoC로 주입
- MainViewModel에서 INavigationService를 통해 SubWindow 실행
- Logger.Instance.Log(...)가 실행되면 메시지 전송
- MainViewModel, SubViewModel 모두 메시지를 수신하고 로그를 동기화 표시
2. 예제1
더보기





📁 Message 구현
WPF_INavigationService01/
├── Messages/
│ └── LogUpdateMessage.cs ← View 간 메시지 전달 클래스
//├── Services/
//│ ├── ILoggerService.cs ← 로그 인터페이스
//│ ├── Logger.cs ← Singleton Logger
//│ ├── INavigationService.cs ← 탐색 인터페이스
//│ └── NavigationService.cs ← Window 열기 구현
//├── ViewModels/
//│ ├── MainViewModel.cs ← Logger + Navigation 사용
//│ └── SubViewModel.cs ← Logger 메시지 수신
//├── Views/
//│ ├── MainWindow.xaml ← 메인 뷰
//│ ├── MainWindow.xaml.cs
//│ ├── SubWindow.xaml ← 서브 뷰 (로그 공유 확인)
//│ └── SubWindow.xaml.cs
//└── App.xaml
// └── App.xaml.cs ← IoC 컨테이너 구성
✔️ LogUpdateMessage 메시지 구현
// 메시지 정의
public class LogUpdateMessage : ValueChangedMessage<string>
{
public LogUpdateMessage(string value) : base(value) { }
}
📁 Services 구현
WPF_INavigationService01/
//├── Messages/
//│ └── LogUpdateMessage.cs ← View 간 메시지 전달 클래스
├── Services/
│ ├── ILoggerService.cs ← 로그 인터페이스
│ ├── Logger.cs ← Singleton Logger
│ ├── INavigationService.cs ← 탐색 인터페이스
│ └── NavigationService.cs ← Window 열기 구현
//├── ViewModels/
//│ ├── MainViewModel.cs ← Logger + Navigation 사용
//│ └── SubViewModel.cs ← Logger 메시지 수신
//├── Views/
//│ ├── MainWindow.xaml ← 메인 뷰
//│ ├── MainWindow.xaml.cs
//│ ├── SubWindow.xaml ← 서브 뷰 (로그 공유 확인)
//│ └── SubWindow.xaml.cs
//└── App.xaml
// └── App.xaml.cs ← IoC 컨테이너 구성
✔️ ILoggerService 인터페이스 구현
public interface ILoggerService
{
void Log(string message);
string GetLogs();
}
✔️ Logger 클래스 구현
public sealed class Logger : ILoggerService
{
private static Logger? _instance = null;
private static readonly object _lock = new();
private readonly StringBuilder _logs = new();
private Logger()
{
Console.WriteLine("Logger 인스턴스가 생성되었습니다.");
}
public static Logger Instance
{
get
{
lock (_lock)
{
return _instance ??= new Logger();
}
}
}
public void Log(string message)
{
string log = $"{DateTime.Now:HH:mm:ss} - {message}";
_logs.AppendLine(log);
// 로그가 업데이트되면 메시지를 발송하여 ViewModel에 알림
WeakReferenceMessenger.Default.Send(new LogUpdateMessage(_logs.ToString()));
}
public string GetLogs()
{
return _logs.ToString();
}
}
✔️ INavigationService 인터페이스 구현

public interface INavigationService
{
void OpenSubWindow();
}
✔️ NavigationService 클래스 구현

📁 ViewModel 구현
WPF_INavigationService01/
//├── Messages/
//│ └── LogUpdateMessage.cs ← View 간 메시지 전달 클래스
//├── Services/
//│ ├── ILoggerService.cs ← 로그 인터페이스
//│ ├── Logger.cs ← Singleton Logger
//│ ├── INavigationService.cs ← 탐색 인터페이스
//│ └── NavigationService.cs ← Window 열기 구현
├── ViewModels/
│ ├── MainViewModel.cs ← Logger + Navigation 사용
│ └── SubViewModel.cs ← Logger 메시지 수신
//├── Views/
//│ ├── MainWindow.xaml ← 메인 뷰
//│ ├── MainWindow.xaml.cs
//│ ├── SubWindow.xaml ← 서브 뷰 (로그 공유 확인)
//│ └── SubWindow.xaml.cs
//└── App.xaml
// └── App.xaml.cs ← IoC 컨테이너 구성
✔️ MainViewModel 구현

public partial class MainViewModel : ObservableObject
{
private readonly INavigationService _navigation;
private readonly ILoggerService _logger;
[ObservableProperty]
private string logText;
public MainViewModel(ILoggerService logger, INavigationService navigation)
{
_navigation = navigation;
_logger = logger;
_logger.Log("MainWindow 열림");
LogText = _logger.GetLogs();
// 메시지 수신 등록
WeakReferenceMessenger.Default.Register<LogUpdateMessage>(this, (r, m) =>
{
LogText = m.Value;
});
}
[RelayCommand]
private void WriteLog()
{
_logger.Log("MainWindow에서 로그 기록");
var logs = _logger.GetLogs();
LogText = logs;
WeakReferenceMessenger.Default.Send(new LogUpdateMessage(logs));
}
[RelayCommand]
private void OpenSubWindow()
{
//var sub = new SubWindow();
//sub.Show();
_navigation.OpenSubWindow();
}
}
✔️ SubViewModel 구현
public partial class SubViewModel : ObservableObject
{
private readonly ILoggerService _logger;
[ObservableProperty]
private string logText;
public SubViewModel(ILoggerService logger)
{
_logger = logger;
_logger.Log("SubWindow 열림");
LogText = _logger.GetLogs();
WeakReferenceMessenger.Default.Register<LogUpdateMessage>(this, (r, m) =>
{
LogText = m.Value;
});
}
[RelayCommand]
private void WriteLog()
{
_logger.Log("SubWindow에서 로그 기록");
var logs = _logger.GetLogs();
LogText = logs;
WeakReferenceMessenger.Default.Send(new LogUpdateMessage(logs));
}
}
📁 View 구현
WPF_INavigationService01 /
//├── Messages/
//│ └── LogUpdateMessage.cs ← View 간 메시지 전달 클래스
//├── Services/
//│ ├── ILoggerService.cs ← 로그 인터페이스
//│ ├── Logger.cs ← Singleton Logger
//│ ├── INavigationService.cs ← 탐색 인터페이스
//│ └── NavigationService.cs ← Window 열기 구현
//├── ViewModels /
//│ ├── MainViewModel.cs ← Logger + Navigation 사용
//│ └── SubViewModel.cs ← Logger 메시지 수신
├── Views /
│ ├── MainWindow.xaml ← 메인 뷰
│ ├── MainWindow.xaml.cs
│ ├── SubWindow.xaml ← 서브 뷰 (로그 공유 확인)
│ └── SubWindow.xaml.cs
//└── App.xaml
// └── App.xaml.cs ← IoC 컨테이너 구성
✔️ MainWindow.xaml 구현
Title="MainWindow" Height="300" Width="400">
<StackPanel Margin="10">
<Button Content="로그 남기기" Command="{Binding WriteLogCommand}" Margin="0 0 0 10"/>
<Button Content="SubWindow 열기" Command="{Binding OpenSubWindowCommand}" Margin="0 0 0 10"/>
<TextBox Text="{Binding LogText}" AcceptsReturn="True" Height="200" VerticalScrollBarVisibility="Auto"/>
</StackPanel>
✔️ MainWindow.xaml.cs 구현
public MainWindow()
{
InitializeComponent();
// DataContext = new MainViewModel(Logger.Instance);
// DataContext = Ioc.Default.GetService<MainViewModel>();
DataContext = Ioc.Default.GetRequiredService<MainViewModel>();
}
✔️ SubWindow 구현
Title="SubWindow" Height="250" Width="350">
<StackPanel Margin="10">
<Button Content="로그 남기기" Command="{Binding WriteLogCommand}" Margin="0 0 0 10"/>
<TextBox Text="{Binding LogText}" AcceptsReturn="True" Height="150" VerticalScrollBarVisibility="Auto"/>
</StackPanel>
✔️ SubWindow.xaml.cs 구현
public SubWindow()
{
InitializeComponent();
// DataContext = new SubViewModel(Logger.Instance);
// DataContext = Ioc.Default.GetService<SubViewModel>();
DataContext = Ioc.Default.GetRequiredService<SubViewModel>();
}
📁 Services 구현
WPF_INavigationService01 /
//├── Messages/
//│ └── LogUpdateMessage.cs ← View 간 메시지 전달 클래스
//├── Services/
//│ ├── ILoggerService.cs ← 로그 인터페이스
//│ ├── Logger.cs ← Singleton Logger
//│ ├── INavigationService.cs ← 탐색 인터페이스
//│ └── NavigationService.cs ← Window 열기 구현
//├── ViewModels /
//│ ├── MainViewModel.cs ← Logger + Navigation 사용
//│ └── SubViewModel.cs ← Logger 메시지 수신
//├── Views /
//│ ├── MainWindow.xaml ← 메인 뷰
//│ ├── MainWindow.xaml.cs
//│ ├── SubWindow.xaml ← 서브 뷰 (로그 공유 확인)
//│ └── SubWindow.xaml.cs
└── App.xaml
└── App.xaml.cs ← IoC 컨테이너 구성
✔️ App.xaml 구현

✔️ App.xaml.cs 구현

protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// IoC 컨테이너에 싱글톤 Logger 등록
Ioc.Default.ConfigureServices(
new ServiceCollection()
.AddSingleton<ILoggerService>(Logger.Instance)
.AddTransient<MainViewModel>()
.AddTransient<SubViewModel>()
.BuildServiceProvider()
);
var mainWindow = new MainWindow();
mainWindow.Show();
}
✔️ 소스코드
WPF_INavigationService.zip
0.09MB