Windows 8.1 store app 开发笔记

时间:2023-03-08 18:19:30

原文:Windows 8.1 store app 开发笔记

零、简介

  一切都要从博彦之星比赛说起。今年比赛的主题是使用Bing API(主要提到的有Bing Map API、Bing Translate API和Bing AD API)设计移动应用(Windows store app和Windows phone app)。从7月初开始设计到现在,应用的功能已经基本完成,就差美工来给界面优化一下。下面是我设计的应用的功能和实现的方法,

一、BING MAP API

  作为一个以Bing Map API为主的应用,主要有以下的功能:

  1、定位:

 private LocationRange range = null;
private CancellationTokenSource cts = null;
private Geolocator geolocator = null; private async void locateButton_Click(object sender, RoutedEventArgs e)
{
// 根据定位按钮的标签判定是“定位”或“取消定位”
if (locateButton.Label == "定位")
{
locateButton.Label = "取消定位";
try
{
// 获得cancellation token
cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
this.infoBlock.Text = "正在定位"; // 获得位置
Geoposition pos = await geolocator.GetGeopositionAsync().AsTask(token);
this.infoBlock.Text = "定位成功";
// App.location是在App.xaml.cs中用于保存定位位置的全局变量
App.location = new Location(pos.Coordinate.Point.Position.Latitude, pos.Coordinate.Point.Position.Longitude); // 设置默认地图缩放等级
double zoomLevel = 13.0f;
// range是一个自定义控件,用一个大圆来涵盖定位区域
MapLayer.SetPosition(range, App.location);
rangeLayer.Children.Add(range);
zoomLevel = 15.0f; // 设置地图视野到给定的位置和缩放等级
map.SetView(App.location, zoomLevel);
}
catch (System.UnauthorizedAccessException)
{
this.infoBlock.Text = "定位请求被拒绝";
}
catch (TaskCanceledException)
{
this.infoBlock.Text = "定位被取消";
}
catch (System.Exception)
{
this.infoBlock.Text = "暂时无法获得您的位置";
}
finally
{
cts = null;
}
// 重置按钮
locateButton.Label = "定位";
//locateButton.Icon = ;
}
else
{
// 取消定位
if (cts != null)
{
cts.Cancel();
cts = null;
}
// 重置按钮
locateButton.Label = "定位";
//locateButton.Icon = ;
}
}

locateButton_Click

  2、添加图钉:

 private async void AddPinButton_Click(object sender, RoutedEventArgs e)
{
// 实例化一个图钉类(这个图钉类是我自定义的)
pin = new MapediaPin(map);
// 为图钉添加Drag和Tap触发方法(当然还有Hold等)
pin.drag += pin_Dragged;
pin.Tapped += pin_Tapped;
//将图钉显示到地图的*
MapLayer.SetPosition(pin, map.Center);
pinLayer.Children.Add(pin);
}

AddPinButton_Click

  3、拖动图钉:

 private bool isDragging = false;        // pin正在拖拽标志

         // 当pin被拖动时激活
