本文内容导读:
通过对winform微博管理工具,来记录一些容易被忽视,而且很有趣的东西,比如:
1、xslt根据xml内容生成html文档,并且里面一些比较写法注意点等
2、xslt中调用C#方法
3、xslt中引入js的一些框架
4、js调用winform后台方法及winform调用js的方法(以webbrowser为媒介)
FeedDemon这个工具基本也是js和winform的互调;
TX的QQ广告太多,所以改用TM,之前QQ集成了腾讯微博,但改QQ为TM后,发现TM对微博的支持不太理想;但本人在中午饭后闲暇之时,喜欢看看微博和文章;但又不太喜欢每次刷网页,麻烦;本来想去网上找个PC(winform)版本的腾讯微博,结果没有,无奈,想到之前腾讯提供API了,所以去看了看腾讯微博开发平台;下面说重点,如何解决winform中对xml的解析问题;
实现调用腾讯API的问题,在微博开发平台[http://wiki.open.t.qq.com/index.php]中可以查阅相关信息,里面有提供C#版本的SDK源文件和调用实例;所以在调用这块我不多做解释,我们只要通过API把相应的数据拿到程序里面,那么API就调用成功,剩下的就是我们程序自己内部交互的问题了;
基本上也就这么个小工具,目前支持的功能暂时只有腾讯微博,新浪微博正在准备开发中,可以支持长微博发送(大于140字自动转图片上传到腾讯微博);
我们从调用API拿到数据开始说起,因为调用API腾讯已经说的很详细,而且还有示例代码;
首先红色区域是一个webBrowser控件其他的都是winform里面的常用控件;大致实现如下
1、 首先通过API拿到xml数据,并且保存为本地的xml
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
statuses st = new statuses(oauthKey, "xml"); string ret = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"; ret += st.home_timeline(0, 0, 20); //保存为本地xml File.Delete(path + "\\temp.xml"); FileStream fs = new FileStream("temp.xml", FileMode.OpenOrCreate); StreamWriter sw = new StreamWriter(fs); sw.Write(ret); sw.Close(); fs.Close();
2、 现在API取数基本就完了,剩下的就是我们解析这个xml了并展示数据的问题了,我们使用xslt来解析xml为html文件
a、 先看cs文件中将用xslt解析xml文件为html的代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
string path = Application.StartupPath; XslCompiledTransform trans = new XslCompiledTransform(); trans.Load("temp.xslt"); trans.Transform("temp.xml", "temp.html"); path = path + "\\temp.html"; wbContent.Visible = true; if (wbContent.Url == null) { wbContent.Url = new Uri(path); } wbContent.Refresh();
b、 然后就是temp.xslt这个文件了;鄙人之前写过一个简单的xslt解析的简单文章[http://www.cnblogs.com/RegicideGod/archive/2012/08/07/2627436.html],我们此处也用xslt来解析xml;看来前面的文件,这里的具体我也不全部放代码来;直接说问题和解决方法吧;
腾讯提供的xml中的时间是时间戳,就是C#中[DateTime.Now.Ticks]的这个东西,我们在xslt中如何将时间戳转换为时间?在网上搜了下代码(网上有相关代码,写的不太详细或不全),需要修改下cs文件中,加载xstl时候的参数设置,就是a步中修改为
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
StringBuilder sbXml = new StringBuilder(); StringWriter stringWriter = new StringWriter(sbXml); XmlTextWriter xmlTextWriter = new XmlTextWriter(stringWriter); //设置可以执行脚本函数 XsltSettings settings = new XsltSettings(); settings.EnableDocumentFunction = true; settings.EnableScript = true; //设置xslt可以包含外部的xslt文件 XmlUrlResolver resolver = new XmlUrlResolver(); resolver.Credentials = System.Net.CredentialCache.DefaultCredentials; string path = Application.StartupPath; XslCompiledTransform trans = new XslCompiledTransform(); trans.Load("temp.xslt", settings, resolver); trans.Transform("temp.xml", "temp.html"); path = path + "\\temp.html"; wbContent.Visible = true; if (wbContent.Url == null) { wbContent.Url = new Uri(path); } wbContent.Refresh();
然后在XSLT的头部这么写
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="utf-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:csfun="urn:csharp-functions" exclude-result-prefixes="msxsl"> <xsl:output method="html" indent="yes"/> <xsl:include href="fun.xslt"/>
大致的意思是让xslt文件可以调用csharp-function
然后fun.xslt中就可以这么来写,将xml中的时间戳在xslt中调用C#方法来转换成时间了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="utf-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:csfun="urn:csharp-functions" exclude-result-prefixes="msxsl"> <msxsl:script implements-prefix="csfun" language="C#"> <![CDATA[ public string CheckDate(string tm) { string timeStamp = tm; DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); long lTime = long.Parse(timeStamp + "0000000"); TimeSpan toNow = new TimeSpan(lTime); DateTime dtResult = dtStart.Add(toNow); return dtResult.ToString(); } ]]> </msxsl:script> </xsl:stylesheet>
在来看下调用CheckDate方法
“发表时间: <xsl:value-ofselect="csfun:CheckDate(timestamp)"/>”
就可以将xml中timestamp的值传到刚才的c#方法中,然后接收返回值了;网上还有一些代码是传到JS中处理,好像大多数都没提到要设置XsltSettings可以执行脚本函数
我们也一定要设置b步骤中的加载xslt转换xml为html的方法;
还有一个小问题是xslt中写img标签和a标签
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<xsl:if test="image!=''"> <a target="_blank" style="color:#999;"> <xsl:attribute name="href"> <xsl:value-of select="image"/>/2000 </xsl:attribute> <img src="{image}/120" border="0" /> </a> </xsl:if>
Img标签中src可以直接指定xml的image值就可以了;不用xsl:value-of来查找了;腾讯微博中,图片只给了路径,没有给图片大小,需要自己手动填写,/120是尺寸为120大小的图片/2000一般是指原图
以上代码就可以实现基本的从微博拿到数据存储为xml在通过xslt转成html显示到webbrowser上面,就完成了整个微博的内容显示,但最重要的是需要有交互,就是对某一条微博进行评论和回复;每一个条微博右下角都会对应一个转播,评论,密语等功能操作,因为我们要通过生成的html中获取选中的那一条的微博信息,然后弹出一个提示框,让用户输入文字信息,进行评论;
这个界面(比较龊的界面)就是点击某一条微博的时候,弹出一个层的效果,然后输入文字信息点确定后,就会调用后台方法,通过API提交到腾讯服务器;
下面接说问题,在xslt模板生成的html中,是没有生成头标签的,但是我们这个地方用了一个基于jquery弹出层框架,需要导入jquery框架等,所以需要在html头部生一个标签就是经常看到容易被忽略的
”<!DOCTYPE html>“
虽然我们写的是html,但是我们要指定这个文档是html才行,不然webbrowser显示html带引入js时会报错,在xslt模板中我们导入上面一句话的写法是
<xsl:template name="DOCTYPE"> <![CDATA[<!DOCTYPE html>]]> </xsl:template>
然后在<html>的上面写上这么一句话,就相当于写了<!DOCTYPE html>这个东西
<xsl:value-of select="document('')/*/xsl:template[@name='DOCTYPE']/node()" disable-output-escaping="yes"/>
JS的引入问题解决了,剩下的就是点击页面的确定把html页面上的内容传到form窗体上面,那么现在的问题就是js调用winform方法,在bs开发中js调用后台方法,就是ajax但这里不行,没有IIS服务器的配合,行不通;继续百度加谷歌,发现webbrowser给我们提供了便利,就是可以让在webbrowser中的html通过js调用winform中的后台方法;我们来看下吧
a、指定主窗体类可以让webbrowser回调窗体中的方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//指定js可以回调webBrowser中的方法
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public partial class FrmMain : Form
{
public FrmMain()
{}
private void frmMain_Load(object sender, EventArgs e)
{
wbContent.ObjectForScripting = this; //wbContent为webBrowser控件
}
}
b、在窗体中写好评论一条微博的方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//评论一条微博
public void Comments(string conText, string reid,string flag)
{
conText = conText == "" ? " " : conText;
t tw = new t(oauthKey, "xml");
string ret = tw.comment(conText, "", "", "", reid);
if ("true".Equals(flag.ToLower()))
{
BroadCast(conText, reid);
}
}
c、在js中的调用如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//评论一条微博 function Comments(reid) { //alert(conText); var con='<div style="'+(_iwid*0.7+25)+'px;height:'+_ihei*0.5+'px;margin-left:-8px;margin-top:-5px;">'; con+='<textarea cols="80" style="margin-left:5px;margin-top:-5px;" rows="6" id="sendContent"></textarea><br/>您将评论:<br/>'+conText; con+='<br/><input type="checkbox" id="ch">一并转播'; con+='</div>'; $.dialog({ _iwid*0.7, height:_ihei*0.5, lock: true, title:'评论', background: '#DCE2F1', /* 背景色 默认的遮罩背景色为:#DCE2F1浅蓝护眼色 */ opacity: 0.5, /* 透明度 */ content: con, ok: function () { window.external.Comments($("#sendContent").val()+" ",reid,$("#ch")[0].checked); return true; }, cancel: true }); }
最重要的是标红的那句话,是在js中调用winform后台的Comments方法,并且把参数传到后台,今天消息处理;
当然还有在winform中通过webbrowser来调用js方法
//调用JS
private void btnAddFace_Click(object sender, EventArgs e)
{
wbContent.Document.InvokeScript("scriptFunc", new String[] { "这是winform调用脚本方法" });
}
到这里基本就完成了,主要是通过业务来讲解一些简单的技术问题;这些东西并不是很难理解,只是容易被忽视;