[开源,学习,分享]UWP第三方简书客户端分享
简介
Windows10正式版发布到现在,我利用零零碎碎的一些时间对UWP进行一些学习,也基于这门技术开发了一个第三方的简书App.
基本界面
优酷视频:
http://v.youku.com/v_show/id_XMTM2MjU4MjI4NA==.html
基本功能
- 客户端采用了UWP的技术,所以支持x86,x64,ARM平台,采用了响应式的布局.对手机进行了部分的优化.
- 对SQLite和本地存储进行了封装,支持缓存.
缓存支持同步和异步的两种方式,分别实现了两个接口:
internal interface IStorage
{
void AddItem(string key, object value);
void UpdateItem(string key, object value);
bool ContainItem(string key);
void FlushAll();
T GetItem<T>(string key) where T : class;
List<T> GetItems<T>(string key) where T : class;
bool RemoveItem(string key);
long GetSize();
}interface IStorageAsync
{
Task AddItemAsync(string key, object value);
Task UpdateItemAsync(string key, object value);
Task<bool> ContainItemAsync(string key);
Task FlushAllAsync();
Task<T> GetItemAsync<T>(string key) where T : class;
Task<List<T>> GetItemsAsync<T>(string key) where T : class;
Task<bool> RemoveItemAsync(string key);
long GetSize();
}通过Key和Value的方式实现增减删改.
- 简单的封装了新浪微博的分享图片和文字的功能,可以在Config.cs文件中加入你自己的key和secret.
public async Task<WeiboResult> ShareTextAsync(string text)
{
if (text == null)
{
throw new ArgumentNullException(nameof(text));
} if (string.IsNullOrWhiteSpace(text))
{
throw new ArgumentException("Text could not be empty", nameof(text));
} if (!UserInfo.CheckUseable())
{
string authorizeCode = await this.GetAuthorizeCodeAsync();
await this.Authorize(authorizeCode);
} Uri uri = new Uri("https://api.weibo.com/2/statuses/update.json"); Dictionary<string, string> pairs = new Dictionary<string, string>();
pairs.Add("access_token", UserInfo.Token);
pairs.Add("status", text); HttpFormUrlEncodedContent content = new HttpFormUrlEncodedContent(pairs); using (HttpClient client = new HttpClient())
{
HttpResponseMessage response;
try
{
response = await client.PostAsync(uri, content);
}
catch (Exception ex)
{
throw new Exception("Network error", ex);
}
return await response.Content.ReadAsJsonAsync<WeiboResult>();
}
} public async Task<WeiboResult> ShareImageAsync(byte[] image, string text)
{
if (image == null)
{
throw new ArgumentNullException(nameof(image));
} if (text == null)
{
throw new ArgumentNullException(nameof(text));
} if (string.IsNullOrWhiteSpace(text))
{
throw new ArgumentException("Text could not be empty", nameof(text));
} if (!UserInfo.CheckUseable())
{
string authorizeCode = await this.GetAuthorizeCodeAsync();
await this.Authorize(authorizeCode);
} Uri uri = new Uri("https://upload.api.weibo.com/2/statuses/upload.json"); HttpBufferContent bufferContent = new HttpBufferContent(image.AsBuffer()); HttpMultipartFormDataContent content = new HttpMultipartFormDataContent(); content.Add(new HttpStringContent(UserInfo.Token), "access_token");
content.Add(new HttpStringContent(text), "status");
content.Add(bufferContent, "pic", "pic.jpg"); using (HttpClient client = new HttpClient())
{
HttpResponseMessage response;
try
{
response = await client.PostAsync(uri, content);
}
catch (Exception ex)
{
throw new Exception("Network error", ex);
}
return await response.Content.ReadAsJsonAsync<WeiboResult>();
}
}
- 添加了对异步线程错误的处理和对异步Command的支持.
异步线程的处理我在上一篇《讲讲我在Windows10(uwp)开发中遇到的一些坑》已经说过了.这里说下贴一下异步Command的代码:
public class AsyncCommand : AsyncCommandBase
{
private readonly Func<Task> command;
public AsyncCommand(Func<Task> command)
{
this.command = command;
}
public override bool CanExecute(object parameter)
{
return true;
}
public override Task ExecuteAsync(object parameter)
{
return command();
}
}
- 支持下拉刷新和加载更多(但还有Bug).
对于UWP的下拉刷新,我在博客园里看到了几种实现方式:
只贴了一种,因为目前实现下拉刷新的方式都是ListView外部套一个ScrollViewer来实现,这种实现方式有个严重的问题就是:ListView内部也是有一个ScrollViewer,当滑动的时候,会出现ListView内部的ScrollViewer被压缩,这样直接导致了下拉刷新的失败.
我这里思考了另一种方式,就是对ListView内部的ScrollViewer进行操作.
<ScrollViewer Margin="0,0,0,-100" RenderTransformOrigin="0.5,0.5" x:Name="ScrollViewer" AutomationProperties.AccessibilityView="Raw" BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}" IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" TabNavigation="{TemplateBinding TabNavigation}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
<ScrollViewer.RenderTransform>
<CompositeTransform TranslateY="-100" />
</ScrollViewer.RenderTransform>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Height="{TemplateBinding RefreshHeaderHeight}" x:Name="PullToRefreshIndicator" Background="Transparent">
<Grid HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid Width="40">
<Viewbox x:Name="Arrow" Height="15" VerticalAlignment="Top" Margin="0,4,0,0" RenderTransformOrigin="0.5,0.5">
<Viewbox.RenderTransform>
<CompositeTransform Rotation="180" />
</Viewbox.RenderTransform>
<Image Source="ms-appx:///Assets/arrow.png" Width="12" Height="12.9999"/>
<!--<Path
Width="12"
Height="12.9999"
Stretch="Fill"
Fill="{TemplateBinding ArrowColor}"
Data="M 20.4289,10.4376L 25,15.0087L 23.571,16.4376L 20.0291,12.8957L 20.0291,21.9999L 18.0083,21.9999L 18.0083,12.8583L 14.4289,16.4377L 13,15.0087L 17.5624,10.429L 19.0087,9" />-->
</Viewbox>
</Grid>
<TextBlock Grid.Column="1" x:Name="PullPart" Text="{TemplateBinding PullPartTemplate}"/>
<TextBlock Grid.Column="1" Visibility="Collapsed" x:Name="ReleasePart" Text="{TemplateBinding ReleasePartTemplate}"/>
</Grid>
</Border>
<ItemsPresenter FooterTransitions="{TemplateBinding FooterTransitions}" FooterTemplate="{TemplateBinding FooterTemplate}"
Footer="{TemplateBinding Footer}" HeaderTemplate="{TemplateBinding HeaderTemplate}" Header="{TemplateBinding Header}"
HeaderTransitions="{TemplateBinding HeaderTransitions}" Padding="{TemplateBinding Padding}" Grid.Row="1"/>
</Grid>
</ScrollViewer>对内部的ScrollViewer的压缩进行操作,这样能够比较精准的获取用户的下拉.
同时我已经把这个代码封装成一个单独的控件,你可以从下面的链接获取到源码:
https://github.com/youngytj/uwp_PullToRefreshListview
使用方式只要在xaml里添加如下代码即可使用:
<local:PullToRefreshListView x:Name="lv"
PullPartTemplate="Pull" ReleasePartTemplate="Release"
RefreshContent="lv_RefreshContent" MoreContent="lv_MoreContent"/>PullPartTemplate和ReleasePartTemplate分别是下拉和释放时候的文字.然后后面是更新和加载更多时候的事件.
- 使用了MVVMLight,所有的界面都以嵌入的方式放入MainPage中.
MainPage里面通过ContentControl的来绑定内容
<ContentControl Content="{Binding CurrentViewModel}" ContentTemplate="{Binding Path=CurrentTemplate}"
HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"/>View和ViewModel的绑定放在了App.xaml
<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator"/>
<DataTemplate x:Key="HomeViewModel">
<view:HomeView/>
</DataTemplate>
...
</Application.Resources>这里有个注意的地方就是View只是作为一个资源的方式存在,当MainPage中发生页面转换时,会将ViewModel的名字作为一个Key(所以类名必须是Key)来寻找View.
public static class DataTemplateSelector
{
public static DataTemplate GetTemplate(ViewModelBase param)
{
Type t = param.GetType();
if(!views.ContainsKey(t.Name))
{
views.Add(t.Name, App.Current.Resources[t.Name] as DataTemplate);
} return views[t.Name];
}
}
开源地址
没有上传到市场,因为我这边网络一直上载不了包,如果网络环境好了以后再考虑上传,下面是Github的源码地址:
写在最后
并不是很看好微软这种实现跨平台.除了目前UWP这门技术的不成熟,包括很多的缺失,诸如异步线程的处理问题,缺少对移动端的滑动的支持(不像android一样可以从底层开始实现一个行云流水般的手势操作,还有就是ScrollViewer依然存在之前的问题.),还有就是对于微软的这种跨平台的方式,我支持这种看法--因为硬件设备和运行环境的不同带来的用户体验的不同,才是跨平台最大的障碍!这一障碍,不是任何一个“技术”或“技术提供商”可以解决的!.总体来说,因为是全新的平台,相应的开源组件比较少,上手还需要一些时间来熟悉这个平台,平台的不足之处也需要自己从无到有.
这个客户端其实还有很多不好的地方,比如对于异步线程启动关闭的控制不足,缺少log,缺少对于缓存的系统的管理,还有导航系统的不足,不同网络的环境下的客户端优化的问题.但是我认为仅仅作为一个研究学习的项目,已经足够了.如果你喜欢或者支持这样的项目,帮忙点个推荐吧.
以上,说完.谢谢.
[开源,学习,分享]UWP第三方简书客户端分享的更多相关文章
- swift调用oc语言文件,第三方库文件或者自己创建的oc文件——简书作者
Swift是怎样调用OC的第三方库的呢?请看下面详情: 情况一: 1.首先打开Xcode,iOS->Application->Single View Application, 选Next. ...
- 抽空通过简书网学习了一下console,感觉高大上!
抽空看了一下简书中关于console的文章,为了便于自己今后查看,自己写了一遍!原文地址:http://www.jianshu.com/p/f961e1a03a56 测试代码在最下面 1.consol ...
- 仿简书分享:UIActivityViewController系统原生分享
接下来介绍UIActivityViewController: 1. 创建要分享的数据内容,加在一个数组 ActivityItems里. NSString *textToShare = @"我 ...
- 文字创作类App分享-简书
今天我用Mockplus做了一套简书App的原型,这是一款文字创作类的App,用户通过写文.点赞等互动行为,提高自己在社区的影响力,打造个人品牌.我运用了Mockplus基础组件.交互组件.移动组件等 ...
- .Net Core身份认证:IdentityServer4实现OAuth 2.0 客户端模式 - 简书
原文:.Net Core身份认证:IdentityServer4实现OAuth 2.0 客户端模式 - 简书 一.客户端模式介绍 客户端模式(Client Credentials Grant)是指客户 ...
- AI时代学习新的技术,方向为计算机视觉--欢迎来我的简书blog拔草
2017-09-01 19:29:33 简书blog: https://www.jianshu.com/u/973c8c406de7
- iOS开发--Bison详解连连支付集成简书
"最近由于公司项目需要集成连连支付,文档写的不是很清楚,遇到了一些坑,因此记录一下,希望能帮到有需要的人." 前面简单的集成没有遇到什么坑,在此整理一下官方的集成文档,具体步骤如下 ...
- 从刚刚「简书」平台的短暂异常,谈Nginx An error occurred报错~
09.26简书平台的短暂异常 An error occurred. Sorry, the page you are looking for is currently unavailable. Plea ...
- Scrapy爬取Ajax(异步加载)网页实例——简书付费连载
这两天学习了Scrapy爬虫框架的基本使用,练习的例子爬取的都是传统的直接加载完网页的内容,就想试试爬取用Ajax技术加载的网页. 这里以简书里的优选连载网页为例分享一下我的爬取过程. 网址为: ht ...
随机推荐
- mock 测试 MVC
SpringMVC测试框架 基于RESTful风格的SpringMVC的测试,我们可以测试完整的Spring MVC流程,即从URL请求到控制器处理,再到视图渲染都可以测试. 一 MockMvcBui ...
- javascript 浮点数加减乘除计算会有问题, 整理了以下代码来规避这个问题
/* * js数学计算 add by yan */ /** ** 加法函数,用来得到精确的加法结果 ** 说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显.这个函数返回较 ...
- AES 加密256位 错误 java.security.InvalidKeyException: Illegal key size or default parameters
Java发布的运行环境包中的加解密有一定的限制.比如默认不允许256位密钥的AES加解密,解决方法就是修改策略文件. 官方网站提供了JCE无限制权限策略文件的下载: JDK8的下载地址: http:/ ...
- python2限制函数传入的关键字参数
在Python2 中,可以通过使用**kwargs,在函数中配合使用kwargs.pop(key, False)实现获取限制关键字参数值,如果未传入则设置默认值,当所有需要的关键字参数都pop完毕,如 ...
- tair介绍以及配置
简介 tair 是淘宝自己开发的一个分布式 key/value 存储引擎. tair 分为持久化和非持久化两种使用方式. 非持久化的 tair 可以看成是一个分布式缓存. 持久化的 tair 将数据存 ...
- mongodb first
use [database] 使用数据库,新增文档后,数据库被自动创建 show dbs 显示所有数据库 db.[document].insert() 插入数据库 例:db.persons.inser ...
- Word 2003-在一个方框里打勾或打叉
最近有个同事问我,如何在Word中输出一个方框中打勾的符号?查了一下帮助,其实很简单,特记录如下,供碰到的朋友参考: 一.在方框中打勾的方法: 先输入一个大写字母R,然后将R选中,将字体改为“Wind ...
- Numpy 基础知识
1.使用ipython --pylab 自动加载 Numpy.Scipy.Matplotlib模块. 创建数组a = arange(10) b = arange(10,dtype='f')c = ar ...
- cookie保存用户名及密码
登陆页中,用户输入用户名密码,点击提交,后台对照mysq数据库中,看是否有对应的用户名,以及密码是否正确.如果正确 则将用户名密码分两份Cookie保存.页面跳转到登陆成功页. 用户再次访问登陆页时, ...
- pycharm 远程开发
1. 服务器安装图形化 和 pycharm 本地使用 MobaXterm 工具登陆 session配置 勾选 x11-forwarding 运行pycharm.sh 2. 本地pycharm 远程服务 ...