public Action<Location> drag;
// 当pin开始被拖动时激活
public Action<Location> dragStart;
// 当pin停止拖动时激活
public Action<Location> dragEnd;
// 当pin被按下时,得到被按下pin的ID,判断是否可拖动,执行操作
protected override void OnPointerPressed(PointerRoutedEventArgs e)
{
base.OnPointerPressed(e); // 如果可以被拖动则开始拖动
if (draggable)
{
if (map != null)
{
center = map.Center;
// 为map的下列方面重写
map.ViewChanged += map_ViewChanged;
map.PointerReleasedOverride += map_PointerReleased;
map.PointerMovedOverride += map_PointerMoved;
}
// 得到当前鼠标位置
var pointerPosition = e.GetCurrentPoint(map);
Location location = null;
// 开始拖动
if (dragStart != null)
{
dragStart(location);
} this.isDragging = true;
}
} // 当pin被移动时
private void map_PointerMoved(object sender, PointerRoutedEventArgs e)
{
// 检查是否正在被拖动
if (this.isDragging)
{
// 随着鼠标移动图标
var pointerPosition = e.GetCurrentPoint(map); Location location = null; if (map.TryPixelToLocation(pointerPosition.Position, out location))
{
// 将图钉(this)移到到当前鼠标的位置(location)
MapLayer.SetPosition(this, location);
}
if (drag != null)
{
drag(location);
}
}
} // 当pin被松开时
private void map_PointerReleased(object sender, PointerRoutedEventArgs e)
{
if (this.isDragging)
{
if (map != null)
{
map.ViewChanged -= map_ViewChanged;
map.PointerReleasedOverride -= map_PointerReleased;
map.PointerMovedOverride -= map_PointerMoved;
} var pointerPosition = e.GetCurrentPoint(map);
Location location;
map.TryPixelToLocation(pointerPosition.Position, out location);
// 得到最终的经纬度
latitude = location.Latitude;
longitude = location.Longitude; location = null; if (dragEnd != null)
{
dragEnd(location);
} this.isDragging = false;
this.draggable = false;
}
}

PinDrag

二、BING TRANSLATE API

  用的这个API的地方,是在对图钉上面的信息进行翻译的时候:

  翻译:

 private HttpClient client = null;            // 用于通信的HTTP客户端

         private async void translateButton_Click(object sender, RoutedEventArgs e)
{
// 根据translateButton的标签判定是“翻译”或“取消翻译”
if (translateButton.Label == "翻译")
{
// 进行网络检查(方法见 五、UTILITIES)
if (!App.CheckNetwork())
{
//this.infoBlock.Text = "无网络连接,请检查网络";
}
else
{
try
{
this.infoBlock.Text = "正在检查网络连接...";
string clientID = "你的clientID";
string clientSecret = "你的clientSecret";
//AzureDataMarket可以从网上找到,是一个已经写好的用于在Azure进行验证的类
var _Authentication = new AzureDataMarket(clientID, clientSecret);
AzureDataMarket.Token m_Token = await _Authentication.GetTokenAsync();
string auth = m_Token.Header;
//实例化该类,以便于后面发送Http请求获取网络数据
client = new HttpClient();
//设置读取响应内容时缓冲区的最大字节数
client.MaxResponseContentBufferSize = ;
//设置请求头部
client.DefaultRequestHeaders.Add("Authorization", auth);
}
catch
{
//this.infoBlock.Text = "连接到服务器失败";
}
}
}
else
{
this.translateButton.Label = "翻译";
}
} // 将descriptionBlock中的内容翻译成language所表示的语言
private async void translate(String language)
{
//language可表示的语言:ar bg ca zh-CHS zh-CHT cs da nl en et fi fr de el ht he hi mww hu id it ja tlh tlh-Qaak ko lv lt ms mt no fa pl pt ro ru sk sl es sv th tr uk ur vi
string url = "http://api.microsofttranslator.com/v2/Http.svc/Translate?text=" + System.Net.WebUtility.UrlEncode(this.descriptionBlock.Text) + "&to=" + language;
//try
{
string strTranslated = await client.GetStringAsync(url);
XDocument xTranslation = XDocument.Parse(strTranslated);
string strTransText = xTranslation.Root.FirstNode.ToString();
this.titleTranslateBlock.Text = strTransText; this.translateButton.Label = "取消翻译";
}
//catch (Exception ex)
{
// this.infoBlock.Text = "不能访问Bing Translate API,错误原因:" + ex.Message.ToString();
} }
// 当englishButton按下时,翻译成英语
private void englishButton_Click(object sender, RoutedEventArgs e)
{
translate("en");
}
// 当simChineseButton按下时,翻译成简体中文
private void simChineseButton_Click(object sender, RoutedEventArgs e)
{
translate("zh-CHS");
}

translateButton_Click

三、BING AD API

  待应用......

四、LIVE SDK

  1、登入和登出live帐号:

             // live SDK使用范围:登入、获得用户基本信息、使用onedrive上传功能
