文采不好,将就着看,见谅

思路最重要,故本文不提供源码下载

参考项目:

http://www.windowsphone.com/zh-cn/store/app/%E5%BF%83%E7%90%86fm/41089a68-2efa-47f7-bd40-a508a1c8c5df

由于Windows Phone在考虑性能的情况下限制每个TextBlock最多显示高度为2000像素的文本,若超过此值,将自动被截断,显示空白。

网上有很多此问题的解决方案,如:计算文字像素,向容器添加多个TextBlock。但此方法效率相对较低且可能导致文本分段不正确。

据我所知常使用的方案有两种:

1.分页,监听ScrollViewer,当滚动到最下方,自动加载新页内容(类似瀑布流)

2.使用WebBrowser

方案一在纯文本的情况下可使用(也存在分段不正确的问题)

本文介绍第二种方案,使用WebBrowser

在使用之前需在网络下载以下文件

1.Newtonsoft.Json.WindowsPhone.dll

用于json解析(本示例仅使用了一小部分此程序集的功能,为提高效率和减小XAP文件大小,您可考虑自行编写解析代码)

2.HtmlAgilityPack.dll

用于解析html,修改图片尺寸(为提高效率和减小XAP文件大小,您可自行编写正则表达式,查询img标签并替换相关属性)

3.jquery-1.9.1.js(其它版本也行)

用于脚本编写(本示例并未大量使用脚本,可不使用jquery,自行编写原生js亦可)

概述

windows phone自带IE9浏览器,全面支持HTML5

可完美实现图文混排

开发时,可采用两种方案

1.将读取的文章按文件单独存放到独立存储空间,查看时直接读取相应文件即可。

优点:效率高

缺点:不利于更新,如果日后更新文章模板,在不清除原有文件的情况下,曾经保存的文章板式得不到更新

2.建立数据库,将文章内容存放到数据库,查看时动态生成html页

注:使用此方法需考虑文本被截断的问题,Windows phone使用的是SQL CE,没有text类型字段,字符串类型列最大值为4000个字符,如超过将抛出异常。

可使用如下方法解决:将获取的文本内容以3000个字符为单位截取(为什么不是4000?考虑到SQL行最大字节为8049),以多条数据的形式保存(此方法并不是最好的,如有更好解决方法请指教)

优点:方便更新,不占用手机内存

缺点:性能较方案一低

由于WebBrowser控件默认允许拖动和放大缩小

阻止缩放可在Html的Head中添加:

<meta content="width=device-width,user-scalable=no" name="viewport">

阻止拖动,我们可做如下工作,具体可参考:http://www.scottlogic.com/blog/2010/03/04/linq-to-visual-tree.html

或百度搜索:LinqToVisualTree

操作思路

1.编写主要逻辑代码

2.相应的资源文件和模板放入项目,将生成操作设置为:Resources

之所以要做这一步,是因为WebBrowser控件读取的是独立存储空间的文件,在控件初始化时,需读取相应文件将其存放到独立存储空间

运行时思路

1.将拷贝的资源文件和模板文件转移到独立存储空间

2.获取文章详细内容

3.读取模板文件

4.替换模板内容

5.保存html文件

6.显示html

关于图片加载

加载内容,难免会存在图片,图片都存在于网络且尺寸不同,若每次显示都加载网络图片,势必会浪费用户流量,耗费时间

解决尺寸不同:

通过正则表达式或其它手段获取img标签,将宽设置为100%,删除高(自适应)

解决图片路径:

通过正则表达式或其它手段获取img标签,得到图片url,将图片缓存至独立存储空间,下次加载,首先判断独立存储空间是否存在对应文件,如存在则直接加载,若不存在则在加载网络图片的同时将图片缓存至独立存储空间。

/// <summary>
/// 调整图片
/// </summary>
/// <param name="html"></param>
/// <param name="imageWidth"></param>
/// <returns></returns>
private string RevisionImg(string html, int imageWidth)
{
HtmlDocument document = new HtmlDocument();
document.LoadHtml(html);
if (document == null) { return html; }
var images = document.DocumentNode.SelectNodes("//img");
if (images == null || images.Count == ) { return html; }
foreach (HtmlNode image in images)
{
if (imageWidth != )
{
image.Attributes.Remove("width");
//image.Attributes.Add("width", string.Format("{0}px", imageWidth));
image.Attributes.Add("width", string.Format("{0}%", ));
}
if (image.Attributes["height"] != null)
{
image.Attributes["height"].Remove();
}
if (image.Attributes["src"] != null)
{
try
{
string imageUrl = image.Attributes["src"].Value;
//获取图片url,若不存在,则缓存至独立存储空间
StorageCachedImage cacheImage = new StorageCachedImage(new Uri(imageUrl, UriKind.Absolute));
if (cacheImage.IsSaveLocal)
{
imageUrl = "/" + cacheImage.ImageUri.Replace("\\", "/").TrimStart('/');
}
image.Attributes["src"].Value = imageUrl;
}
catch { }
}
}
return document.DocumentNode.OuterHtml;
}

