十二月 2, 2009

[转]使用MVVM模式打造英汉词典

Written by

 

     注:  本文为转载,转载必须保留原作者信息及其原始链接!

     原址: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模式。

老规矩,先看下运行时的截图
image

这里说下我的开发环境

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并添加相应的文件,最终的解决方案视图如下

image

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进行关联了。

源码下载:点此下载

 

 

Category : .NetC#Window$WPF其他

Tags :

Comments

4 Responses

  1. Denver说道:

    Keep on writing and chggniug away!

  2. ich bin mir da nicht so sicher. auch offline konfigurieren wir unsere Kommunikation selber und sagen nicht allen, daß wir gerade neue Schuhe gekauft haben oder erörtern mit allen, wie das Kindergartenfest zu organisieren ist. Ich habe den Eindruck, dass das Einbeziehen unterschiedlicher Gruppen in die Kommunikation hier ansprechend gelöst werden könnte, so daß auch “normale” Menschen es nützlich finden.

  3. http://www./说道:

    I'm so glad you posted about your special day so we could see what you were up to. I think this was such a special way to celebrate your mom's birthday and I bet she loved it.

  4. esurrance说道:

    I am just writing my resume as a realtor and I am getting difficulty to place things into words inside a professional way.What are the good examples from the duties and achievements which i will include?

发表评论

电子邮件地址不会被公开。

Proudly powered by WordPress and Sweet Tech Theme