15. Singleton 주입 → DependencyInjection

1. DependencyInjection 개요
더보기
✔️ Singleton 주입
- Logger 같은 전역 서비스(Singleton)를 ViewModel에 안전하게 주입하여 사용합니다.
- MVVM에서 Logger.Instance를 직접 참조하지 않고, 인터페이스 기반으로 느슨한 결합을 유지합니다.
✔️ "Singleton 주입"을, DependencyInjection 기반으로 확장
- App.xaml.cs에서 DI 컨테이너를 구성하고,
- ILoggerService를 싱글톤으로 등록해 MainViewModel, SubViewModel에 자동으로 주입됩니다.
- App.xaml.cs에서 ServiceCollection을 구성하고 ILoggerService, MainViewModel, SubViewModel을 등록
- MainWindow.xaml.cs, SubWindow.xaml.cs에서 Ioc.Default.GetRequiredService<T>()로 ViewModel 주입
- ViewModel 생성자는 그대로 ILoggerService를 받음
2. 예제1
더보기



📁 Message 구현
WPF_Singleton04_03MVVM/ ├── Messages/ │ ├── LogUpdateMessage.cs //├── Services/ //│ ├── ILoggerService.cs //│ └── Logger.cs ← Singleton 구현 //├── ViewModels/ //│ └── MainViewModel.cs //│ └── SubViewModel.cs //├── Views/ //│ └── MainWindow.xaml //│ └── MainWindow.xaml.cs //│ └── SubWindow.xaml //│ └── SubWindow.xaml.cs //└── App.xaml.cs
✔️ LogUpdateMessage 메시지 구현
// 메시지 정의 public class LogUpdateMessage : ValueChangedMessage<string> { public LogUpdateMessage(string value) : base(value) { } }
📁 Services 구현
WPF_Singleton04_03MVVM/ //├── Messages/ //│ ├── LogUpdateMessage.cs ├── Services/ │ ├── ILoggerService.cs │ └── Logger.cs ← Singleton 구현 //├── ViewModels/ //│ └── MainViewModel.cs //│ └── SubViewModel.cs //├── Views/ //│ └── MainWindow.xaml //│ └── MainWindow.xaml.cs //│ └── SubWindow.xaml //│ └── SubWindow.xaml.cs //└── App.xaml.cs
✔️ 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(); } }
📁 ViewModel 구현
WPF_Singleton04_03MVVM/ //├── Messages/ //│ ├── LogUpdateMessage.cs //├── Services/ //│ ├── ILoggerService.cs //│ └── Logger.cs ← Singleton 구현 ├── ViewModels/ │ └── MainViewModel.cs │ └── SubViewModel.cs //├── Views/ //│ └── MainWindow.xaml //│ └── MainWindow.xaml.cs //│ └── SubWindow.xaml //│ └── SubWindow.xaml.cs //└── App.xaml.cs
✔️ MainViewModel 구현
public partial class MainViewModel : ObservableObject { private readonly ILoggerService _logger; [ObservableProperty] private string logText; public MainViewModel(ILoggerService logger) { _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(); } }
✔️ 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_Singleton04_03MVVM/ //├── Messages/ //│ ├── LogUpdateMessage.cs //├── Services/ //│ ├── ILoggerService.cs //│ └── Logger.cs ← Singleton 구현 //├── ViewModels/ //│ └── MainViewModel.cs //│ └── SubViewModel.cs ├── Views/ │ └── MainWindow.xaml │ └── MainWindow.xaml.cs │ └── SubWindow.xaml │ └── SubWindow.xaml.cs //└── App.xaml.cs
✔️ 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>(); }
✔️ 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>(); }
📁 Services 구현
WPF_Singleton04_03MVVM/ //├── Messages/ //│ ├── LogUpdateMessage.cs //├── Services/ //│ ├── ILoggerService.cs //│ └── Logger.cs ← Singleton 구현 //├── ViewModels/ //│ └── MainViewModel.cs //│ └── SubViewModel.cs //├── Views/ //│ └── MainWindow.xaml //│ └── MainWindow.xaml.cs //│ └── SubWindow.xaml //│ └── SubWindow.xaml.cs └── App.xaml.cs
✔️ 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_IoC.zip
0.11MB
댓글을 사용할 수 없습니다.