代码片段

关于javascript与C#互操作

设置WebBrowser控件IsScriptEnabled属性为True

注册WebBrowser控件LoadCompleted和ScriptNotify事件

在LoadCompleted事件中可编写调用js初始化方法

在ScriptNotify事件中可监听javascript,脚本中通过window.external.notify触发ScriptNotify事件

public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this._webBrowser = this.GetTemplateChild("WebBrowser") as WebBrowser;
this._webBrowser.LoadCompleted += _webBrowser_LoadCompleted;
this._webBrowser.ScriptNotify += _webBrowser_ScriptNotify; } void _webBrowser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
this._webBrowser.InvokeScript("init");
} void _webBrowser_ScriptNotify(object sender, NotifyEventArgs e)
{
string keyValue = e.Value;
if (string.IsNullOrWhiteSpace(keyValue)) { return; }
JObject jObject = JObject.Parse(keyValue);
string key = jObject["key"].Value<string>();
string value = jObject["value"].Value<string>();
if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(value)) { return; } if (key == "imgClick")
{ }
else if (key == "aClick")
{
this.OpenLink(value);
}
}

代码片段

源码

新建项目,创建自定义控件WebBrowserArticle

using HtmlAgilityPack;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Tasks;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using ZP.AppLibrary; namespace ZP.Controls
{
public class WebBrowserArticle : Control
{
private const string _htmlTemplateFilePath = "/html/content_template.html";
private const string _htmlFilePath = "/html/index.html"; private WebBrowser _webBrowser;
public bool ScrollDisabled { get; set; }//是否禁用滚动
public WebBrowserArticle()
{
this.DefaultStyleKey = typeof(WebBrowserArticle);
this.Loaded += WebBrowserArticle_Loaded;
} #region 属性
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register(
"Title",
typeof(string),
typeof(WebBrowserArticle),
new PropertyMetadata(null, OnTextPropertyChanged));
public string Title
{
get
{
return (string)GetValue(TitleProperty);
}
set
{
SetValue(TitleProperty, value);
}
} public static readonly DependencyProperty OtherDataProperty =
DependencyProperty.Register(
"OtherData",
typeof(string),
typeof(WebBrowserArticle),
new PropertyMetadata(null, OnTextPropertyChanged));
/// <summary>
/// 其它数据(多个用字符“~”分隔)
/// </summary>
public string OtherData
{
get
{
return (string)GetValue(OtherDataProperty);
}
set
{
SetValue(OtherDataProperty, value);
}
} public static readonly DependencyProperty BodyProperty =
DependencyProperty.Register(
"Body",
typeof(string),
typeof(WebBrowserArticle),
new PropertyMetadata(null, OnTextPropertyChanged));
public string Body
{
get
{
return (string)GetValue(BodyProperty);
}
set
{
SetValue(BodyProperty, value);
}
}
#endregion void WebBrowserArticle_Loaded(object sender, RoutedEventArgs e)
{
if (this._webBrowser != null)
{
this.SaveHtml(); var border = this._webBrowser.Descendants<Border>().Last() as Border;
border.ManipulationDelta += Border_ManipulationDelta;
border.ManipulationCompleted += Border_ManipulationCompleted;
}
} public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this._webBrowser = this.GetTemplateChild("WebBrowser") as WebBrowser;
this._webBrowser.LoadCompleted += _webBrowser_LoadCompleted;
this._webBrowser.ScriptNotify += _webBrowser_ScriptNotify; } void _webBrowser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
this._webBrowser.InvokeScript("init");
} void _webBrowser_ScriptNotify(object sender, NotifyEventArgs e)
{
string keyValue = e.Value;
if (string.IsNullOrWhiteSpace(keyValue)) { return; }
JObject jObject = JObject.Parse(keyValue);
string key = jObject["key"].Value<string>();
string value = jObject["value"].Value<string>();
if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(value)) { return; } if (key == "imgClick")
{ }
else if (key == "aClick")
{
this.OpenLink(value);
}
} /// <summary>
/// 打开链接
/// </summary>
/// <param name="url"></param>
private void OpenLink(string url)
{
WebBrowserTask webBrowserTask = new WebBrowserTask();
webBrowserTask.Uri = new Uri(url, UriKind.Absolute);
webBrowserTask.Show();
} private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
WebBrowserArticle source = (WebBrowserArticle)d;
//string html = (string)e.NewValue;
source.SaveHtml();
} private void SaveHtml()
{
if (this._webBrowser == null || this.Title == null || this.OtherData == null || this.Body == null) { return; }
Common.CopyContentToIsolatedStorage("/Controls;component/WebBrowserArticle/html/content_template.html", _htmlTemplateFilePath);
string template = IsolatedStorageHelper.OpenFile(_htmlTemplateFilePath);
template = template.Replace("{title}", this.Title);
template = template.Replace("{body}", this.Body);
string otherHtml = string.Empty;
string otherData = this.OtherData;
if (!string.IsNullOrWhiteSpace(otherData))
{
string[] otherDatas = otherData.Split(new string[] { "~" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string item in otherDatas)
{
otherHtml += string.Format("<span class=\"otherData\">{0}</span>", item);
}
}
template = template.Replace("{otherData}", otherHtml);
template = this.RevisionImg(template, (int)this._webBrowser.ActualWidth);
IsolatedStorageHelper.SaveFile(_htmlFilePath, template); Common.CopyContentToIsolatedStorage("/Controls;component/WebBrowserArticle/html/js/jquery-1.9.1.js", "/html/js/jquery-1.9.1.js");
Common.CopyContentToIsolatedStorage("/Controls;component/WebBrowserArticle/html/js/content.js", "/html/js/content.js");
Common.CopyContentToIsolatedStorage("/Controls;component/WebBrowserArticle/html/css/content.css", "/html/css/content.css");
this._webBrowser.Navigate(new Uri(_htmlFilePath, UriKind.RelativeOrAbsolute));
} /// <summary>
/// 调整图片
/// </summary>
/// <param name="html"></param>
/// <param name="imageWidth"></param>
/// <returns></returns>
private string RevisionImg(string html, int imageWidth)
{
HtmlDocument document = new HtmlDocument();
document.LoadHtml(html);
if (document == null) { return html; }
var images = document.DocumentNode.SelectNodes("//img");
if (images == null || images.Count == ) { return html; }
foreach (HtmlNode image in images)
{
if (imageWidth != )
{
image.Attributes.Remove("width");
//image.Attributes.Add("width", string.Format("{0}px", imageWidth));
image.Attributes.Add("width", string.Format("{0}%", ));
}
if (image.Attributes["height"] != null)
{
image.Attributes["height"].Remove();
}
if (image.Attributes["src"] != null)
{
try
{
string imageUrl = image.Attributes["src"].Value;
//获取图片url,若不存在,则缓存至独立存储空间
StorageCachedImage cacheImage = new StorageCachedImage(new Uri(imageUrl, UriKind.Absolute));
if (cacheImage.IsSaveLocal)
{
imageUrl = "/" + cacheImage.ImageUri.Replace("\\", "/").TrimStart('/');
}
image.Attributes["src"].Value = imageUrl;
}
catch { }
}
}
return document.DocumentNode.OuterHtml;
} #region 阻止拖动
private void Border_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
if (e.FinalVelocities.ExpansionVelocity.X != 0.0 ||
e.FinalVelocities.ExpansionVelocity.Y != 0.0)
{
e.Handled = true;
}
} private void Border_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
if (e.DeltaManipulation.Scale.X != 0.0 ||
e.DeltaManipulation.Scale.Y != 0.0)
{
e.Handled = true;
}
if (ScrollDisabled)
{
if (e.DeltaManipulation.Translation.X != 0.0 ||
e.DeltaManipulation.Translation.Y != 0.0)
{
e.Handled = true;
}
}
}
#endregion
}
}