private readonly string[] scopes = new string[] {
"wl.signin", "wl.basic", "wl.photos", "wl.skydrive", "wl.skydrive_update"};
private LiveAuthClient authClient = null;
private LiveConnectClient liveClient = null; private void loginButton_Click(object sender, RoutedEventArgs e)
{
// 根据loginButton判定是“登入”或“登出”
if (this.loginButton.Label == "登出")
{
this.authClient.Logout();
this.loginButton.Label = "Live帐号登入";
this.loginBlock.Text = "未登入";
}
else
{
login();
}
} private async void login()
{
try
{
this.loginButton.IsEnabled = false; this.authClient = new LiveAuthClient();
this.loginBlock.Text = "登入中";
// 登入时显示进度的进度环
this.loginProgress.IsActive = true;
// 检验网络状态
if (App.CheckNetwork())
{
// 得到登入结果
LiveLoginResult loginResult = await this.authClient.LoginAsync(this.scopes);
if (loginResult.Status == LiveConnectSessionStatus.Connected)
{
App.Session = loginResult.Session;
this.liveClient = new LiveConnectClient(loginResult.Session);
LiveOperationResult operationResult = await this.liveClient.GetAsync("me"); // 当用户登入后
dynamic meResult = operationResult.Result;
this.loginButton.Label = "登出";
if (meResult.first_name != null && meResult.last_name != null)
{
//显示用户的登录信息
this.loginBlock.Text = "欢迎! " + meResult.first_name + " " + meResult.last_name;
}
else
{
this.loginBlock.Text = "欢迎! ";
}
}
else
{
this.loginBlock.Text = "未登入";
}
}
else
{
this.infoBlock.Text = "无网络连接,请检查网络";
this.loginBlock.Text = "未登入";
}
}
catch (LiveAuthException)
{
this.infoBlock.Text = "登入请求被拒绝";
}
finally
{
// CanLogout为false的情况:应用使用windows已登入的账号时
if (this.loginButton.Label == "登出" && this.authClient != null && !this.authClient.CanLogout)
{
this.loginButton.IsEnabled = false;
}
else
{
this.loginButton.IsEnabled = true;
}
this.loginProgress.IsActive = false;
}
}

loginButton_Click

  2、上传图片至OneDrive:

 private async void syncButton_Click(object sender, RoutedEventArgs e)
{
// App.Session是用来记录当前登入账户的一次会话,登入live帐号之后产生
if (App.Session != null)
{
// 得到本地的photo文件夹
IReadOnlyList<StorageFolder> folders = await App.photosFolder.GetFoldersAsync();
// 在Onedrive中新建一个文件夹,名字为“新建文件夹”
string skyDriveFolder = await CreateDirectoryAsync("新建文件夹", "me/skydrive");
// 对photo文件夹中的子文件夹进行遍历
foreach (StorageFolder folder in folders)
{
// 获得子文件夹下的所有文件
IReadOnlyList<StorageFile> files = await folder.GetFilesAsync();
foreach (StorageFile file in files)
{
// 将文件上传
LiveOperationResult result = await liveClient.BackgroundUploadAsync(skyDriveFolder, file.DisplayName + ".jpg", file, OverwriteOption.Overwrite);
}
}
}
} private async Task<string> CreateDirectoryAsync(string folderName, string parentFolder)
{
string folderId = null;
// 查询OneDrive中是否含有folderName文件夹
var queryFolder = parentFolder + "/files?filter=folders,albums";
var opResult = await liveClient.GetAsync(queryFolder);
dynamic result = opResult.Result; foreach (dynamic folder in result.data)
{
// 如果存在这个文件夹,则返回文件夹名
if (folder.name == folderName)
{
folderId = folder.id;
break;
}
} if (folderId == null)
{
// 不存在则创建
var folderData = new Dictionary<string, object>();
folderData.Add("name", folderName);
opResult = await liveClient.PostAsync(parentFolder, folderData);
result = opResult.Result;
folderId = result.id;
} return folderId;
}

syncButton_Click

