现在的位置: 首页 > 综合 > 正文

WebBrowser控件的高级用法,c#和Javascript交互及光标位置恢复<转>

2012年04月13日 ⁄ 综合 ⁄ 共 7583字 ⁄ 字号 评论关闭

 
 摘要:在做Winform应用的时候,有些效果不太好做,不像网页,用CSS和HTML能做出灰常漂亮的界面来,其实用WebBrowser可以让你的程序拥有两者的优势。这里介绍一个winform内嵌WebBrowser做的一个RSS浏览器及内嵌在Winform里的html编辑器的光标恢复问题。
 


不知道大家有没有用过FeedDemon,它是一个不错的RSS订阅工具,左边的导航树是Winform的,右边的主区域是用WebBrowser来呈现的,而且在主区域点击某条RSS条目后左边的树节点相应的未读数目就会变化,点击左边的树选择“设置所有项目未已读”,右边主区域的RSS列表就会变为已读图标,这是一个典型的Winform和WebBrowser相结合的例子,既发挥了Winform能利用本地CPU计算能力,响应快的特点,又发挥了HTML编程容易,界面华丽的优势,要用winform写一个右边主区域效果的控件,估计得费不少力。

我们先来看下这个RSS阅读器的核心功能,首先是利用http请求去获取rss内容,RSS是XML格式的,显示的话,就可以用XSLT来显示,这样可以做到内容和显示相分离,显示部分用WebBrowser来显示,然后呢WebBrowser里的javascript要可以调用Winform方法,Winform也要能调用Webbrowser控件里的javascript方法。

RSS的XML格式大家都很熟悉了,随便找一段示例如下


RSS XML Sample

我们还要再写个RSS来呈现这个RSS,就以列表的方式呈现就行了,然后我们设置简单的CSS,让已读的RSS条目显示为蓝色,未读的默认显示为黑色,然后点击每个条目的时候要把颜色改为已读的颜色,并且同时Winform。从上面的RSS定义可以看到我把前三个item元素加了一个read="true"的属性(为了演示目的我手工加的),我们用xslt的if语句来读取这个属性来动态设置RSS条目的样式。最后xslt还要定义一个让winform调用的javascript方法以供后面的演示。最终的XSLT如下,不太熟悉XSLT语法的可以参考我以前贴过的帖子。


<?
xml version="1.0" encoding="utf-8"
?>



<

xsl:stylesheet


version
="1.0"



xmlns:xsl

="http://www.w3.org/1999/XSL/Transform"
>



<
xsl:output
method
="html"

/>



<
xsl:template
match
="rss/channel"
>



<
html
>



<
head
>



<
title
>



<
xsl:value-of
select
="title"

/>



</
title
>



<
SCRIPT
LANGUAGE
="JavaScript"
>



function invokeWin(obj)


{


obj.childNodes[0].style.color='blue';


window.external.winFunction(obj.childNodes[0].href);


}


function scriptFunc(str)


{


alert(str);


}


</
SCRIPT
>



<
style
media
="all"
lang
="en"
type
="text/css"
>



body


{


background-color:#ccc;


}


.ChannelTitle


{


font-family: Verdana;


font-size: 11pt;


font-weight: bold;


width: 500px;


text-align: center;


}


.PostDate


{


font-family: Verdana;


font-size: 7pt;


padding-left: 15px;


}


A,A:visited


{


text-decoration: none;


color: #000


}


A:link


{


text-decoration: none;


}


A:hover


{


text-decoration: underline;


}


</
style
>



</
head
>



<
body
>



<
xsl:apply-templates
select
="title"

/>



<
ol
>



<
xsl:apply-templates
select
="item"

/>



</
ol
>



<
div
align
="center"
>
©
2008WawaSoft 2008
</
div
>



</
body
>



</
html
>



</
xsl:template
>



<
xsl:template
match
="title"
>



<
div
class
="ChannelTitle"
>



<
xsl:value-of
select
="text()"

/>



</
div
>



<
br
/>



</
xsl:template
>



<
xsl:template
match
="item"
>



<
li
>



<
span
onclick
="invokeWin(this)"
>



<
a
TARGET
="_blank"
href
="{link}"
>



<
xsl:if
test
="@read='true'"
>



<
xsl:attribute
name
="style"
>
color:blue;
</
xsl:attribute
>



</
xsl:if
>



<
xsl:value-of
select
="title"

/>



</
a
>



</
span
>



<
span
class
="PostDate"
>



<
xsl:value-of
select
="pubDate"

/>



</
span
>



</
li
>



</
xsl:template
>



</
xsl:stylesheet
>