代码片段

新建目录:themes

在目录themes新建:generic.xaml

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=System"
xmlns:controls="clr-namespace:当前控件命名空间;assembly=当前控件程序集名称"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:windows="clr-namespace:System.Windows;assembly=System.Windows"> <Style TargetType="controls:WebBrowserArticle">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<phone:WebBrowser Name="WebBrowser" IsScriptEnabled="True" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style> </ResourceDictionary>

代码片段

将“当前控件命名空间”替换为你所建立自定义控件的命名空间

将“当前空间程序集名称”替换为你所建立自定义控件的程序集名称

如:

新建html模板,并导入相关文件

body {
margin:;
padding: 0px;
-ms-text-size-adjust: none;
} header {
padding: 0px 0 20px;
} .title {
font-size: 25px;
font-weight: bold;
line-height: 30px;
color: #454545;
margin: 10px 0 20px 0px;
} .otherInfo {
font-size: 12px;
color: #afafaf;
} .otherData {
margin: 0px 5px 0 5px;
} article {
margin-top: -15px;
line-height: 25px;
margin-right: 0px;
margin-bottom:50px;
font-size: 14px;
color: #7c7c7c;
} article div {
clear: both;
float: right;
margin: 10px 2px 5px 5px;
overflow: hidden;
height: 125px;
width: 125px;
} article div img {
border:;
} article p {
margin:;
}

