Windows 8 已经正式发布了,有人说好,也有人说不好。但是不管怎样, Windows 8 肯定会有大量的用户。作为程序员,当然又得学习新的东西了,俺也不例外啊。
Windows 8的传统界面跟Windows 7 没有太大区别,区别大的就是Metro风格了(现在好像叫做Modern UI了吧)。
根据MSDN上的说法,开发Metro程序有三种方式:
1. HTML + JavaScript
2. C#/VB + XAML
3. C++ + XAML/DirectX
个人觉得如果Metro App里面UI部分比较多的话,采用第一种或者第二种比较好,不太推荐C++, 当然如果App里面比较涉及底层的话,还是C++。
我先选择HTML + JavaScript来学习开发Metro程序。第一次开发Metro,错误在所难免,各位大哥不要笑话啊。
MSDN上面已经有很详细的说明了:http://msdn.microsoft.com/zh-cn/library/windows/apps/br211385.aspx。这里主要是为了记录一下我自己的学习过程。
先从最最简单的Blank App开始,用VS2012创建一个JavaScript Windows store 应用程序,选择Blank App模板,如下图。
随后,VS就生成了一个模板代码。主要有3个文件:default.css, default.js, default.html.
这也就是HTML + JavaScript开发Metro应用程序的3个重要组成部分:
1. css文件: 用来协助HTML文件布局UI;
2. HTML文件:处理UI;
3. js文件:程序的代码。
对于做过Web开发的程序员来说,可以很快的用javascript做一个Metro小应用。因为CSS, HTML 和javascript在web开发里面太常见了。
接下来,我用javascript来模拟一个小应用吧,就模拟做一个登录页面。比如:
很简单,就居中放一个登录框。我用default.js, default.css, default.html来处理这个对话框。
先来看看default.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>App1</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<!-- App1 references -->
<link href="/css/default.css" rel="stylesheet" />
<script src="/js/default.js"></script>
</head>
<body>
<div id="logging">
<div class="row" style="margin-top:50px">
Username: <input id="TextUserName" type="text" style="width:150px"/>
</div>
<div class="row">
Password: <input id="TextPassword" type="password" style="width:150px"/>
</div>
<div class="row" style="margin-top:20px;margin-left:50px">
<button type="button" id="login" style="position:relative">Login</button>
<button type="button" id="register" style="position:relative">Register</button>
</div>
<div class="row" style="margin-top:20px;margin-left:50px">
<p id="hint"></p>
</div>
</div>
</body>
</html>
其中<div id="logging"></div>,这部分就是用来显示登录框的。相当的简单啊,这个对于做过web开发的程序员来说简直是小菜一碟,呵呵。
看看相应的css:
body {
}
@media screen and (-ms-view-state: fullscreen-landscape) {
}
@media screen and (-ms-view-state: filled) {
}
@media screen and (-ms-view-state: snapped) {
}
@media screen and (-ms-view-state: fullscreen-portrait) {
}
#logging {
border: 2px solid #C0C0C0;
background-color: #008080;
font-family: 黑体;
font-size: 20px;
position: fixed;
width: 300px;
height: 300px;
top: 50%;
left: 50%;
margin-left: -150px;
margin-top: -150px;
}
.row {
width: 260px;
height: auto;
margin-left:10px;
}
我就加了一个id和一个class,其中id logging里面,为了把登录框居中显示,用了一个小技巧,就是top和left都是50%,这样左上角的位置就是屏幕中心,然后margin-left, margin-top用了一个负数,也就是宽度和高度的一半。这样就相当于登录框的中心点在屏幕的中心了。这样办法使用于任何屏幕分辨率。
OK, 接下来就看看代码:
// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
"use strict";
WinJS.Binding.optimizeBindingReferences = true;
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll().done(function () {
AddEvents();
}));
}
};
app.oncheckpoint = function (args) {
// TODO: This application is about to be suspended. Save any state
// that needs to persist across suspensions here. You might use the
// WinJS.Application.sessionState object, which is automatically
// saved and restored across suspension. If you need to complete an
// asynchronous operation before your application is suspended, call
// args.setPromise().
};
WinJS.UI.Pages.define("/default.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
// TODO: Initialize the page here.
AddEvents();
var appData = Windows.Storage.ApplicationData.current;
var roamingSettings = appData.roamingSettings;
var username = document.getElementById("TextUserName");
var str = roamingSettings.values["username"];
username.value = str;
},
});
// The click event handler for login
function Login(mouseEvent) {
window.navigate("pagecontrol.html");
// WinJS.Navigation.navigate("pagecontrol.html");
}
function Register(mouseEvent) {
var hint = document.getElementById("hint");
var username = document.getElementById("TextUserName");
var pwd = document.getElementById("TextPassword");
hint.innerText = "username:" + username.value + "\npassword:" + pwd.value;
}
function nameInputChanged(eventInfo) {
var ele = eventInfo.srcElement;
var appData = Windows.Storage.ApplicationData.current;
var roamingSettings = appData.roamingSettings;
roamingSettings.values["username"] = ele.value;
// WinJS.Application.sessionState.UserName = ele.value;
}
function AddEvents() {
var login = document.getElementById("login");
login.addEventListener("click", Login, false);
var register = document.getElementById("register");
register.addEventListener("click", Register, false);
var username = document.getElementById("TextUserName");
username.addEventListener("change", nameInputChanged);
}
app.start();
})();
增加一个函数function AddEvents(),这个函数用来给按钮设置响应函数。那么我们在什么地方调用这个函数呢?
1. 在app.onactivated里面,这样等于app激活的时候就设置按钮的响应函数;
2. 但是这里好像有个问题,对于app中有多个页面的时候,app.onactivated不会调用多次。比如切换到第二个页面,那么第二个页面的按钮的响应函数什么时候设置呢?我们可以使用ready成员函数,如:
WinJS.UI.Pages.define("/default.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
// TODO: Initialize the page here.
AddEvents();
});
我还不是很确定ready函数是页面开始加载前调用,还是页面已经加载完了再被调用?这个还得进一步确认。
注意,JavaScript的匿名函数的第一行代码, "use strict",这个意思是使用strict(严格)模式,MSDN上是这么解释的:
Strict mode is a way to introduce better error-checking into your code. When you use strict mode, you cannot, for example, use implicitly declared variables, or assign a value to a read-only property, or add a property to an object that is not extensible. The restrictions are listed in the Restrictions on Code in Strict Mode section later in this topic.
ok,这个例子里面有2个按钮,登录和注册,注册就简单显示一条信息。登录的话,就是切换到第二个页面。
那么如何添加一个新的页面呢?也是很简单,在vs向导就可以了,如:
我们只有增加一个PageControl就行了,然后VS就会自动生成3个文件:css,html,js。
注意上面登录按钮里面是如何切换到第二个页面的,我这里使用window.navigate("pagecontrol.html");来切换到第二个页面。其实这个地方有好几种办法,web开发里面的js跳转页面的方法基本都可以用。而且微软自己好像也封装了一些办法,这个不在这里探讨了。
第二个页面很简单,就放了个返回登录页面的链接:
怎么实现的呢,太简单了,就用了一个html超链接:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>pagecontrol</title>
<!-- WinJS references -->
<link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
<link href="/css/pagecontrol.css" rel="stylesheet" />
<script src="/js/pagecontrol.js"></script>
</head>
<body>
<div class="pagecontrol fragment" style="text-align:center">
<header aria-label="Header content" role="banner">
<button class="win-backbutton" aria-label="Back" disabled type="button"></button>
<h1 class="titlearea win-type-ellipsis">
<span class="pagetitle">Second page</span>
</h1>
</header>
<a href="/default.html">return to "login page"</a>
</div>
</body>
</html>
就是这一行:<a href="/default.html">return to "login page"</a>,其他什么也没做,cool。
ok,再介绍一下数据存储。我们可以使用2种对象:
1. Windows.Storage.ApplicationData.current.roamingSettings
2. WinJS.Application.sessionState
第一种是“永久”存储,就是说就算应用退出了,数据还是存在的。
第二种就是临时的了MSDN上的说法是:
会话数据为临时数据,它与应用中用户的当前会话相关。会话会在以下情形下结束:用户使用关闭手势或 Alt + F4 关闭应用、重新启动计算机或注销计算机。
上面的例子里面使用了第一种“永久”存储。使用也是相当的简单,通过这些对象,我们可以把应用的状态保存起来,然后在某种情况下恢复,比如把应用从后台迁到前台。
先学习到这里,下一次来看看“应用栏”的使用。