注: 本文为转载,转载必须保留原作者信息及其原始链接!
原址:http://www.slfans.com/?action-viewnews-itemid-16530
发布: 2009-6-17 11:26 | 作者: 紫色永恒
最近比较关注MVVM(Model-View_ViewModel)模式,该模式十分适合WPF/Silverlight的开发。出于练习的目的打算使用Silverlight做个英汉词典(可能是由于近来疯狂的听VOA的缘故),下面针对该项目进行简单的分析。
注:由于Silverlight不支持Command 所以并无法像WPF那样完全实现MVVM模式。
这里说下我的开发环境
windows server 2008
visual studio 2008 with sp1
sliverlight 2
下面开始一步一步的制作该应用。
首先新建一个Silverlight项目并宿主在ASP.NET Web Application中(当然我强烈建议宿主在ASP.NET MVC中,不过该项目基本上和宿主端没什么联系而并不是每个人都安装了ASP.NET MVC,所以宿主在可以使用Silverlight控件的Web Form中也许受众面更广泛一些)
在Silverlight的项目中分别新建三个文件夹Model、View、ViewModel并添加相应的文件,最终的解决方案视图如下
Model/DictModel.cs以及Model/SentModel.cs为纯粹的业务模型,所有的属性都必须实现IPropertyChanged接口以便在其值更改时可以同时更新UI。这两个类同时继承PropertyChangedBase,该基类很简单,请见我的另外一篇文章:让INotifyPropertyChanged的实现更优雅一些
这两个类的代码如下
DictModel.cs
using System;
namespace EternalDict.Model
{
public class DictModel : PropertyChangedBase
{
string _key;
public string Key
{
get
{
return _key;
}
set
{
_key = value;
this.NotifyPropertyChanged(p => p.Key);
}
}
string _lang;
public string Lang
{
get
{
return _lang;
}
set
{
_lang = value;
this.NotifyPropertyChanged(p => p.Lang);
}
}
string _audio;
public string Audio
{
get
{
return _audio;
}
set
{
_audio = value;
this.NotifyPropertyChanged(p => p.Audio);
}
}
string _pron;
public string Pron
{
get
{
return _pron == null ? string.Empty : string.Format("[{0}]", _pron);
}
set
{
_pron = value;
this.NotifyPropertyChanged(p => p.Pron);
}
}
string _def;
public string Def
{
get
{
return _def;
}
set
{
_def = value;
this.NotifyPropertyChanged(p => p.Def);
}
}
System.Collections.ObjectModel.ObservableCollection<SentModel> _sentCollection;
public System.Collections.ObjectModel.ObservableCollection<SentModel> SentCollection
{
get
{
return _sentCollection;
}
set
{
_sentCollection = value;
this.NotifyPropertyChanged(p => p.SentCollection);
}
}
}
}
SentModel.cs
using System;
namespace EternalDict.Model
{
public class SentModel : PropertyChangedBase
{
string _orig;
public string Orig
{
get
{
return _orig;
}
set
{
_orig = value;
this.NotifyPropertyChanged(p => p.Orig);
}
}
string _trans;
public string Trans
{
get
{
return _trans;
}
set
{
_trans = value;
this.NotifyPropertyChanged(p => p.Trans);
}
}
}
}
ViewModel/DictViewModel.cs则用来为View/DictView.xmal提供数据
这里我使用海词http://dict.cn/提供的API,通过Linq to XML进行解析。不过有个问题,海词的API可以提供GBK和UTF8这两种编码的服务,不过当前UTF8并不提供汉英翻译的功能,而silverlight并不支持GBK的编码转换,所以也只能实现英汉查找。也许某天你会发现汉英查找可用了,那么八成是海词官方升级了API。
该类的代码如下
using System;
using System.Net;
using System.Xml.Linq;
using System.Linq;
using System.Text;
using EternalDict.Model;
namespace EternalDict.ViewModel
{
public class DictViewModel
{
string _wordToQuery;
public DictModel Dm { get { return _dm; } set { _dm = value; } }
private DictModel _dm;
public DictViewModel()
{
_dm = new DictModel();
}
public void QueryWord(string wordToQuery)
{
this._wordToQuery = wordToQuery;
string apiUrlString = string.Format("http://api.dict.cn/ws.php?utf8=true&q={0}", this._wordToQuery);
Uri endPoint = new Uri(apiUrlString);
WebClient client = new WebClient();
client.DownloadStringAsync(endPoint);
client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
}
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
this.ParseXml(e.Result);
}
}
void ParseXml(string stringToParse)
{
/*Silverlight不支持其他编码 囧
Encoding gbk = Encoding.GetEncoding("GBK");
Encoding utf8 = Encoding.UTF8;
byte[] gbkBytes = gbk.GetBytes(stringToParse);
byte[] utf8Bytes = Encoding.Convert(gbk, utf8, gbkBytes);
char[] utf8Chars = new char[utf8.GetCharCount(utf8Bytes, 0, utf8Bytes.Length)];
utf8.GetChars(utf8Bytes, 0, utf8Bytes.Length, utf8Chars, 0);
stringToParse = new string(utf8Chars);
*/
XDocument xDoc = XDocument.Parse(stringToParse);
var nodeDict = xDoc.Root;
var audio = nodeDict.Elements().Where(p => p.Name == "audio").SingleOrDefault();
var lang = nodeDict.Elements().Where(p => p.Name == "lang").SingleOrDefault();
var pron = nodeDict.Elements().Where(p => p.Name == "pron").SingleOrDefault();
var def = nodeDict.Element("def").Value;
_dm.Audio = audio == null ? string.Empty : audio.Value;
_dm.Def = def.Equals("Not Found") ? "未找到该单词的释义" : def;
_dm.Key = this._wordToQuery;
_dm.Lang = lang == null ? string.Empty : lang.Value;
_dm.Pron = pron == null ? "无" : pron.Value;
var eleSents = nodeDict.Elements().Where(p => p.Name == "sent");
if (eleSents != null)
{
_dm.SentCollection = new System.Collections.ObjectModel.ObservableCollection<SentModel>();
foreach (var item in eleSents)
{
SentModel sm = new SentModel();
sm.Orig = item.Element("orig").Value;
sm.Trans = item.Element("trans").Value;
_dm.SentCollection.Add(sm);
}
}
}
}
}
这里公开了DictModel这个属性,用于为View提供数据。在View中完全通过数据绑定与其通讯。现在看下DictView.cs中最重要的几行代码
DictViewModel dvm = new DictViewModel();
public DictView()
{
InitializeComponent();
Loaded += new RoutedEventHandler(Dict_Loaded);
}
void Dict_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = dvm;
}
在View加载后便将ViewModel本身作为其DataContext。当点击查询按钮的时候便调用DictViewModel的QueryWord方法。
private void btnLookUp_Click(object sender, RoutedEventArgs e)
{
dvm.QueryWord(txtWord.Text.Trim());
}
剩下的就是在DictView.xaml中进行UI的设计了,代码比较多就不贴了。比较关键的是
<StackPanel DataContext="{Binding Dm}" Orientation="Vertical" >
这里将BM绑定到该StackPanel的DataContext上,其可视化树上的所有子孙元素便都可以通过Binding与Model进行关联了。
源码下载:点此下载

浙公网安备 33010602011771号