content.css

var xapKEY = {
imgClick: "imgClick",
aClick: "aClick"
}; function callXAP(key, value) {
var jsonData = "{key:\"" + key + "\",value:\"" + value + "\"}";
window.external.notify(jsonData);
} function init() {
//$("img").click(function () {
// var currObj = $(this);
// var imageUrl = currObj.attr("src").toLowerCase();
// if (imageUrl.indexOf('.gif') > 0) {
// currObj.remove();
// } else {
// currObj.mousedown(function () {
// callXAP(xapKEY.imgClick, imageUrl);
// });
// }
//});
//$("a img").unbind("click");
$("a").click(function () {
var currObj = $(this);
var link = currObj.attr("href");
if (link && link.indexOf("javascript:") == -1) {
callXAP(xapKEY.aClick, link);
}
return false;
});
$("embed,object").remove();
}

content.js

<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="UTF-8">
<meta content="width=device-width,user-scalable=no" name="viewport">
<link href="css/content.css" rel="stylesheet" />
<script type="text/javascript" src="js/jquery-1.9.1.js"></script>
</head>
<body>
<header>
<div class="title">{title}</div>
<div class="otherInfo">{otherData}</div>
</header>
<article>
{body}
</article>
<script type="text/javascript" src="js/content.js"></script>
</body>
</html>

