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


    最近比较关注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进行关联了。

    源码下载:点此下载
    在线体验:http://024hi.com/lab/ria/dict.html

  • 相关阅读:
    在画图时添加中文
    legend图例
    数组的拼接
    将多维数组改为一维数组
    ChinaCock扫描控件介绍-使用TCCBarcodeScanner引起app闪退
    ChinaCock打印控件介绍-TCCFujitsuPrinter实现蓝牙针式打印
    用NetHttpClient执行Post操作遇到的问题
    【转】FireMonkey ListView 自动计算行高
    基于MQTT的串口数据转发器
    kbmMW均衡负载与容灾(1)
  • 原文地址:https://www.cnblogs.com/024hi/p/1503169.html
Copyright © 2020-2023  润新知