天天看點

“Win10 UAP 開發系列”之主題模式切換

微軟動作真是快,本來想寫WP8.1RT系列,結果剛整理了一點就出Win10 UAP了。不過還好RT到Win10的差别還不算太大。前兩天參加了Win10開發極客秀,雖然沒獲獎,不過在韋恩卑鄙的幫助下順利将澎湃新聞WP8.1版更新到了Win10UAP,使用了一些新的特性,最近争取有時間慢慢把一些東西總結一下。

今天先說一下如何在Win10 UAP中切換主題模式。

切換日間、夜間主題模式這個功能我從WP8就實作了,并封裝成了一個庫,用在我所有的WP8的app裡。到了WP8.1因為系統主題樣式都改了,又重寫了一遍。還沒來得及整理寫blog,Win10的樣式又改了……吐槽不完啊簡直。不過思路都是一樣的,現在以Win10版本為例總結一下。

UAP的樣式和以前的版本基本一樣,都是一些類似css的東西,我們通過覆寫系統的style,就可以實作自己的主題樣式。首先找到UAP的style的位置:

C:\Program Files (x86)\Windows Kits\10\Include\10.0.10069.0\winrt\xaml\design\themeresources.xaml

2015-12-29 update:

更新10586後,該檔案的位址在:

C:\Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\10.0.10586.0\Generic

裡面有generic.xaml和themeresources.xaml

打開這個檔案,可以看到裡面存放的是系統預設的主題樣式。

順便說一下,WP8 和WP8.1 的預設主題樣式也可以找到,位置不一樣。

一、建立UAP項目

建立個UAP項目。因為我習慣用MVVM-Sidekick來做,是以以後都會基于這個架構來做,順便給@韋恩卑鄙 做下廣告^_^

“Win10 UAP 開發系列”之主題模式切換

這個例子就叫ThemeDemo。确定。

等待架構程式建立完成。

“Win10 UAP 開發系列”之主題模式切換

可見現在Win10 UAP的項目隻有一個,與WP8.1時代分别為PC和手機建立項目的方式已經不同了。這樣可以更友善。

二、添加預設主題

用VS2015RC打開剛才找到的系統預設樣式檔案,如圖:

“Win10 UAP 開發系列”之主題模式切換

這樣看比較亂,把代碼折疊一下:

“Win10 UAP 開發系列”之主題模式切換

這樣看就清楚了,包括了Default、Light和高對比對三種主題樣式,和各種style、字型、字型大小、各種Color和Brush、控件的style等等,現在我們需要提取出來進行修改。

在項目中添加一個名為CustomTheme的檔案夾。

一般隻需要對Dark和Light分别處理即可,比如我想Dark的背景色不是純黑,Light的背景色不是純白等等。

建立兩個xaml檔案,命名為ThemeResourcesDark.xaml和ThemeResourcesLight.xaml,根節點這樣寫:

“Win10 UAP 開發系列”之主題模式切換

然後把系統樣式檔案裡有關Color和Brush的部分複制過來,Default對應Dark,Light對應Light。

控件的style另外建個檔案CustomStyleResources.xaml,把控件的style複制過來,因為不同主題下控件隻是背景色不同,margin、padding這些屬性都是一緻的。

我還添加了一套FlatUI的顔色資源,FlatUIColorsResources.xaml,裡面存放了各種Flat風格的Color和Brush來友善使用。

三、引入自定義樣式資源

打開App.xaml,添加以下代碼:

“Win10 UAP 開發系列”之主題模式切換

控件的style和主題的style都引入進來了,順便說一下,控件模闆等東西不要往App.xaml裡堆,多了顯得太亂,應該都統一放到資源檔案裡進行管理。

四、修改自定義樣式

現在運作程式,樣子是預設的,還是白底黑字。因為RequestedTheme="Light"。

現在我們修改個背景色看看。打開MainPage.xaml 可以看到以下代碼:

“Win10 UAP 開發系列”之主題模式切換

也就是說,根Grid的背景色名字是ApplicationPageBackgroundThemeBrush。

然後去ThemeResourcesLight.xaml檔案裡找這個資源,改一下顔色:

“Win10 UAP 開發系列”之主題模式切換

修改的顔色最好加個注釋。

然後跑一下:

“Win10 UAP 開發系列”之主題模式切換

好了背景色已經變了,不再是純白了。然後可以繼續改前景色、Dark主題的背景色、前景色……。

五、在程式中切換主題