content_template.html

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media; namespace ZP.AppLibrary
{
/// <summary>
/// Adapts a DependencyObject to provide methods required for generate
/// a Linq To Tree API
/// </summary>
public class VisualTreeAdapter : ILinqTree<DependencyObject>
{
private DependencyObject _item; public VisualTreeAdapter(DependencyObject item)
{
_item = item;
} public IEnumerable<DependencyObject> Children()
{
int childrenCount = VisualTreeHelper.GetChildrenCount(_item);
for (int i = ; i < childrenCount; i++)
{
yield return VisualTreeHelper.GetChild(_item, i);
}
} public DependencyObject Parent
{
get
{
return VisualTreeHelper.GetParent(_item);
}
}
}
/// <summary>
/// Defines an interface that must be implemented to generate the LinqToTree methods
/// </summary>
/// <typeparam name="T"></typeparam>
public interface ILinqTree<T>
{
IEnumerable<T> Children(); T Parent { get; }
} public static class TreeExtensions
{
/// <summary>
/// Returns a collection of descendant elements.
/// </summary>
public static IEnumerable<DependencyObject> Descendants(this DependencyObject item)
{
ILinqTree<DependencyObject> adapter = new VisualTreeAdapter(item);
foreach (var child in adapter.Children())
{
yield return child; foreach (var grandChild in child.Descendants())
{
yield return grandChild;
}
}
} /// <summary>
/// Returns a collection containing this element and all descendant elements.
/// </summary>
public static IEnumerable<DependencyObject> DescendantsAndSelf(this DependencyObject item)
{
yield return item; foreach (var child in item.Descendants())
{
yield return child;
}
} /// <summary>
/// Returns a collection of ancestor elements.
/// </summary>
public static IEnumerable<DependencyObject> Ancestors(this DependencyObject item)
{
ILinqTree<DependencyObject> adapter = new VisualTreeAdapter(item); var parent = adapter.Parent;
while (parent != null)
{
yield return parent;
adapter = new VisualTreeAdapter(parent);
parent = adapter.Parent;
}
} /// <summary>
/// Returns a collection containing this element and all ancestor elements.
/// </summary>
public static IEnumerable<DependencyObject> AncestorsAndSelf(this DependencyObject item)
{
yield return item; foreach (var ancestor in item.Ancestors())
{
yield return ancestor;
}
} /// <summary>
/// Returns a collection of child elements.
/// </summary>
public static IEnumerable<DependencyObject> Elements(this DependencyObject item)
{
ILinqTree<DependencyObject> adapter = new VisualTreeAdapter(item);
foreach (var child in adapter.Children())
{
yield return child;
}
} /// <summary>
/// Returns a collection of the sibling elements before this node, in document order.
/// </summary>
public static IEnumerable<DependencyObject> ElementsBeforeSelf(this DependencyObject item)
{
if (item.Ancestors().FirstOrDefault() == null)
yield break;
foreach (var child in item.Ancestors().First().Elements())
{
if (child.Equals(item))
break;
yield return child;
}
} /// <summary>
/// Returns a collection of the after elements after this node, in document order.
/// </summary>
public static IEnumerable<DependencyObject> ElementsAfterSelf(this DependencyObject item)
{
if (item.Ancestors().FirstOrDefault() == null)
yield break;
bool afterSelf = false;
foreach (var child in item.Ancestors().First().Elements())
{
if (afterSelf)
yield return child; if (child.Equals(item))
afterSelf = true;
}
} /// <summary>
/// Returns a collection containing this element and all child elements.
/// </summary>
public static IEnumerable<DependencyObject> ElementsAndSelf(this DependencyObject item)
{
yield return item; foreach (var child in item.Elements())
{
yield return child;
}
} /// <summary>
/// Returns a collection of descendant elements which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> Descendants<T>(this DependencyObject item)
{
return item.Descendants().Where(i => i is T).Cast<DependencyObject>();
} /// <summary>
/// Returns a collection of the sibling elements before this node, in document order
/// which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> ElementsBeforeSelf<T>(this DependencyObject item)
{
return item.ElementsBeforeSelf().Where(i => i is T).Cast<DependencyObject>();
} /// <summary>
/// Returns a collection of the after elements after this node, in document order
/// which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> ElementsAfterSelf<T>(this DependencyObject item)
{
return item.ElementsAfterSelf().Where(i => i is T).Cast<DependencyObject>();
} /// <summary>
/// Returns a collection containing this element and all descendant elements
/// which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> DescendantsAndSelf<T>(this DependencyObject item)
{
return item.DescendantsAndSelf().Where(i => i is T).Cast<DependencyObject>();
} /// <summary>
/// Returns a collection of ancestor elements which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> Ancestors<T>(this DependencyObject item)
{
return item.Ancestors().Where(i => i is T).Cast<DependencyObject>();
} /// <summary>
/// Returns a collection containing this element and all ancestor elements
/// which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> AncestorsAndSelf<T>(this DependencyObject item)
{
return item.AncestorsAndSelf().Where(i => i is T).Cast<DependencyObject>();
} /// <summary>
/// Returns a collection of child elements which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> Elements<T>(this DependencyObject item)
{
return item.Elements().Where(i => i is T).Cast<DependencyObject>();
} /// <summary>
/// Returns a collection containing this element and all child elements.
/// which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> ElementsAndSelf<T>(this DependencyObject item)
{
return item.ElementsAndSelf().Where(i => i is T).Cast<DependencyObject>();
} } public static class EnumerableTreeExtensions
{
/// <summary>
/// Applies the given function to each of the items in the supplied
/// IEnumerable.
/// </summary>
private static IEnumerable<DependencyObject> DrillDown(this IEnumerable<DependencyObject> items,
Func<DependencyObject, IEnumerable<DependencyObject>> function)
{
foreach (var item in items)
{
foreach (var itemChild in function(item))
{
yield return itemChild;
}
}
} /// <summary>
/// Applies the given function to each of the items in the supplied
/// IEnumerable, which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> DrillDown<T>(this IEnumerable<DependencyObject> items,
Func<DependencyObject, IEnumerable<DependencyObject>> function)
where T : DependencyObject
{
foreach (var item in items)
{
foreach (var itemChild in function(item))
{
if (itemChild is T)
{
yield return (T)itemChild;
}
}
}
} /// <summary>
/// Returns a collection of descendant elements.
/// </summary>
public static IEnumerable<DependencyObject> Descendants(this IEnumerable<DependencyObject> items)
{
return items.DrillDown(i => i.Descendants());
} /// <summary>
/// Returns a collection containing this element and all descendant elements.
/// </summary>
public static IEnumerable<DependencyObject> DescendantsAndSelf(this IEnumerable<DependencyObject> items)
{
return items.DrillDown(i => i.DescendantsAndSelf());
} /// <summary>
/// Returns a collection of ancestor elements.
/// </summary>
public static IEnumerable<DependencyObject> Ancestors(this IEnumerable<DependencyObject> items)
{
return items.DrillDown(i => i.Ancestors());
} /// <summary>
/// Returns a collection containing this element and all ancestor elements.
/// </summary>
public static IEnumerable<DependencyObject> AncestorsAndSelf(this IEnumerable<DependencyObject> items)
{
return items.DrillDown(i => i.AncestorsAndSelf());
} /// <summary>
/// Returns a collection of child elements.
/// </summary>
public static IEnumerable<DependencyObject> Elements(this IEnumerable<DependencyObject> items)
{
return items.DrillDown(i => i.Elements());
} /// <summary>
/// Returns a collection containing this element and all child elements.
/// </summary>
public static IEnumerable<DependencyObject> ElementsAndSelf(this IEnumerable<DependencyObject> items)
{
return items.DrillDown(i => i.ElementsAndSelf());
} /// <summary>
/// Returns a collection of descendant elements which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> Descendants<T>(this IEnumerable<DependencyObject> items)
where T : DependencyObject
{
return items.DrillDown<T>(i => i.Descendants());
} /// <summary>
/// Returns a collection containing this element and all descendant elements.
/// which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> DescendantsAndSelf<T>(this IEnumerable<DependencyObject> items)
where T : DependencyObject
{
return items.DrillDown<T>(i => i.DescendantsAndSelf());
} /// <summary>
/// Returns a collection of ancestor elements which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> Ancestors<T>(this IEnumerable<DependencyObject> items)
where T : DependencyObject
{
return items.DrillDown<T>(i => i.Ancestors());
} /// <summary>
/// Returns a collection containing this element and all ancestor elements.
/// which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> AncestorsAndSelf<T>(this IEnumerable<DependencyObject> items)
where T : DependencyObject
{
return items.DrillDown<T>(i => i.AncestorsAndSelf());
} /// <summary>
/// Returns a collection of child elements which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> Elements<T>(this IEnumerable<DependencyObject> items)
where T : DependencyObject
{
return items.DrillDown<T>(i => i.Elements());
} /// <summary>
/// Returns a collection containing this element and all child elements.
/// which match the given type.
/// </summary>
public static IEnumerable<DependencyObject> ElementsAndSelf<T>(this IEnumerable<DependencyObject> items)
where T : DependencyObject
{
return items.DrillDown<T>(i => i.ElementsAndSelf());
}
}
}

