1. Singleton 주입 개요

더보기

✔️ 사용 목적

  • Logger 같은 전역 서비스(Singleton)를 ViewModel에 안전하게 주입하여 사용합니다.
  • MVVM에서 Logger.Instance를 직접 참조하지 않고, 인터페이스 기반으로 느슨한 결합을 유지합니다.

 

 



✔️ 소스코드

 

WPF_Singleton.zip
0.23MB

 

 

 

 

 

2. 예제1 - Window 1개

더보기

📁 Services 구현

WPF_Singleton04_01MVVM/
  ├── Services/
  │   ├── ILoggerService.cs
  │   └── Logger.cs            ← Singleton 구현
//├── ViewModels/
//│   └── MainViewModel.cs
//├── Views/
//│   └── MainWindow.xaml
//│   └── MainWindow.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 Singleton 인스턴스 생성됨");
    }

    public static Logger Instance
    {
        get
        {
            lock (_lock)
            {
                return _instance ??= new Logger();
            }
        }
    }

    public void Log(string message)
    {
        _logs.AppendLine($"{DateTime.Now:HH:mm:ss} - {message}");
    }

    public string GetLogs()
    {
        return _logs.ToString();
    }
}



 

 

📁 ViewModels 구현

WPF_Singleton04_01MVVM/
//├── Services/
//│   ├── ILoggerService.cs
//│   └── Logger.cs            ← Singleton 구현
  ├── ViewModels/
  │   └── MainViewModel.cs
//├── Views/
//│   └── MainWindow.xaml
//│   └── MainWindow.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("MainViewModel 생성됨");
        LogText = _logger.GetLogs();
    }

    [RelayCommand]
    private void WriteLog()
    {
        _logger.Log("버튼 클릭 로그 기록");
        LogText = _logger.GetLogs();
    }
}

 

 

 

 

📁 View 구현

WPF_Singleton04_01MVVM/
//├── Services/
//│   ├── ILoggerService.cs
//│   └── Logger.cs            ← Singleton 구현
//├── ViewModels/
//│   └── MainViewModel.cs
  ├── Views/
  │   └── MainWindow.xaml
  │   └── MainWindow.xaml.cs
//└── App.xaml.cs

 

✔️ MainWindow XAML 구현

    Title="Logger Singleton" Height="250" Width="400">
<StackPanel Margin="10">
    <Button Content="로그 남기기" Command="{Binding WriteLogCommand}" Margin="0 10"/>
    <TextBox Text="{Binding LogText}" Height="150" AcceptsReturn="True" VerticalScrollBarVisibility="Auto"/>
</StackPanel>

 

✔️ MainWindow 코드 비하인드 구현

// Logger.Instance 를 서비스 인터페이스로 주입
DataContext = new MainViewModel(Logger.Instance);

 

 

 

 

 

3. 예제2 - Window 2개

더보기

📁 Services 구현

WPF_Singleton04_02MVVM/
  ├── 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 클래스 구현

// Logger 클래스는 애플리케이션 전역에서 하나만 존재해야 하는 로깅 클래스입니다.
// 여러 창(Window) 또는 ViewModel에서 공통적으로 사용할 수 있도록 Singleton 패턴으로 구성됩니다.
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)
    {
        _logs.AppendLine($"{DateTime.Now:HH:mm:ss} - {message}");
    }

    public string GetLogs()
    {
        return _logs.ToString();
    }
}

 

 


 

📁 ViewModels 구현

WPF_Singleton04_02MVVM/
//├── 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();
    }

    [RelayCommand]
    private void WriteLog()
    {
        _logger.Log("MainWindow에서 로그 기록");
        LogText = _logger.GetLogs();
    }

    [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();
    }

    [RelayCommand]
    private void WriteLog()
    {
        _logger.Log("SubWindow에서 로그 기록");
        LogText = _logger.GetLogs();
    }
}

 

 

 


📁
View 구현

WPF_Singleton04_02MVVM/
//├── 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"/>
</StackPanel>

 

✔️ MainWindow 코드 비하인드 구현

public MainWindow()
{
    InitializeComponent();

    // Logger.Instance 를 서비스 인터페이스로 주입
    DataContext = new MainViewModel(Logger.Instance);
}

 

 

✔️ SubWindow 구현

 

✔️ SubWindow 코드 비하인드 구현

public SubWindow()
{
    InitializeComponent();

    // Logger.Instance 를 서비스 인터페이스로 주입
    DataContext = new SubViewModel(Logger.Instance);
}