五、微博 SDK

  1、连接微博帐号:

 private void shareButton_Click(object sender, RoutedEventArgs e)
{
// 检查网络状态
if (App.CheckNetwork())
{
// 检查该应用是否已和微博连接
if (App.oauthClient.IsAuthorized == false)
{
App.oauthClient.LoginCallback += (isSucces, err, response) =>
{
if (isSucces) // 如果成功
{
// TODO: deal the OAuth result.
}
else
{
this.titleBox.Text = err.errMessage;
}
};
App.oauthClient.BeginOAuth(); // 开始验证
}
}
else
{
// no internet.
}
if (App.oauthClient.IsAuthorized == true) // 验证成功,开始分享
{
// TODO SHARE
}
else
{
this.titleBox.Text = "验证失败";
}
}

shareButton_Click

  2、发布(带图片)微博

 private async void shareWithPhoto(String path)
{
var engine = new SdkNetEngine();
// 微博sdk提供的方法,实例化一个cmd类
ISdkCmdBase cmdBase = new CmdPos MsgWithPic()
{
// 发布的文本消息
Status = shareTextBox.Text,
// 发布的图片绝对路径
PicPath = path
};
// 发布微博
var result = await engine.RequestCmd(SdkRequestType.POST_MESSAGE_PIC, cmdBase); if (result.errCode == SdkErrCode.SUCCESS)
{
// 发布成功
}
// 发布失败
else
{
// TODO: deal the error.
// 失败的状态码
switch (result.errCode)
{
case SdkErrCode.NET_UNUSUAL: this.descriptionBox.Text = "NET_UNUSUAL"; break;
case SdkErrCode.SERVER_ERR: this.descriptionBox.Text = "SERVER_ERR"; break;
case SdkErrCode.TIMEOUT: this.descriptionBox.Text = "TIMEOUT"; break;
case SdkErrCode.USER_CANCEL: this.descriptionBox.Text = "USER_CANCEL"; break;
case SdkErrCode.XPARAM_ERR: this.descriptionBox.Text = "XPARAM_ERR"; break;
}
this.descriptionBox.Text = result.specificCode;
}
}

shareWithPhoto

六、UTILITIES

  1、检查网络状态

 public static Boolean CheckNetwork()
{
bool isOnline = false;
//获得当前的网络连接状态(using Windows.Networking.Connectivity
ConnectionProfile connectionProfile = NetworkInformation.GetInternetConnectionProfile(); if (connectionProfile == null)
{
//TODO No net work
}
else
{
isOnline = true;
}
return isOnline;
}

CheckNetwork

  2、向服务器post请求(服务器端我用的是Servlet+Tomcat+MySQL来接收和处理)

 private readonly static String url = "请求地址";

         private static async Task<string> postData(String data)
{
String result = String.Empty;
// 设置字符编码
Encoding encoding = Encoding.UTF8;
// 将请求的数据转换为字节流
Byte[] bytes = encoding.GetBytes(data);
// 实例化请求对象,有多种请求对象可以使用
WebRequest req = WebRequest.Create(url);
// 请求方式和类型
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
using (Stream outputStream = await req.GetRequestStreamAsync())
{
// 发送字节流信息
outputStream.Write(bytes, , bytes.Length);
}
using (WebResponse webResponse = await req.GetResponseAsync())
{
// 得到响应信息
StreamReader sr = new StreamReader(webResponse.GetResponseStream());
result = sr.ReadToEnd();
} return result;
}

七、总结

  第一次上手C#和xaml,而且是在这略浩大的工程中(对我而言),在开发过程中不免会遇到各种困难,当然也积累了各种经验。经历了多次Visual Studio 2013的安装(从Update1到Update3,从vs安装时写临时文件夹拒绝访问到designer安装失败),各种神奇的、离奇的失败最后都在谷歌和MSDN上找到了答案,也锻炼了我查找和阅读答案的能力。希望以上我的分享能给刚上手win8 app开发的同行们减轻一些查api(当然api也是要仔细看的)查谷歌的负担,共同进步。