LinqToVisualTree.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Net;
using System.Text;
using System.Windows.Media.Imaging; namespace ZP.AppLibrary
{
/// <summary>
/// 独立存储缓存图片
/// </summary>
public sealed class StorageCachedImage : BitmapSource
{
private readonly Uri uriSource;
private readonly string filePath;
private const string CacheDirectory = "Shared/ShellContent/CachedImages";
/// <summary>
/// 是否保存在本地
/// </summary>
public bool IsSaveLocal { get; set; }
static StorageCachedImage()
{
//创建缓存目录
using (var isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!isolatedStorageFile.DirectoryExists(CacheDirectory))
{
isolatedStorageFile.CreateDirectory(CacheDirectory);
}
}
} /// <summary>
/// 创建一个独立存储缓存的图片源
/// </summary>
/// <param name="uriSource"></param>
public StorageCachedImage(Uri uriSource)
{
this.uriSource = uriSource;
string imageAbsolutePath = uriSource.AbsolutePath.ToLower();
string extension = Path.GetExtension(imageAbsolutePath).ToLower();
imageAbsolutePath = imageAbsolutePath.Replace(extension, ""); //去除扩展名其它字符如:*****.jpg!80、*****.jpg#80
if (extension.IndexOf(".jpeg") != -) { extension = ".jpeg"; }
else if (extension.IndexOf(".jpg") != -) { extension = ".jpg"; }
else if (extension.IndexOf(".png") != -) { extension = ".png"; }
else if (extension.IndexOf(".bmp") != -) { extension = ".bmp"; }
else if (extension.IndexOf(".gif") != -) { extension = ".gif"; } imageAbsolutePath += extension;
imageAbsolutePath = imageAbsolutePath.TrimStart('/').Replace('/', '_').Replace(':', '_');
//文件路径
filePath = Path.Combine(CacheDirectory, imageAbsolutePath);
OpenCatchSource();
} /// <summary>
/// 打开缓存源
/// </summary>
private void OpenCatchSource()
{
bool exist;
using (var isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())
{
exist = isolatedStorageFile.FileExists(filePath);
}
this.IsSaveLocal = exist;
if (exist)
{
SetCacheStreamSource();
}
else
{
SetWebStreamSource();
}
} /// <summary>
/// 设置缓存流到图片
/// </summary>
private void SetCacheStreamSource()
{
using (var isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var stream = isolatedStorageFile.OpenFile(filePath, FileMode.Open, FileAccess.Read))
{
SetSource(stream);
}
}
} /// <summary>
/// 下载Uri中的图片
/// </summary>
private void SetWebStreamSource()
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(uriSource);
httpWebRequest.AllowReadStreamBuffering = true;
httpWebRequest.BeginGetResponse(ResponseCallBack, httpWebRequest);
} /// <summary>
/// 下载回调
/// </summary>
/// <param name="asyncResult"></param>
private void ResponseCallBack(IAsyncResult asyncResult)
{
var httpWebRequest = asyncResult.AsyncState as HttpWebRequest;
if (httpWebRequest == null) return;
try
{
var response = httpWebRequest.EndGetResponse(asyncResult);
using (var stream = response.GetResponseStream())
{
using (var isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var fileStream = isolatedStorageFile.OpenFile
(filePath, FileMode.OpenOrCreate, FileAccess.Write))
{
stream.CopyTo(fileStream);
}
}
Dispatcher.BeginInvoke(SetCacheStreamSource);
}
}
catch (Exception err)
{
Debug.WriteLine(err.Message);
}
} /// <summary>
/// 当前图片Uri
/// </summary>
public string ImageUri
{
get
{
bool exist;
using (var isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication())
{
exist = isolatedStorageFile.FileExists(this.filePath);
}
if (exist)
{
return this.filePath;
}
else
{
return uriSource.ToString();
}
}
}
}
}