UAP的主題是通過RequestedTheme來設定的,可以在頁面中綁定一個屬性來實作切換。

打開MainPage_Model.cs,添加一個屬性,輸入代碼段propvm按Tab

/// <summary>

///目前主題

/// </summary>

public ElementTheme CurrentTheme

{

get { return _CurrentThemeLocator(this).Value; }

set

_CurrentThemeLocator(this).SetValueAndTryNotify(value);

}

#region Property ElementTheme CurrentTheme Setup

protected Property<ElementTheme> _CurrentTheme = new Property<ElementTheme> { LocatorFunc = _CurrentThemeLocator };

static Func<BindableBase, ValueContainer<ElementTheme>> _CurrentThemeLocator = RegisterContainerLocator<ElementTheme>("CurrentTheme", model => model.Initialize("CurrentTheme", ref model._CurrentTheme, ref _CurrentThemeLocator, _CurrentThemeDefaultValueFactory));

static Func<ElementTheme> _CurrentThemeDefaultValueFactory = () => { return ElementTheme.Default; };

#endregion

在初始化VM的時候,給其指派:

“Win10 UAP 開發系列”之主題模式切換

添加一個Command,輸入propcmd按Tab

///切換日間夜間模式

public CommandModel<ReactiveCommand, String> CommandSetCustomTheme

get { return _CommandSetCustomThemeLocator(this).Value; }

set { _CommandSetCustomThemeLocator(this).SetValueAndTryNotify(value); }

#region Property CommandModel<ReactiveCommand, String> CommandSetCustomTheme Setup

protected Property<CommandModel<ReactiveCommand, String>> _CommandSetCustomTheme = new Property<CommandModel<ReactiveCommand, String>> { LocatorFunc = _CommandSetCustomThemeLocator };

static Func<BindableBase, ValueContainer<CommandModel<ReactiveCommand, String>>> _CommandSetCustomThemeLocator = RegisterContainerLocator<CommandModel<ReactiveCommand, String>>("CommandSetCustomTheme", model => model.Initialize("CommandSetCustomTheme", ref model._CommandSetCustomTheme, ref _CommandSetCustomThemeLocator, _CommandSetCustomThemeDefaultValueFactory));

static Func<BindableBase, CommandModel<ReactiveCommand, String>> _CommandSetCustomThemeDefaultValueFactory =

model =>

var resource = "SetCustomTheme"; // Command resource

var commandId = "SetCustomTheme";

var vm = CastToCurrentType(model);

var cmd = new ReactiveCommand(canExecute: true) { ViewModel = model }; //New Command Core

cmd

.DoExecuteUIBusyTask(

vm,

async e =>

//Todo: Add SetCustomTheme logic here, or

await MVVMSidekick.Utilities.TaskExHelper.Yield();

if (vm.CurrentTheme == ElementTheme.Dark || vm.CurrentTheme == ElementTheme.Default)

vm.CurrentTheme = ElementTheme.Light;

else

vm.CurrentTheme = ElementTheme.Dark;

)

.DoNotifyDefaultEventRouter(vm, commandId)

.Subscribe()

.DisposeWith(vm);

var cmdmdl = cmd.CreateCommandModel(resource);

cmdmdl.ListenToIsUIBusy(model: vm, canExecuteWhenBusy: false);

return cmdmdl;

};

ElementTheme和ApplicationTheme是不同的,後者是App的屬性,前者可以應用于UIElement。是以可以把這個屬性綁定到根Grid上。

“Win10 UAP 開發系列”之主題模式切換

在頁面中加一個Button,Content設定為"切換主題",然後把Command綁定到CommandSetCustomTheme上

“Win10 UAP 開發系列”之主題模式切換

跑一下看看:

“Win10 UAP 開發系列”之主題模式切換
“Win10 UAP 開發系列”之主題模式切換

可以順利切換了,而且背景色和前景色也變成了我們設定的樣子,不是純黑純白了。

其實TextBlock和Button并沒有設定背景色前景色,都是繼承系統的,是以不用特别設定。其他的控件也一樣,如果需要特殊處理就自己添加樣式即可。

六、設定控件的style

順便說一下CustomStyleResources.xaml的作用,我建議把控件的樣式寫在這裡,覆寫系統預設的。比如可以把所有的Grid都更改一下背景色,就可以在這裡改,或者改全局Pivot的頭部margin之類的。

忘了最後附上源碼:

連結: http://pan.baidu.com/s/1mgFvXos 密碼: wnck

繼續閱讀