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


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

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

切換日間、夜間主題模式這個功能我從WP8就實現了,並封裝成了一個庫,用在我所有的WP8app里。到了WP8.1因為系統主題樣式都改了,又重寫了一遍。還沒來得及整理寫blogWin10的樣式又改了……吐槽不完啊簡直。不過思路都是一樣的,現在以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來做,所以以后都會基於這個框架來做,順便給@韋恩卑鄙 做下廣告^_^

這個例子就叫ThemeDemo。確定。

等待框架程序創建完成。

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

二、添加默認主題

用VS2015RC打開剛才找到的系統默認樣式文件,如圖:

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

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

在項目中添加一個名為CustomTheme的文件夾。

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

新建兩個xaml文件,命名為ThemeResourcesDark.xaml和ThemeResourcesLight.xaml,根節點這樣寫:

然后把系統樣式文件里有關Color和Brush的部分復制過來,Default對應Dark,Light對應Light。

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

我還添加了一套FlatUI的顏色資源,FlatUIColorsResources.xaml,里面存放了各種Flat風格的Color和Brush來方便使用。

三、引入自定義樣式資源

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

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

四、修改自定義樣式

現在運行程序,樣子是默認的,還是白底黑字。因為RequestedTheme="Light"

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

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

然后去ThemeResourcesLight.xaml文件里找這個資源,改一下顏色:

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

然后跑一下:

好了背景色已經變了,不再是純白了。然后可以繼續改前景色、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的時候,給其賦值:

添加一個Command,輸入propcmd按Tab

/// <summary>

///切換日間夜間模式

/// </summary>

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;

};

#endregion

 

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

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

跑一下看看:

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

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

六、設置控件的style

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

 

忘了最后附上源碼:

鏈接: http://pan.baidu.com/s/1mgFvXos 密碼: wnck


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com