程序里面呢,我们得让WebBrowser来显示这个RSS,代码如下



private

void
FWBTest_Load(
object

sender, EventArgs e)

{

wb1.AllowWebBrowserDrop

=

false

;


//
wb1.IsWebBrowserContextMenuEnabled = false;



wb1.WebBrowserShortcutsEnabled
=

false

;

wb1.ObjectForScripting

=

this

;

wb1.ScriptErrorsSuppressed

=

true

;


try


{

XslCompiledTransform xslt

=

new

XslCompiledTransform();

xslt.Load(

"
rss.xslt
"

);


string

HTMLoutput;


using
(StringWriter writer
=

new

StringWriter())

{

xslt.Transform(

"
rss.xml
"
,
null

, writer);

HTMLoutput

=

writer.ToString();

}

wb1.DocumentText

=

HTMLoutput;

}


catch

(XsltException xsle)

{

Console.WriteLine(

"
样式表中有错。
"

);

}


catch

(XmlException xmle)

{

Console.WriteLine(

"
加载样式表时出现分析错误。
"

);

}


catch

(Exception ex)

{

Console.WriteLine(ex);

}

}

都是WebBrowser和.net的Xml对象的基本用法。

和javascript交互也很简单,以下分别是让javascript调用的方法和用c#调用javascript方法的代码。



public

void
winFunction(
string

str)

{

toolStripStatusLabel1.Text

=

string
.Format(
"
脚本执行方法:{0}
"

, str);

}


private

void
toolStripButton1_Click(
object

sender, EventArgs e)

{

wb1.Document.InvokeScript(

"
scriptFunc
"

,


new
String[] {
"
这是winform调用脚本方法
"

});

}


关键点就是javascript代码的下面这句

window.external.winFunction(obj.childNodes[0].href);

以及c#代码下面这句

wb1.Document.InvokeScript("scriptFunc",new String[] { "这是winform调用脚本方法" });

 

 

 


RSS这部分演示完毕了。

winform下的富文本编辑器控件不太多,一般有两种途径,一种是扩展RichTextBox,要去研究rtf格式,mime协议等,一种是用WebBrowser控件,并把designMode设置为on,然后就是和网页的html编辑器一样,调用一些ExecCommand方法来编辑格式等,这里介绍后者,因为后者实现简单,而且html格式可以直接按原格式贴到互联网上,通用性比较好,这里不具体说一些编辑命令如何实现,这些可以参考文后的参考链接,这里只讨论如何让你的HTML文档关闭后再加载恢复上次编辑的光标位置的功能。

这里需要用一些mshtml对象,所以要在项目里引用Microsoft.mshtml,引用位置默认应该是C:\Program Files\Microsoft.NET\Primary Interop Assemblies\Microsoft.mshtml.dll,我不知道这个组件是不是新安装的windows xp,2003都有,如果没有的话可以把这个dll放到你项目的bin目录下一起发布。

大致原理是这样的,在关闭当前编辑文档的时候获取当前光标的位置,也就是当前选择的元素(虽然doc.selection有可能是个图片,而不是TextRange,但我们只考虑textRange的情况,大家可以写代码过滤掉其它情况,如果当前编辑点不是文本类型,就不考虑恢复光标位置了,呵呵。)。然后给当前选择元素后面插入一个小的span元素,作为一个标识符,最后再把文档的Body的InnerHTML保存到数据库里。下次从数据库里读取保存的html文本,先设置到当前WebBrowser的Body的innerHTML属性,然后通过getElementById方法找上次插入的标识符span,找到这个span就相当于找到了上次的光标位置,最后用body元素createTextRange后调用其moveToElementText方法把光标编辑位置移动到找到的位置。

相应代码如下



private

void

NewDoc()





{


wb1.Navigate(

"
about:blank
"

);


IHTMLDocument2 doc

=
wb1.Document.DomDocument
as

IHTMLDocument2;


doc.designMode

=

"
On
"

;


}






private

void

SaveDoc()





{


if
(wb1.Document
!=

null

)





{


IHTMLDocument2 doc

=
wb1.Document.DomDocument
as

IHTMLDocument2;


HTMLDocumentClass documentClass

=
wb1.Document.DomDocument
as

HTMLDocumentClass;


IHTMLDOMNode caret_pos

=
(IHTMLDOMNode)documentClass.getElementById(
"
caret_pos
"

);


if
(caret_pos
!=

null
) caret_pos.removeNode(
true

);


IHTMLTxtRange range

=
doc.selection.createRange()
as

IHTMLTxtRange;


range.pasteHTML(caretHtml);

抱歉!评论已关闭.