StorageCachedImage.cs

/// <summary>
/// 复制文件到独立存储空间
/// </summary>
/// <param name="sourceFileUrl">源文件</param>
/// <param name="saveFileUrl">保存文件</param>
public static void CopyContentToIsolatedStorage(string sourceFileUrl, string saveFileUrl = null)
{
using (IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication())
{
saveFileUrl = string.IsNullOrWhiteSpace(saveFileUrl) ? sourceFileUrl : saveFileUrl;
//if (iso.FileExists(saveFileUrl)) { iso.DeleteFile(saveFileUrl); }
if (!iso.FileExists(saveFileUrl))
{
var fullDirectory = System.IO.Path.GetDirectoryName(saveFileUrl);
if (!iso.DirectoryExists(fullDirectory))
{
iso.CreateDirectory(fullDirectory);
} using (Stream input = Application.GetResourceStream(new Uri(sourceFileUrl, UriKind.Relative)).Stream)
{
using (IsolatedStorageFileStream output = iso.CreateFile(saveFileUrl))
{
byte[] readBuffer = new byte[];
int bytesRead = -;
while ((bytesRead = input.Read(readBuffer, , readBuffer.Length)) > )
{
output.Write(readBuffer, , bytesRead);
}
}
}
}
}
} /// <summary>
/// 保存文件
/// </summary>
/// <param name="fileName"></param>
/// <param name="content"></param>
public static void SaveFile(string fileName, string content)
{
using (var store = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication())
{
if (store.FileExists(fileName)) { store.DeleteFile(fileName); }
using (var stream = store.CreateFile(fileName))
{
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(content);
stream.Write(buffer, , buffer.Length);
}
}
} /// <summary>
/// 打开文件
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static string OpenFile(string fileName)
{
string data = string.Empty;
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (myIsolatedStorage.FileExists(fileName))
{
using (IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile(fileName, FileMode.Open, FileAccess.ReadWrite))
{
StreamReader sr = new StreamReader(fileStream, System.Text.Encoding.UTF8);
data = sr.ReadToEnd();
sr.Close();
}
}
}
return data;
}

其它相关方法

