IsolatedStorage를 사용하면 Blend에서 디자인이 안보인다?에서 DesignerProperties 클래스를 활용하여 Blend에서 실행중인지 여부를 구분할 수 있다고 했는데요, DesignerProperties를 보다 정확하게 활용할 수 있는 간단한 방법을 소개합니다.

기본적으로 DesignerProperties는 다음과 같이 사용하면 되죠.

if (DesignersProperties.GetIsInDesignMode(AnyUIElementInVisualTree) == true)
    // 디자인 모드
else
    // Web 모드

간단하죠? 그런데 한 가지 문제는 반드시 인자로 VisualTree에 올라가 있는 UIElement를 필요로 한다는 점이에요. 보통 UserControl이나 Control 안에 코드를 작성할 때에는 단순히 GetIsDesignerMode(this)를 해도 무방하지만 Model과 같이 따로 UIElement를 확정할 수 없는 코드에서는 난감하죠. 이럴 때에는 다음과 같이 해결할 수 있어요.

if (DesignersProperties.GetIsInDesignMode(Application.Current.RootVisual) == true)
    // 디자인 모드
else
    // Web 모드

Application이 지원하는 RootVisual은 전역에서 일관적으로 접근할 수 있는데다가 비주얼 트리VisualTree의 최상위 오브젝트를 의미하니까 완벽해 보여요. 그렇지만 여기에도 문제는 있는데요, 바로 Application이 아직 RootVisual을 결정하지 못한 상태일 때에 이 검사는 실패한다는 점이죠. 일반적인 실버라이트 애플리케이션의 App.xaml.cs를 보죠.

public App()
{
    this.Startup += this.Application_Startup;
    this.Exit += this.Application_Exit;
    this.UnhandledException += this.Application_UnhandledException;

    InitializeComponent();
}

private void Application_Startup(object sender, StartupEventArgs e)
{
    this.RootVisual = new Page();
}

7행의 InitializeComponent();가 실행되기 직전에는 Application.Current.RootVisual이 실버라이트 애플리케이션을 다운로드 받는 동안 보이는 로딩 화면Splash에 대한 비주얼 트리를 담고 있죠.

image

그 후 애플리케이션이 초기화 되고 로딩 화면이 사라진 후 Application_Startup 이벤트 핸들러가 호출되는데요, 12행의 RootVisual을 new Page로 설정하기 직전까지는 Application.Current.RootVisual이 null 값을 가지고 있어요.

즉, 애플리케이션이 초기화 된 직후부터 RootVisual을 설정하기 전까지 Application.Current.RootVisual이 null이므로 이 사이에는 DesignerProperties.GetIsDesignMode(Application.Current.RootVisual)이란 코드는 안전하지 않게 되는거죠. 한 가지 다행인 점은 앞서 본 것 처럼 App 클래스의 생성자에서 RootVisual이 null이 아니기 때문에 이를 이용하여 다음과 같이 안전한 코드를 작성할 수 있어요.

// 초기값은 블렌드에서 실행중이라고 가정합니다.
private bool _isBlend = true;
/// 
/// 블렌드에서 실행중인지 여부를 반환합니다.
/// 
public bool IsBlend
{
    get { return _isBlend; }
    private set { _isBlend = value; }
}

public App()
{
    // 블렌드에서 실행중인지 여부를 검사합니다.
    IsBlend = DesignerProperties.GetIsInDesignMode(RootVisual);

    this.Startup += this.Application_Startup;
    this.Exit += this.Application_Exit;
    this.UnhandledException += this.Application_UnhandledException;

    InitializeComponent();
}

여기서 중요한 점은 최초에는 블렌드에서 실행중이라고 가정한다는 거에요. 그 이유는 내부적으로 블렌드에서 실행될 때에 분명히 Application의 생성자가 호출되지만 우리가 그것을 확인할 수 없기 떄문에 실행 코드의 ‘모호성’을 줄이기 위해서에요. 반면 웹 페이지로 동작하고 있다면 이 코드는 100% 동작한다고 확신할 수 있으니 초기 값을 안전하기 가져가는 것이 좋겠죠.

그리고 코드를 애플리케이션 전역에서 공유할 수 있도록 App 클래스의 static 멤버로 정의했기 때문에 애플리케이션의 어떤 코드에서도 안전하게 가져갈 수 있겠죠.

만약 라이브러리에서도 블렌드에서 실행중인지 여부를 검사해야 한다면 여기에서 한 단계 더 나아가 위의 코드를 래핑하는 전역 클래스Static Class를 하나 만들 수도 있고요. 이 부분은 각자 프로젝트에 맞춰서 해보세요.

저작자 표시 동일 조건 변경 허락
신고
Posted by gongdo


티스토리 툴바