原創|其它|編輯:郝浩|2009-06-15 17:07:58.000|閱讀 604 次
概述:最近比較關注MVVM(Model-View_ViewModel)模式,該模式十分適合WPF/Silverlight的開發。出于練習的目的打算使用Silverlight做個英漢詞典(可能是由于近來瘋狂的聽VOA的緣故),下面針對該項目進行簡單的分析
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
最近比較關注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提供數據
這里我使用提供的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("//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進行關聯了。
源碼下載:
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:博客園