Windows Phone 显示长文本的更多相关文章

  1. css截断长文本显示

    实现 截断长文本显示处理,以前是通过后台的截取,但这种方法容易丢失数据,不利于SEO. 而通过前端css的截断,则灵活多变,可统一运用与整个网站. 这项技术主要运用了text-overflow属性,这 ...

  2. CSS控制长文本内容显示(截取的地方用省略号代替)

    自动换行问题,正常字符的换行是比较合理的,而连续的数字和英文字符常常将容器撑大,下面介绍的是CSS如何实现处理的方法. 现实中经常出现一些内容比较长的文本,为了使整体布局美观,需要将文本内容控制在一行 ...

  3. Delphi: TLabel设置EllipsisPosition属性用...显示过长文本时,以Hint显示其全文本

    仍然是处理多语言中碰到问题. Delphi自2006版以后,TLabel有了EllipsisPosition属性,当长文本超过其大小时,显示以...,如下图: 这样虽然解决显示问题,但很显然,不知道. ...

  4. 【css】长文本左侧显示省略号

    classnames: https://blog.csdn.net/duola8789/article/details/71514450 react普通样式 行内样式: https://blog.cs ...

  5. ABAP程序中关于长文本的处理方法

    现象描述 长文本在SAP的运用主要体现在一些notes的记录,或者一些比较长的文本的存取,比如工作流的审批意见,采购申请和采购订单的附加说明等等.如下图: 处理过程 1:SAP中所有的长文本都存在两张 ...

  6. OAF 中对文字实现html效果及对超级长文本实现默认换行,对只读的messageTextInput中的内容自动换行

    今天遇到一个需求,客户注册页面客户化了一个超级长的注册须知,内容很多.但是样式相对又要做起来好看点. 注册须知的内容使用多个message拼接而成. 老大说rawText支持html样式,于是我想到了 ...

  7. <q>标签,短文本引用;<blockquote>标签,长文本引用

    <q>标签,短文本引用 <q>引用文本</q>,默认显示双引号,不需要在文本中添加 <blockquote>标签,长文本引用 浏览器对<block ...

  8. 使用UIWebView中html标签显示富文本

    使用UIWebView中html标签显示富文本 用UIWebView来渲染文本并期望达到富文本的效果开销很大哦! Work 本人此处直接加载自定义字体"新蒂小丸子体",源码不公开, ...

  9. windows不能显示此连接属性。windows management instrumentation (WMI) 信息可能损坏

    Windows Management Instrumentation (WMI)信息可能损坏错误修复 在 查看“本地连接”的属性,并切换到“高级”选项卡后,提示:“Windows不能显示此连接的属性. ...

随机推荐

  1. 如何为PHP贡献代码

    PHP在之前把源代码迁移到了git下管理, 同时也在github(https://github.com/php/php-src)上做了镜像, 这样一来, 就方便了更多的开发者为PHP来贡献代码. 今天 ...

  2. 如何设置BIOS使服务器断电后再来电能自动开机

    不同的主板及CMOS型号相对应的选项会有所不同,但我想应该不会差太多,一般都在[POWER MANAGEMENT SETUP]和[Integrated Peripherals]这两个选项中.下面介绍两 ...

  3. DataTable的Merge使用

    using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.T ...

  4. vs 2012 智能提示后为何不能 直接按enter键把提示的内容输入

    这个是VS的"建议完成模式"和"标准模式",两者间切换按快捷键:Ctrl+Alt+空格键

  5. dual

    1. dual 确实是一张表.是一张只有一个字段,一行记录的表. 2.习惯上,我们称之为'伪表'.因为他不存储主题数据.3. 他的存在,是为了操作上的方便.因为select 都是要有特定对象的.如:s ...

  6. ElasticSearch 的 聚合(Aggregations)

    Elasticsearch有一个功能叫做 聚合(aggregations) ,它允许你在数据上生成复杂的分析统计.它很像SQL中的 GROUP BY 但是功能更强大. Aggregations种类分为 ...

  7. HDU 4405 【概率dp】

    题意: 飞行棋,从0出发要求到n或者大于n的步数的期望.每一步可以投一下筛子,前进相应的步数,筛子是常见的6面筛子. 但是有些地方可以从a飞到大于a的b,并且保证每个a只能对应一个b,而且可以连续飞, ...

  8. PL/SQL Developer使用技巧、快捷键

    1.类SQL PLUS窗口:File->New->Command Window,这个类似于oracle的客户端工具sql plus,但比它好用多了. 2.设置关键字自动大写:Tools-& ...

  9. VS2010 Win32项目的源码位置设置

    在VS2010中,我们可以创建一个Win32项目用来编辑C或CPP代码,项目建好后我们向项目文件夹添加代码文件,并调试能正常运行. 有时候我们会发现项目目录下没有源文件,这种情况下,可以通过设置“输出 ...

  10. C#中char[]与string之间的转换

    string 转换成 Char[] string ss = "abcdefg"; char[] cc = ss.ToCharArray(); Char[] 转换成string st ...