[WPF] 테마 변경 질문입니다.

안녕하세요, 반갑습니다.

ThemeChanged
(눈부심 주의)
위와 같이 2개의 테마를 버튼으로 컨트롤합니다.

궁금한것은 이 방식이 문제가 잇는지에 대해서 입니다.
사용한 방법은 밑에 소스와 같습니다.

// App.xaml 첫 디버깅 시 DarkTheme로 셋팅 됩니다.
<Application >
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/Themes/DarkTheme.xaml" />  // DarkTheme 추가
                <ResourceDictionary Source="/Style/ToolBox.xaml" />     // 각 Tool(TextBox, ListView)에 대한 Style 지정입니다.
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>
// ViewModel
if (IsSetMode)
{
	App.Current.Resources.MergedDictionaries.Add(Light);     //LightTheme
	App.Current.Resources.MergedDictionaries.Add(ToolBox);   //ToolBox.xaml
	IsSetMode = false;
}
else if (!IsSetMode)
{
	App.Current.Resources.MergedDictionaries.Remove(ToolBox);  //ToolBox.xaml
	App.Current.Resources.MergedDictionaries.Remove(Light);    //LightTheme
	IsSetMode = true;
}

image
[ToolBox.xaml]

버튼 클릭 시 ViewModel에서 위의 코드를 실행합니다.



ToolBox.xaml에서 Theme의 일부분을 상속받고 View에 뿌려줍니다.
BasedOn ="{StaticResource ...}"로 받기 때문에 테마 변경 시 적용이 안됩니다.
그래서 한 것이 위에 소스처럼 Light 테마에 대한 ToolBox.xaml를 만든 후 올렸다 내렸다 하는 것입니다.

5개의 좋아요

문제가 있냐는 말씀이 MVVM 관점에서 MVVM에 위배되냐는 의미라면, 엄밀히 말해 MVVM 관점에서는 문제가 있는 방식이라고 생각합니다. 테마는 단순히 사용자에게 어떻게 보여줄지에만 집중하는 Presentation Logic이니까요. ViewModel이 아니라 View에 있어야 할 내용이죠.

테마를 변경하는 방법이 문제가 있냐는 의미라면, 문제 없다고 생각됩니다. 일반적으로 실시간으로 테마를 변경할 때 첨부하신 방법으로 구현하는 것으로 알고 있습니다.

https://github.com/lepoco/wpfui/blob/main/src/WPFUI/Appearance/ResourceDictionaryManager.cs

4개의 좋아요

ViewModel이 아닌 곳에서 테마를 어떻게 변경해야할지 알아바야 할것 같네요.

감사합니다. :+1:

2개의 좋아요

제로 코드 비하인드를 반드시 유지할 목적이 아니라면 단순하게 테마 변경 버튼의 click 이벤트에 해당 코드를 넣으시는 게 제일 간단할 것 같네요.

2개의 좋아요

ViewModel이 다양한 단위로 구성될 수 있는 것 처럼 View도 그럴 수 있습니다. 모든 원칙을 의존성의 기준으로 생각하고 이해하면 쉽게 이해될 수도 있어요.

테마 관련 처리를 별도의 클래스로 구성하고 View에만 사용하면 MVVM 원칙을 훼손하지 않으면서 모듈화 할 수 있습니다.

그리고 다른 얘기지만 StaticResource는 참조가 되는 시점에서 값이 고정됩니다. DynamicResource를 사용해서 테마에 따라 스타일을 바꿀 수 있는데요, 일장 일단이 있습니다.

아무래도 DynamicResourceStaticResource보다는 약간 느릴 수 있겠지요. 그 느린 정도가 일반적인 상황일 경우 무시할 수준이라고 생각은 합니다.

3개의 좋아요

네 감사합니다.

테마 파일에 같이 첨부된 테마컨트롤.cs가 따로 있어서
이 걸 이용하면 될 것 같습니다.
컨트롤.cs 내용은 아니지만 View 전환을 ioc를 이용해서 사용하는 것 같더라구요.
( 아직은 왜 MVVM을 위반했는지, 어떻게 MMVM을 유지했는지 에 대해 잘 이해가 안되지만 )

처음엔 basedOn으로 상속받는 걸 Dynamic으로 받으면 되질 않을까 했습니다. (상속시 에는 부모가 명시?되어야해서) staticResource로 받아야 되더군요.
그래서 시도 한게 MainWindow.xaml에서 Style을 DynamicResource로 받고
테마 당 각 하나씩 Style을 만들어서 할당 했습니다.

테마를 변경되는 것을 테스트 했고 MVVM을 위반된 걸 확인 했으니 이 부분만 잡으면 될 것 같습니다. :grinning:

다핸히 간단한 프로그램이라 큰 성능문제는 없네요


05/26 기록

이해는 안되는데 정보는 많아서 복잡하네요
어떤게 좋은지 , 문제가 되는지 고민이 됩니다.

2가지 방안을 실행했습니다.

  1. MainViewModel에서 IoC로 ThemesViewModel을 컨트롤 한다.
  2. (MainViewModel를 거치지 않고) ViewModelLocater를 이용하여 ThemesViewModel로 연결합니다.
    ThemesViewModel 내부에 RealyCommand를 구현하여 실행합니다.

image
(MainWindowViewMode)
IoC를 이용하여 Button 동작 부를 사진과 같이 설정 했습니다.
하고나니 버튼 커맨드 자체를 ThemesViewModel에 넘겨서 실행이 가능 할 것 같았습니다.

image

<Button  Command="{Binding ThemesViewModel.ModeCommand,
          Source={x:Static local:ViewModelLocator.Instance}}"/>

ThemesViewModel에 RealyCommand를 구현하여 실행했습니다.
이렇게하면 ThemesViewModel에 Theme 전환기능과 Button RelayCommand가 존재하게 됩니다.

링크 : 깃허브

4개의 좋아요