估计大家看到这个标题,可能还无法理解我这个系统是用来干什么的,先说一个场景,犹如一些咖啡厅的心语墙,客户可以找服务员索取便签纸,写下自己的心语,然后在心语墙上找一个合适的位置贴下。对于这个便签纸,自己在将来的某一天再次光顾这家咖啡厅还可以看到自己以前贴下的心语。当然,其他的顾客也可以浏览,说了这么多,如果您感兴趣,可以猛击:http://fendouzl.s2.jutuo.net 。如果不登录,还有很多功能看不到哦。不过由于时间有限,又要工作,又要做这个毕设系统,还得写论文,因此,目前这个系统还是比较粗糙的,有时间我会去完善之,因为这个系统是我自己在生活中觉得的确需要,正好以前学了silverlight,便想把这个生活模型使用silverlight来模拟,尽管模拟的不好,大家不要见笑,可以直接给我留言指正,我会加以改正的哈。
下面先看看其中一个功能模块的截图
作为一个技术性文章,还是来说说本系统技术方便的事情,不然真会被其他的同学说我在这打广告了。
1 系统架构设计
首先,我想说的是系统的架构,个人觉得这个做一个系统的时候,最好有一个架构图,有了这个架构图,便可以通过这个图导出一个合理的解决方案以及解决方案里面的项目,之后的工作便是在各个项目中填充代码,相对来说还是比较容易的。
1.1 服务器端架构设计
服务器端架构设计的出发点便是如何高效快捷的访问数据库。如图下图所示,可以看到本系统服务端分为四层和三个辅助性的类库,分别是业务逻辑层、工厂层、数据链路接口层、数据链路层、数据访问工具层、公共层、数据库模板层。客户端通过WCF访问业务逻辑层的方法,由于业务逻辑层继承工厂层,因此这个工厂层通过反射技术,动态加载数据链路层的方法,并且辅助层的配合下完成数据库读写,最后把结果通过JSON序列化之后返回给客户端。
1.2 客户端架构设计
客户端主要是silverlight的实现,为了提高客户端代码的重构性和易移植性,决定在客户端使用MVVM模式,架构图如图28所示。其中View层便是UI界面的实现,Model层便是数据源,而ViewModel层便是为了让数据在View层显示的中介。客户端通过WCF请求数据,服务端把数据通过JSON序列化之后返回给客户端。
2.系统解决方案图
通过系统架构图,可以很容易的映射出系统解决方案,系统解决方案列表图如下图所示。目前,自己的技术还不怎么好,不过大型项目,为了避免逻辑混乱,是有必要去分层实现,使用必要的模式,如我这个客户端使用MVVM模式,服务器分为四层。
3 如何连接silverlight客户端上和服务器端
对于这个问题,大家一般都会只用WCF,当然,我也选择这个方式,因为相对比较容易,并且很方便。

public void Get**FromDB() { string query = “condition” Proxy.GetListAsync(JsonConvert.SerializeObject(query)); Proxy.GetListCompleted += new EventHandler<UserOwnWallServiceReference.GetListCompletedEventArgs>(Proxy_GetListCompleted); } } void Proxy_GetListCompleted(object sender, UserOwnWallServiceReference.GetListCompletedEventArgs e) { Deployment.Current.Dispatcher.BeginInvoke(delegate { if (e.Error == null) { _UserOwnWallCollection = JsonConvert.DeserializeObject<ObservableCollection<UserOwnWall>>(e.Result.ToString()); InitUserUI(); } }); }}
这段代码大致展示了用户如何使用WCF服务代理契约去访问远程数据,至于如何去编写这个服务契约,使用是需要注意什么问题,我就不详细讲了,因为在使用的时候的确会遇到各种奇奇怪怪的问题,不过主要应该是配置文件的改动。
4 用户控件移动代码详解
大家如何查看了http://fendouzl.s2.jutuo.net,那么就应该知道,系统很多地方用到了便签纸在Canvas上移动的体验,为此,我写了一个类来管理便签纸移动,其实就是一个用户的控件在canvas上移动,代码如下:

1 public class MouseMoveHelper 2 { 3 #region move 4 static Point _curPoint; //当前点 5 static bool _mouseMoving = false; //定义是否移动中的布尔变量 6 public static void MouseButtonUpHandler(object sender, MouseButtonEventArgs e) 7 { 8 FrameworkElement element = sender as FrameworkElement; 9 element.SetValue(CustomCanvasControl.ZIndexProperty, 0); 10 //放开鼠标之后修改变量值 11 _mouseMoving = false; 12 //停止捕捉鼠标位置 13 element.ReleaseMouseCapture(); 14 //设置当期X Y坐标为0 15 _curPoint.X = 0; 16 _curPoint.Y = 0; 17 //恢复鼠标指针样式 18 element.Cursor = null; 19 } 20 21 public static void MouseButtonDownHandler(object sender, MouseButtonEventArgs e) 22 { 23 FrameworkElement element = sender as FrameworkElement; 24 element.SetValue(CustomCanvasControl.ZIndexProperty, 1); 25 //获得当前鼠标的位置 26 _curPoint = e.GetPosition(element.Parent as CustomCanvasControl); 27 //设置开始拖动的值 28 _mouseMoving = true; 29 if (null != element) { 30 //捕捉鼠标位置 31 element.CaptureMouse(); 32 element.Cursor = Cursors.Hand; 33 } 34 } 35 36 public static void MouseMoveHandler(object sender, MouseEventArgs e) 37 { 38 FrameworkElement element = sender as FrameworkElement; 39 if (_mouseMoving) { 40 try { 41 double currX = e.GetPosition(element.Parent as CustomCanvasControl).X - _curPoint.X; 42 double currY = e.GetPosition(element.Parent as CustomCanvasControl).Y - _curPoint.Y; 43 44 //得到当前画布的宽度和高度 45 double currCanvasWidth = (element.Parent as Canvas).ActualWidth; 46 double currCanvasHeight = (element.Parent as Canvas).ActualHeight; 47 48 //得到当前移动目标的宽度高度 49 double currElementWidth = element.ActualWidth; 50 double currElementHeight = element.ActualHeight; 51 52 if ((currY + (double)element.GetValue(CustomCanvasControl.TopProperty) < 0) || 53 (currX + (double)element.GetValue(CustomCanvasControl.LeftProperty) < 0) 54 || (currY + (double)element.GetValue(CustomCanvasControl.TopProperty) > currCanvasHeight - currElementHeight) || 55 (currX + (double)element.GetValue(CustomCanvasControl.LeftProperty) > currCanvasWidth - currElementWidth)) { 56 //不作任务操作,不移动 57 } else { 58 59 //设置对象坐标 60 element.SetValue(CustomCanvasControl.TopProperty, currY + (double)element.GetValue(CustomCanvasControl.TopProperty)); 61 element.SetValue(CustomCanvasControl.LeftProperty, currX + (double)element.GetValue(CustomCanvasControl.LeftProperty)); 62 } 63 } catch { 64 } 65 } 66 //保存当前坐标值 67 _curPoint = e.GetPosition(element.Parent as CustomCanvasControl); 68 } 69 70 #endregion 71 }
5 Json序列化
目前用来保存和传递数据一般使用Json和XML.使用这两个技术,相对比较容易,重要的很多平台都使用这个两中方式,因此比较通过,Json的使用方式基本是就是序列化和反序列化,使用比较多的是以下两个方法:

JsonConvert.SerializeObject()
JsonConvert.DeserializeObject<>()
6 HTML 5 GelLocation API
因为系统需要定位,因为使用了HTML 5 的定位API,这个相对来说还是比较容易的,就是一个API,自己的去调用就行,还是给出代码:

1 function getUserLocation() { 2 if (navigator.geolocation) { 3 navigator.geolocation.getCurrentPosition(show_map); 4 } else { 5 alert("您的浏览器不支持HTML 5来获取地理位置信息。"); 6 } 7 } 8 function show_map(position) { 9 var latitude = position.coords.latitude; 10 var longitude = position.coords.longitude; 11 callSL(latitude, longitude); 12 } 13 14 function callSL(latitude, longitude) { 15 var slHost = document.getElementById("SilverlightControl"); 16 var page = slHost.Content.FootprintContainer; 17 slHost.Content.FootprintContainer.Process(longitude, latitude); 18 }
需要注意的是,Silverlight如何与javascript通信,代码中也有体现,如何大家感兴趣还是去查看相关资料,
7 早来的总结
这个总结的确来的比较早吧,因为还有一些用到的技术还没有来得及写,好不容易一个假期,我却需要来写毕设,马上又得去上班,因此的确没有更多的时间,再加上自己的确还有很多说不明白讲不清楚。不得不说一个人想将来过的好一点,年轻的时候就需要去拼搏。对于前面我讲的,相信大家也注意到了,我对代码的细节没有做更多的讲解,因为现在网上资源还是比较丰富的,只要大家知道有这么回事,知道关键词,便可以很容易的找到答案,因此我写的这篇文章的重点不是在说具体代码是如何实现的,而是提到一个个知识点,一条条思路。说到这儿,相信大虾开始笑了,不过我还是想说说,成为大虾是一个过程,而不是一个结果。