微软动作真是快,本来想写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来做,所以以后都会基于这个框架来做,顺便给@韦恩卑鄙 做下广告^_^

这个例子就叫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

“Win10 UAP 开发系列”之主题模式切换的更多相关文章

  1. “Win10 UAP 开发系列”之 在MVVM模式中控制ListView滚动位置

    这个扩展属性从WP8.1就开始用了,主要是为了解决MVVM模式中无法直接控制ListView滚动位置的问题.比如在VM中刷新了数据,需要将View中的ListView滚动到顶部,ListView只有一 ...

  2. Win10 UWP开发系列:使用VS2015 Update2+ionic开发第一个Cordova App

    安装VS2015 Update2的过程是非常曲折的.还好经过不懈的努力,终于折腾成功了. 如果开发Cordova项目的话,推荐大家用一下ionic这个框架,效果还不错.对于Cordova.PhoneG ...

  3. Win10 UWP 开发系列:使用多语言工具包让应用支持多语言

    之前我在一篇blog中写过如何使用多语言工具包,见http://www.cnblogs.com/yanxiaodi/p/3800767.html 在WinEcos社区也发布过一篇详细的文章介绍多语言工 ...

  4. Win10 UWP开发系列:解决Win10不同版本的Style差异导致的兼容性问题

    最近在开发一个项目时,遇到了一个奇怪的问题,项目依赖的最低版本是10586,目标版本是14393,开发完毕发布到商店后,很多用户报无法正常加载页面.经查,有问题的都是Win10 10586版本. 我上 ...

  5. Win10 UWP开发系列:实现Master/Detail布局

    在开发XX新闻的过程中,UI部分使用了Master/Detail(大纲/细节)布局样式.Win10系统中的邮件App就是这种样式,左侧一个列表,右侧是详情页面.关于这种 样式的说明可参看MSDN文档: ...

  6. Win10 UWP 开发系列:使用SplitView实现汉堡菜单及页面内导航

    在Win10之前,WP平台的App主要有枢轴和全景两种导航模式,我个人更喜欢Pivot即枢轴模式,可以左右切换,非常方便.全景视图因为对设计要求比较高,自己总是做不出好的效果.对于一般的新闻阅读类Ap ...

  7. Win10 UWP 开发系列:使用SQLite

    在App开发过程中,肯定需要有一些数据要存储在本地,简单的配置可以序列化后存成文件,比如LocalSettings的方式,或保存在独立存储中.但如果数据多的话,还是需要本地数据库的支持.在UWP开发中 ...

  8. Win10 UWP开发系列——开源控件库:UWPCommunityToolkit

    在开发应用的过程中,不可避免的会使用第三方类库.之前用过一个WinRTXamlToolkit.UWP,现在微软官方发布了一个新的开源控件库—— UWPCommunityToolkit 项目代码托管在G ...

  9. Win10 UWP 开发系列:支持异步的SQLite

    上篇文章已经实现了在UWP中使用SQLite作为本地存储,作为移动端的程序,及时响应用户的操作是提高用户体验的重要途径,因此UWP的很多api都是异步的.那么如何使SQLite支持异步呢? 参考SQL ...

随机推荐

  1. DeviceOne 让你一见钟情的App快速开发平台

    接触 DeviceOne 要从15年11月开始说起了,因项目和产品时间需求接触了快速开发平台,DeviceOne是非常棒的一个平台,双向数据绑定,可以自定义指令,过滤器等等.总之非常好用完全超出了我们 ...

  2. [nRF51822] 1、一个简单的nRF51822驱动的天马4线SPI-1.77寸LCD彩屏DEMO

    最近用nRF51822写了个天马4线SPI的1.77寸LCD彩屏驱动,效果如下: 屏幕的规格资料为:http://pan.baidu.com/s/1gdfkr5L 屏幕的驱动资料为:http://pa ...

  3. Java基础之泛型

    泛型: (1)为什么会出现泛型? 因为集合存放的数据类型不固定,故往集合里面存放元素时,存在安全隐患, 如果在定义集合时,可以想定义数组一样指定数据类型,那么就可以解决该类安全问题. JDK1.5后出 ...

  4. 缓存篇~第八回 Redis实现基于方法签名的数据集缓存~续(优化缓存中的key)

    返回目录 上一讲主要是说如何将数据集存储到redis服务器里,而今天主要说的是缓存里的键名,我们习惯叫它key. redis或者其它缓存组件实现的存储机制里,它将很多方法对应的数据集存储在一个公共的空 ...

  5. 第六节:Vue过滤器的用法和自定义过滤器

    1.过滤器的用法,用  '|' 分割表达式和过滤器. 例如:{{ msg |  filter}}     {{msg | filter(a)}}  a就标识filter的一个参数. 用两个过滤器:{{ ...

  6. Python中的魔法方法

    1.什么是魔法方法? 魔法方法就是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而这一 ...

  7. poj 1724ROADS(bfs和dfs做法)

    /* dfs比较好想,就是测试数据的问题,导致在遍历边的时候要倒着遍历才过! */ #include<iostream> #include<cstdio> #include&l ...

  8. Zookeeper-Zookeeper leader选举

    在上一篇文章中我们大致浏览了zookeeper的启动过程,并且提到在Zookeeper的启动过程中leader选举是非常重要而且最复杂的一个环节.那么什么是leader选举呢?zookeeper为什么 ...

  9. Cocos2d-x 3.2学习笔记(三)学习绘图API

    关于cocos2d-x 3.2 版本的绘图方法有两种 1.使用DrawNode类绘制自定义图形. 2.继承Layer类重写draw()方法. 以上两种方法都可以绘制自定义图形,根据自己的需要选择合适的 ...

  10. [OpenCV] Samples 06: [ML] logistic regression

    logistic regression,这个算法只能解决简单的线性二分类,在众多的机器学习分类算法中并不出众,但它能被改进为多分类,并换了另外一个名字softmax, 这可是深度学习中响当当的分类算法 ...