转载

“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

打开这个文件,可以看到里面存放的是系统默认的主题样式。

顺便说一下,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

/// <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上。

“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

正文到此结束
Loading...