[WPF] View, ViewModel Singleton
지난 프로젝트에서 페이지 전환이 많다보니 생성자를 통해 View나 ViewModel을 넘기는 일이 많았습니다.
☠️ 하지만 새로운 인스턴스를 생성하는 방식으로 넘기게 될 때 동작이 제대로 작동하지 않는 문제가 있었습니다.
예를 들면,
1
2
3
4
5
6
|
public void OpenWindowSub1()
{
WindowSub1 window = new WindowSub1();
window.DataContext = new ViewModelSub1(new ViewModelMain());
window.Show();
}
|
Window를 새롭게 호출하는 경우, DataContext로 연결된 ViewModelSub1에 현재 ViewModelMain의 새로운 인스턴스를 넘겨줄 경우, 인스턴스에 저장된 데이터를 사용하지 못하게 됩니다.
따라서, 기존 인스턴스의 값을 사용하고 싶다면 새로운 인스턴스 생성이 아닌 this를 사용해 현재 인스턴스를 넘겨야 합니다.
1
2
3
4
5
6
|
public void OpenWindowSub1()
{
WindowSub1 window = new WindowSub1();
window.DataContext = new ViewModelSub1(this);
window.Show();
}
|
이럴 때, 만일 singleton 패턴을 사용한다면 처음처럼 인스턴스를 만들고자해도 기존의 인스턴스가 반환되기 때문에 문제를 다른 방식으로도 해결할 수 있습니다.
Singleton
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public static readonly object LockObject = new object();
private static WindowSub1 _instance = null;
public static WindowSub1 Instance
{
get
{
if (_instance == null)
{
lock (LockObject)
{
if (_instance == null)
{
_instance = new WindowSub1();
}
}
}
return _instance;
}
}
|
LockObject는 멀티 쓰레드 환경에서 동시에 여러 스레드가 인스턴스를 생성하는 것을 방지하는 구문입니다.
1. 잠금 요청
* 스레드가 lock(LockObject) 구문에 도달하면, LockObject( 잠금을 위해 사용되는 객체 )에 대한 잠금을 요청
2. 잠금 확인 및 대기
* 만약 다른 스레드가 이미 LockObject에 대한 잠금을 획득하고 있다면, 요청한 스레드는 대기 상태로 전환되고, 잠금이 해제될 때까지 대기
* 만약 LockObject에 대한 잠금이 없다면, 요청한 스레드는 잠금을 획득하고 코드 블록을 실행
3. 코드 블록 실행
* 잠금을 획득한 스레드는 lock 구문 내의 코드 블록을 실행
* 이 코드 블록은 동시에 하나의 스레드만 실행할 수 있음
4. 잠금 해제
* 코드 블록의 실행이 완료되면, 잠금은 자동으로 해제되고, 다른 스레드가 대기 큐에서 잠금을 요청할 수 있게 됨
⭐ 싱글톤 객체를 만들 때, 매개변수가 없는 기본 생성자를 사용
만일, 추가적으로 인자가 필요할 경우에는 매개변수가 있는 기본 생성자가 아닌 초기화 함수 사용
1
2
3
4
5
|
// 싱글톤 인스턴스 획득
ViewModelSub1 vmSub1 = ViewModelSub1.Instance;
// 초기화 메서드를 통해 데이터 설정
vmSub1.Initialize("Arg");
|