[MVC]MVC模式结合Mediator模式的运用

mikel阅读(929)

Mediator模式有一种本事,就是可以让本身需要互相协作的对方,可以不用知道彼此,而把两者之间的联系,转交给Mediator来处理。换句 话说,Mediator模式解除了需要互相协调的对象之间的依赖。这也是Mediator(调停者)模式名字的由来。一个颇为形象的例子是聊天室。进入聊 天室的用户总是要彼此通信的,这些对象如果直接进行交互,就会彼此连接,最后织成一张纷繁复杂的大网。要分清彼此之间的关系,真可以说是“剪不断理还乱” 了。所以,引入一个聊天室对象来管理用户间的交流,就势成必然。

Mediator模式与Facade模式都是管理复杂对象的行家里手,不过 二者在运用上还是有本质的不同。Facade是门面,通过它隔断了客户端与复杂对象之间的直接关系。Mediator是仲裁者,哪里出现纠纷哪里就有它的 身影。Facade对象对于客户端来说是可见的,而隐藏了复杂对象;Mediator对象对于客户端来说则是隐藏的,客户端直接调用复杂对象,而复杂对象 之间的关系,则转交给了Mediator。

MVC模式则是职责分离的典范,就好似三权分立一般,各司其职。Model负责提供数 据,View则负责显示数据,Controller则负责控制Model与View之间的交互,封装了领域逻辑。这样的职责分离形式,能够有效地解除数 据、业务逻辑与UI界面之间的耦合关系。但是,在MVC模式中,由于业务逻辑的问题,很有可能在Controller之间还需要进行交互。这种交互一旦增 多,就可能出现在一个Controller中出现不同的Controller,导致代码出现分散,形成霰弹式修改的坏味道。

Marlon在其博客上发表了一篇文章, 有效地将MVC模式与Mediator模式两者结合,创造出一种称之为MVC+M的模式,有效地解决了Controller对象之间相互依赖的问题。 Marlon实现了一个文件浏览器来展示这一模式。运行程序,当我们点击左边的目录树时,在右边就会显示当前目录下的所有文件。UI如图所示:

左 边视图对应的控制对象为DirectorySelectorController,而右边视图对应的则为FileSelectorController对 象。Marlon统一定义了一个接口IColleague,作为Mediator模式中参与者的抽象接口,并让相关的Controller实现它。类图如 下所示:

每个Controller对象所接收的Mediator对象都是相同的,因为Mediator对象作为BaseController基类的属性存在,并利用了Singleton模式,保证了Mediator对象只能存在一个:

public abstract class BaseController : INotifyPropertyChanged, IColleague

{

    static Mediator mediatorInstance = new Mediator();

    public Mediator Mediator { get; private set; }

 

    public BaseController()

    {

        //set the mediator to be the same one for every controller.

        Mediator = mediatorInstance;

    }

     //rest of implementation

}

 

在子类的构造函数中,通过调用Mediator对象的Register方法,建立了消息与Controller对象之间的映射关系。以FileSelectorController类为例:

public FileSelectorController()

{

    Mediator.Register(this, new[]

    {

        Messages.DirectorySelectedChanged

    });

}

Mediator类完成Controller对象之间的协调,其定义如下:

public class Mediator

{

    MultiDictionary<string, IColleague> internalList

        = new MultiDictionary<string, IColleague>();


    public void Register(IColleague colleague, IEnumerable<string> messages)

    {

        foreach (string message in messages)

            internalList.AddValue(message, colleague);

    }

 

    public void NotifyColleagues(string message, object args)

    {

        if (internalList.ContainsKey(message))

        {

            //forward the message to all listeners

            foreach (IColleague colleague in internalList[message])

                colleague.MessageNotification(message, args);

        }

    }

}

Register() 方法会将消息与Controller对象的映射注册到内部字典internalList中。而NotifyColleagues()方法则会遍历整个 internalList,然后执行Controller对象(体现为IColleague类型)的MessageNotification()方法。通 过MessageNotification()方法,每个Controller对象根据传输的消息字符串,做出相应的响应操作。例如在 FileSelectorController类中,就是根据Message的值,执行装载文件的业务逻辑:

public override void MessageNotification(string message, object args)

{

    switch (message)

    {

        case Messages.DirectorySelectedChanged:

            //load all files for the directory specified

            LoadFiles((DirectoryDisplayItem)args);

            break;

    }

}

如 果没有引入Mediator模式,由于需要在点击目录时显示当前目录的文件,因此在DirectorySelectorController类的 ItemSelected事件中,必须调用FileSelectorController对象获取文件信息,然后通过对应视图显示这些文件信息。这就导致 了DirectorySelectorController和FileSelectorController之间的依赖。现在,在 DirectorySelectorController的ItemSelected事件中,就可以通过Mediator来实现文件信息的读取与显示:

//event handler for the selecting changed

void ItemSelected(object sender, RoutedEventArgs e)

{

    TreeView treeView = (TreeView)e.OriginalSource;

    //Send a message that an item is selected and pass the object selected

    Mediator.NotifyColleagues(Messages.DirectorySelectedChanged, treeView.SelectedItem);

}

Marlon实现的MVC+M模式有效地解除了Controller对象之间的耦合关系,其中,他引入了IColleague接口对Controller的相关方法进行了抽象。不过,这样的接口并非必须,正如我在《Strategy模式与Delegate委托》 一文中提到的接口与委托之间的关系,我们完全可以用委托来代替IColleague接口的定义,使整个结构变得更加的灵活。由于引入了委托与消息对象的映 射关系,因此在Controller类的MessageNotification()方法中,不再需要用switch语句来判断消息的值,而是直接根据映 射关系,调用委托对象所指代的方法逻辑。Mediator类可以修改为:

public class Mediator

{

    IDictionary<string,Action<object>> m_List = new Dictionary<string,Action<object>>();

 

    public void Register(string message,Action<object> callback)

    {

        m_List.Add(message,callback);

    }

 

    public void NotifyColleagues(string message, object args)

    {

        if (m_List.ContainsKey(message))

        {

            m_List[message](args);

        }

    }

}

与之对应的,FileSelectorController可以修改为:

public FileSelectorController()

{

    Mediator.Register(Messages.DirectorySelectedChanged,

        (obj) =>

        {

            LoadFiles((DirectoryDisplayItem)obj);

        });

}

至于最初定义在Controller类的MessageNotification()方法,则被匿名函数所代替,已经不再需要了。

本文已在ITPub上全文发表

[资源]20个让Web Developer开发生涯更加轻松的工具

mikel阅读(728)

源文:  http://net.tutsplus.com/articles/web-roundups/20-tools-to-make-the-life-of-a-web-developer-easier/

简译:  PuterJam

 

Typetester

一个在线对比字体的工具,可以很直观得看到不同字体的差异

 

pForm

创建HTML表单的工具,能在瞬间创建很美观的表单,并输出html代码

 

ColourLovers

在线的调色板工具,你能够搜索到很多配色方案或提交你的配色方案

 

Firebug

无所不能的firebug,不多介绍了

 

HTML Entity Character Lookup

HTML 实体 查询工具

 

960 Grid System

960 是个神奇的数字,960 是横向尺寸,960 网格系统是能够让设计师快速创建网页原型的辅助系统。可以比喻成网页的黄金分割线

pfvyzisv.jpg

 

 

Em Calculator

EM换算器~ ,可以把像素换算成 em 单位。

 

Browser Shots

多浏览器截屏工具,可以提供多个平台,不同浏览器的页面截屏效果

 

Icon Finder

还在为找图标发愁么,一个不错的图片搜索工具。

 

WhatTheFont

当你图片里看到一个好看的文字而不知道字体名称时,可以用它来帮你分析字体类型

 

MeasureIt

firefox插件,可以在页面上显示一个尺子

 

ColorZilla

同样是firefox插件,可以在页面上取色,前端开发必备

 

Pingdom

一个在线的抓包工具

 

Test Everything

Test Everything 提供了很多测试工具来测试你的站点。从css html 到SEO ,从网络工具到优化应有尽有。

 

CSS Sprite Generator

样式精灵,这类工具很多了,就是把图片分割并且输出成css

 

Web Developer Toolbar

也是一个非常强大的web开发工具。

 

Domainr

域名查询工具,很方面查询域名的使用情况,并且给出未注册域名的建议。(需要翻墙)

 

Font Burner

字体查询工具,并且提供在线的字体解决方案。仅限英文。

 

Smush.It

图片优化工具,能够优化你的图片尺寸

 

Load Impact

可以模拟不同地区的用户访问你的站点的情况。并且以图表的情况反馈结果。

[ASP.NET]重提URL Rewrite(1):IIS与ASP.NET

mikel阅读(652)

  之前觉得这个话题已经被谈滥了。URL Rewrite早已经被广大开发人员所接受,网上关于URL Rewrite的组件和文章也层出不穷,但是总是让我感觉意犹未尽,于是最终还是忍不住提笔写了这系列文章。这些文章不会谈论URL Rewrite的价值与意义,而只会谈论纯技术的内容。文章中也不会有详尽地实现分析,而是结合了我的经验,从应用角度来讲解这个话题。您已经知道的,您 还不知道的,别处已经讲过的,或者还没有讲过的,希望这系列文章的“旧事重提”不会让您觉得沉闷,并且能让您了解ASP.NET中URL Rewrite的方方面面。如果您以后再遇到URL Rewrite方面的问题是能够想到这几篇文章,估计我做梦也会笑出声来。

  要充分理解文章后面谈到的话题,我们必须简单的了解一下IIS与ASP.NET的通信过程。我在这里讲解的是IIS 6服务器。至于IIS 5和IIS 7,前者可以说已经被淘汰了,而后者的“经典模式”与IIS 6可谓如出一辙,而新的“管道模式”其实是讲ASP.NET中的某些概念与IIS进行了深度集成。我相信,如果您了解了IIS 6和ASP.NET,在IIS 7的集成模式下也不会有任何问题。

  首先我们来看一幅简单的示意图,展示了IIS从收到Request开始,到返回Response整个过程中的几个主要步骤:

  1. IIS收到请求。
  2. 选择器根据URL的特点与IIS中的配置,选择一个ISAPI用于处理该请求——现在自然会选择ASP.NET ISAPI。
  3. ASP.NET执行引擎接收到请求,于是初始化数据(例如构建各种对象)。
  4. 开始触发各种Pipeline事件,自然先从BeginRequest开始。
  5. 经过了多个Pipeline事件,ASP.NET根据配置为当前请求选择一个合适的Handler或HandlerFactory进行处理(当然特殊情况例外,例如已经在之前的事件中直接输出结果并结束请求了)。
  6. 经过了Handler处理之后又经过几个Pipeline事件,以EndRequest结束。
  7. 输出Response。

  在一个ASP.NET应用中如果要进行URL Rewrite,那么一般就是在BeginRequest事件中调用HttpContext的RewritePath方法,将该请求重新“定位”至一个目 标URL。例如我们就可以在Global.asax中重写Application_BeginRequest方法来实现这一点:

  之所以在BeginRequest中进行Rewrite,是因为这个事件是在所有Pipeline事件中最早被触发的。在这时进行了重新“定位 ”之后,当前HttpContext中的一些属性也就发生了相应的变化(例如HttpContext.Request.Path)。这样,接下来的 Pipeline事件的处理程序逻辑就会受到影响。例如在需要根据目录进行权限判断时,就会使用“定位”后的路径,而不是ASP.NET所收到的请求。自 然最“显著”的变化就是对Handler的选择,例如上例,我们把请求重新定位至“CustomerList.aspx”文件,这样ASP.NET引擎就 会选择*.aspx所对应的System.Web.UI.PageHandlerFactory类对请求进行处理。

public class Global : System.Web.HttpApplication
{
    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        HttpContext context = HttpContext.Current;
 
        if (context.Request.Path.Equals("/Customers",
            StringComparison.InvariantCultureIgnoreCase))
        {
            context.RewritePath("~/CustomerList.aspx");
        }
    }
}

  最后插句提外话,有两个概念需要区分开来,那就是“ASP.NET Pipeline”与“Web Forms”。两者都是ASP.NET里的重要模型,但是差别还是非常大的:

  • ASP.NET Pipeline:作为每个ASP.NET应用所接受到的请求来说,都会经过这个“管道”进行处理。这是一个ASP.NET级别的模型。
  • Web Forms:在ASP.NET Pipeline的执行过程中,其中有一个步骤是选择一个合适的Handler(或HandlerFactory)来处理请求。如果是aspx页 面,ASP.NET就会选择System.Web.UI.PageHandlerFactory类,在这个类中才最终形成了WebForms模型。

  其实上面这句话的“形成”二字可能也不太确切。因为Web Forms可能应该是一个可以独立使用的执行引擎和模型,而System.Web.UI.PageHandlerFactory中也只是利用了这个模型而 已。我们在编写ASP.NET应用时,完全可以根据我们的需要,在其他地方使用这个模型。例如在《技巧:使用User Control做HTML生成》一文中,我们就在一个Generic Handler中把ascx当作模板来生成内容。

相关链接:

(2)使用已有组件进行URL Rewrite

(3)在URL Rewrite后保持PostBack地址

(4)不同级别URL Rewrite的一些细节与特点

[JQuery]JQuery自动提示插件

mikel阅读(1109)

页面代码: 

  1. <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>  
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  3. <html xmlns="http://www.w3.org/1999/xhtml" >  
  4. <head id="Head1" runat="server">  
  5. <mce:script language="JavaScript" src="JavaScript/JQuery1.2.js" mce_src="JavaScript/JQuery1.2.js"></mce:script>  
  6. <mce:script language="javascript"><!–  
  7.     var __moveIndex = -1;  
  8.     var _x;  
  9.     var _y;  
  10.     var _w;  
  11.     var _data=[];  
  12.     var eSrc = null;  
  13.     var _searchUrl = '<%=ResolveClientUrl("~/search/?k=") %>';  
  14.     $(function(){  
  15.         eSrc = $('#<%=TKeyWord.ClientID %>');  
  16.         addChoseDiv();  
  17.         $("body").click(function(){  
  18.             var target = event.srcElement || event.target;  
  19.             var eID = $(target).attr("id");  
  20.             if(eID!="TKeyWord")  
  21.             {  
  22.                 $("#matchLay").hide();     
  23.             }  
  24.         });  
  25.     });  
  26.       
  27.     //keydown事件  
  28.     function keydown()  
  29.     {  
  30.         if(event.keyCode==13)//回车键  
  31.         {  
  32.             if(__moveIndex>0)  
  33.             {  
  34.                 eSrc.val(_data[__moveIndex-1]["colKeyName"]);  
  35.                 $("#matchLay").hide();  
  36.                 document.location.href=_searchUrl+encodeURI(_data[__moveIndex-1]["colKeyName"]);  
  37.             }  
  38.             else if($.trim(eSrc.val())!=="")  
  39.             {  
  40.                 $("#matchLay").hide();  
  41.                 document.location.href=_searchUrl+encodeURI(eSrc.val());  
  42.             }  
  43.              
  44.            return false;  
  45.         }  
  46.     }  
  47.       
  48.     //初始化层  
  49.     function addChoseDiv()  
  50.     {  
  51.         _x = pageX(eSrc[0]);  
  52.         _y = pageY(eSrc[0])+eSrc.height()+5;  
  53.         _w =eSrc.width()+4;  
  54.           
  55.         $("<div id='matchLay' z-index='500'   style='background-color:#ffffff;display:none;width:"  
  56.         +_w+"px;position:absolute;left:"+_x+"px;top:"+_y  
  57.         +"px;border-left:1px solid #000000;border-bottom:1px solid #000000;border-right:1px solid #000000;' ></div>").appendTo($("body"));  
  58.     }  
  59.       
  60.     //选定匹配项导航函数  
  61.     function SelKey(obj)  
  62.     {  
  63.        eSrc.val($(obj).children().filter(":nth-child(1)").text());  
  64.        document.location.href=_searchUrl+encodeURI(eSrc.val());  
  65.        $("#matchLay").hide();    
  66.     }  
  67.       
  68.     //匹配函数  
  69.     function IsMatch()  
  70.     {  
  71.       
  72.         var rs = $.ajax({  
  73.             type:"GET",  
  74.             cache:false,  
  75.             url:"SearchPro.aspx",  
  76.             success:function(data,status){  
  77.                 //alert(data);  
  78.             }  
  79.         });  
  80.   
  81.         var v = eSrc.val();  
  82.         if(v=="")//输入为空,返回  
  83.         {  
  84.             $("#matchLay").hide();     
  85.             return false;  
  86.         }  
  87.           
  88.         _data = _Default.GetSkeys(v).value;  
  89.           
  90.         if(_data!=null && _data.length>0)//生成匹配div  
  91.         {  
  92.             var shtm = "<table width='100%' cellspacing='0' id='sList' >";  
  93.             for(var i=0;i<_data.length;i++)  
  94.             {  
  95.                 shtm+="<tr  onmouSEOver='mouSEOver(this)'  onclick='SelKey(this)'><td align='left'>"+_data[i]["colKeyName"]+"</td>";  
  96.                 shtm+="<td align='right' style="color:green" mce_style="color:green">"+RelNumber(parseInt(_data[i]["colResults"],10))+" 结果</td>";  
  97.                 shtm+="</tr>"  
  98.             }  
  99.             shtm+="</table>";  
  100.             $("#matchLay").html(shtm);  
  101.             $("#matchLay").show();     
  102.             return true;  
  103.         }else //没有匹配隐藏div  
  104.         {  
  105.             $("#matchLay").hide();     
  106.             return false;  
  107.         }  
  108.     }  
  109.   
  110.     //search Button click事件  
  111.     function goSearch(k)  
  112.     {  
  113.         document.location.href=_searchUrl+encodeURI(k);  
  114.     }  
  115.       
  116.     //onkeyup事件  
  117.     function matchBase()  
  118.     {  
  119.         if(!IsMatch()) return false;//没有匹配返回  
  120.          
  121.          if(event.keyCode==38)//上箭头  
  122.         {  
  123.             if(__moveIndex==-1 || __moveIndex==1)  
  124.             {  
  125.                 mouseOver($("#sList tr").length);  
  126.             }else  
  127.             {  
  128.                 mouseOver(__moveIndex-1,__moveIndex);  
  129.             }  
  130.         }  
  131.         else if(event.keyCode==40)//下箭头  
  132.         {  
  133.             if(__moveIndex==$("#sList tr").length)  
  134.             {  
  135.                 mouseOver(1,$("#sList tr").length);  
  136.             }else  
  137.             {  
  138.                 if(__moveIndex==-1)  
  139.                 {  
  140.                     mouseOver(1,1);  
  141.                 }else  
  142.                 {  
  143.                     mouseOver(__moveIndex+1,__moveIndex);  
  144.                 }  
  145.             }  
  146.              
  147.         }  
  148.     }  
  149.       
  150.     //提示层mouseover事件  
  151.     function mouseOver()  
  152.     {  
  153.         var obj = null;  
  154.         var n = __moveIndex ;  
  155.         if(n==-1) n=1;  
  156.         var oldObj =$("#sList tr:nth-child("+n+")");  
  157.         if(typeof arguments[0]=="object")  
  158.         {  
  159.             obj = $(arguments[0]);  
  160.         }else  
  161.         {  
  162.             obj = $("#sList tr:nth-child("+arguments[0]+")");  
  163.             oldObj =$("#sList tr:nth-child("+arguments[1]+")");  
  164.         }  
  165.           
  166.         oldObj.css("backgroundColor","#ffffff");  
  167.         oldObj.children().filter(":nth-child(1)").css("color","#000000");  
  168.         oldObj.children().filter(":nth-child(2)").css("color","green");  
  169.           
  170.         obj.css("backgroundColor","#3366CC");  
  171.         obj.children().filter(":nth-child(1)").css("color","#ffffff");  
  172.         obj.children().filter(":nth-child(2)").css("color","#ffffff");  
  173.           
  174.         __moveIndex = obj[0].rowIndex+1;  
  175.     }  
  176.       
  177.     //格式化正整数123,456  
  178.     function RelNumber(num)  
  179.     {  
  180.         var t=num>0?num:Math.abs(num);  
  181.         var str=num.toString();  
  182.         var il = str.length;  
  183.         var n = 1;  
  184.         while(t>1000)  
  185.         {    
  186.             t/=1000;  
  187.             str=str.substring(0,il-n*3)+","+str.substr(il-n*3);  
  188.             ++n;  
  189.         }  
  190.         return str;  
  191.     }  
  192.       
  193.     //取得元素x坐标  
  194.     function pageX(elem)  
  195.     {  
  196.         return elem.offsetParent?(elem.offsetLeft+pageX(elem.offsetParent)):elem.offsetLeft;  
  197.     }  
  198.     //取得元素y坐标  
  199.     function pageY(elem)  
  200.     {  
  201.         return elem.offsetParent?(elem.offsetTop+pageY(elem.offsetParent)):elem.offsetTop;  
  202.     }  
  203. // –></mce:script>  
  204. </head>  
  205. <body>  
  206. <form runat="server">  
  207. <asp:TextBox AutoCompleteType="Disabled"  runat="server" ID="TKeyWord" Width="250px" ></asp:TextBox>  
  208. <asp:Button runat="server" ID="Btn_search" Text="Search"  />  
  209. </form>  
  210. </body>  
  211. </html>  

   

后台代码: 

  1. using System;  
  2. using System.Data;  
  3. using System.Configuration;  
  4. using System.Web;  
  5. using System.Web.Security;  
  6. using System.Web.UI;  
  7. using System.Web.UI.WebControls;  
  8. using System.Web.UI.WebControls.WebParts;  
  9. using System.Web.UI.HtmlControls;  
  10. using AjaxPro;  
  11.   
  12. public partial class _Default : System.Web.UI.Page   
  13. {  
  14.     private string NowKey = string.Empty;  
  15.     SHOPBill.SmartSearch.SearchBill sBill = new SHOPBill.SmartSearch.SearchBill();  
  16.   
  17.     protected void Page_Load(object sender, EventArgs e)  
  18.     {  
  19.         Utility.RegisterTypeForAjax(typeof(_Default));  
  20.         if (!IsPostBack)  
  21.         {  
  22.             TKeyWord.Attributes.Add("onkeyup""matchBase();");  
  23.             TKeyWord.Attributes.Add("onkeydown""keydown();");  
  24.             Btn_search.Style.Add("cursor""hand");  
  25.             Btn_search.Attributes.Add("align""absmiddle");  
  26.             Btn_search.Attributes.Add("onclick""if($.trim($('#" + TKeyWord.ClientID + "').val())==''){alert('关键字不能为空!',false);return false};document.location.href='" + ResolveClientUrl("~/search/?k=") + "'+encodeURI($('#" + TKeyWord.ClientID + "').val())");  
  27.           
  28.             List<SHOPModule.SmartSearch.SearchItem> list = sBill.SelectKeys();  
  29.             HttpContext.Current.Cache["SEARCHKEYS"] = list;  
  30.         }  
  31.   
  32.     }  
  33.   
  34.   
  35.   
  36.     [AjaxPro.AjaxMethod]  
  37.     public List<SHOPModule.SmartSearch.SearchItem> GetSkeys(string inputKey)  
  38.     {  
  39.         NowKey = inputKey;  
  40.         List<SHOPModule.SmartSearch.SearchItem> list = null;  
  41.         List<SHOPModule.SmartSearch.SearchItem> result = null;  
  42.         if (HttpContext.Current.Cache.Get("SEARCHKEYS") == null)  
  43.         {  
  44.             list = sBill.SelectKeys();  
  45.             HttpContext.Current.Cache["SEARCHKEYS"] = list;  
  46.         }  
  47.         else  
  48.         {  
  49.             list = HttpContext.Current.Cache.Get("SEARCHKEYS"as List<SHOPModule.SmartSearch.SearchItem>;  
  50.         }  
  51.   
  52.         result = list.FindAll(ListMatch);  
  53.         return result;  
  54.     }  
  55.   
  56.     private bool ListMatch(SHOPModule.SmartSearch.SearchItem m)  
  57.     {  
  58.         string k = SHOPCommUtility.Hz2Py.GetWholePinyin(m.colKeyName);  
  59.         return (MatchKeys(NowKey.ToLower(), m.colKeyName.ToLower()) || MatchKeys(NowKey.ToLower(), k.ToLower()));  
  60.   
  61.     }  
  62.   
  63.     private bool MatchKeys(string iKey, string K)  
  64.     {  
  65.         return K.Length >= iKey.Length && K.Substring(0, iKey.Length) == iKey;  
  66.     }  
  67. }  

 

汉字转拼音算法: 

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text.RegularExpressions;  
  4. using System.Text;  
  5.   
  6. namespace SHOPCommUtility  
  7. {  
  8.     /// <summary>  
  9.     /// 汉字转拼音类  
  10.     /// </summary>  
  11.     public class Hz2Py  
  12.     {  
  13.         private static int[] pyValue = new int[]  
  14.         {  
  15.             -20319,-20317,-20304,-20295,-20292,-20283,-20265,-20257,-20242,-20230,-20051,-20036,  
  16.             -20032,-20026,-20002,-19990,-19986,-19982,-19976,-19805,-19784,-19775,-19774,-19763,  
  17.             -19756,-19751,-19746,-19741,-19739,-19728,-19725,-19715,-19540,-19531,-19525,-19515,  
  18.             -19500,-19484,-19479,-19467,-19289,-19288,-19281,-19275,-19270,-19263,-19261,-19249,  
  19.             -19243,-19242,-19238,-19235,-19227,-19224,-19218,-19212,-19038,-19023,-19018,-19006,  
  20.             -19003,-18996,-18977,-18961,-18952,-18783,-18774,-18773,-18763,-18756,-18741,-18735,  
  21.             -18731,-18722,-18710,-18697,-18696,-18526,-18518,-18501,-18490,-18478,-18463,-18448,  
  22.             -18447,-18446,-18239,-18237,-18231,-18220,-18211,-18201,-18184,-18183, -18181,-18012,  
  23.             -17997,-17988,-17970,-17964,-17961,-17950,-17947,-17931,-17928,-17922,-17759,-17752,  
  24.             -17733,-17730,-17721,-17703,-17701,-17697,-17692,-17683,-17676,-17496,-17487,-17482,  
  25.             -17468,-17454,-17433,-17427,-17417,-17202,-17185,-16983,-16970,-16942,-16915,-16733,  
  26.             -16708,-16706,-16689,-16664,-16657,-16647,-16474,-16470,-16465,-16459,-16452,-16448,  
  27.             -16433,-16429,-16427,-16423,-16419,-16412,-16407,-16403,-16401,-16393,-16220,-16216,  
  28.             -16212,-16205,-16202,-16187,-16180,-16171,-16169,-16158,-16155,-15959,-15958,-15944,  
  29.             -15933,-15920,-15915,-15903,-15889,-15878,-15707,-15701,-15681,-15667,-15661,-15659,  
  30.             -15652,-15640,-15631,-15625,-15454,-15448,-15436,-15435,-15419,-15416,-15408,-15394,  
  31.             -15385,-15377,-15375,-15369,-15363,-15362,-15183,-15180,-15165,-15158,-15153,-15150,  
  32.             -15149,-15144,-15143,-15141,-15140,-15139,-15128,-15121,-15119,-15117,-15110,-15109,  
  33.             -14941,-14937,-14933,-14930,-14929,-14928,-14926,-14922,-14921,-14914,-14908,-14902,  
  34.             -14894,-14889,-14882,-14873,-14871,-14857,-14678,-14674,-14670,-14668,-14663,-14654,  
  35.             -14645,-14630,-14594,-14429,-14407,-14399,-14384,-14379,-14368,-14355,-14353,-14345,  
  36.             -14170,-14159,-14151,-14149,-14145,-14140,-14137,-14135,-14125,-14123,-14122,-14112,  
  37.             -14109,-14099,-14097,-14094,-14092,-14090,-14087,-14083,-13917,-13914,-13910,-13907,  
  38.             -13906,-13905,-13896,-13894,-13878,-13870,-13859,-13847,-13831,-13658,-13611,-13601,  
  39.             -13406,-13404,-13400,-13398,-13395,-13391,-13387,-13383,-13367,-13359,-13356,-13343,  
  40.             -13340,-13329,-13326,-13318,-13147,-13138,-13120,-13107,-13096,-13095,-13091,-13076,  
  41.             -13068,-13063,-13060,-12888,-12875,-12871,-12860,-12858,-12852,-12849,-12838,-12831,  
  42.             -12829,-12812,-12802,-12607,-12597,-12594,-12585,-12556,-12359,-12346,-12320,-12300,  
  43.             -12120,-12099,-12089,-12074,-12067,-12058,-12039,-11867,-11861,-11847,-11831,-11798,  
  44.             -11781,-11604,-11589,-11536,-11358,-11340,-11339,-11324,-11303,-11097,-11077,-11067,  
  45.             -11055,-11052,-11045,-11041,-11038,-11024,-11020,-11019,-11018,-11014,-10838,-10832,  
  46.             -10815,-10800,-10790,-10780,-10764,-10587,-10544,-10533,-10519,-10331,-10329,-10328,  
  47.             -10322,-10315,-10309,-10307,-10296,-10281,-10274,-10270,-10262,-10260,-10256,-10254  
  48.         };  
  49.   
  50.         private static string[] pyName = new string[]  
  51.         {  
  52.             "A","Ai","An","Ang","Ao","Ba","Bai","Ban","Bang","Bao","Bei","Ben",  
  53.             "Beng","Bi","Bian","Biao","Bie","Bin","Bing","Bo","Bu","Ba","Cai","Can",  
  54.             "Cang","Cao","Ce","Ceng","Cha","Chai","Chan","Chang","Chao","Che","Chen","Cheng",  
  55.             "Chi","Chong","Chou","Chu","Chuai","Chuan","Chuang","Chui","Chun","Chuo","Ci","Cong",  
  56.             "Cou","Cu","Cuan","Cui","Cun","Cuo","Da","Dai","Dan","Dang","Dao","De",  
  57.             "Deng","Di","Dian","Diao","Die","Ding","Diu","Dong","Dou","Du","Duan","Dui",  
  58.             "Dun","Duo","E","En","Er","Fa","Fan","Fang","Fei","Fen","Feng","Fo",  
  59.             "Fou","Fu","Ga","Gai","Gan","Gang","Gao","Ge","Gei","Gen","Geng","Gong",  
  60.             "Gou","Gu","Gua","Guai","Guan","Guang","Gui","Gun","Guo","Ha","Hai","Han",  
  61.             "Hang","Hao","He","Hei","Hen","Heng","Hong","Hou","Hu","Hua","Huai","Huan",  
  62.             "Huang","Hui","Hun","Huo","Ji","Jia","Jian","Jiang","Jiao","Jie","Jin","Jing",  
  63.             "Jiong","Jiu","Ju","Juan","Jue","Jun","Ka","Kai","Kan","Kang","Kao","Ke",  
  64.             "Ken","Keng","Kong","Kou","Ku","Kua","Kuai","Kuan","Kuang","Kui","Kun","Kuo",  
  65.             "La","Lai","Lan","Lang","Lao","Le","Lei","Leng","Li","Lia","Lian","Liang",  
  66.             "Liao","Lie","Lin","Ling","Liu","Long","Lou","Lu","Lv","Luan","Lue","Lun",  
  67.             "Luo","Ma","Mai","Man","Mang","Mao","Me","Mei","Men","Meng","Mi","Mian",  
  68.             "Miao","Mie","Min","Ming","Miu","Mo","Mou","Mu","Na","Nai","Nan","Nang",  
  69.             "Nao","Ne","Nei","Nen","Neng","Ni","Nian","Niang","Niao","Nie","Nin","Ning",  
  70.             "Niu","Nong","Nu","Nv","Nuan","Nue","Nuo","O","Ou","Pa","Pai","Pan",  
  71.             "Pang","Pao","Pei","Pen","Peng","Pi","Pian","Piao","Pie","Pin","Ping","Po",  
  72.             "Pu","Qi","Qia","Qian","Qiang","Qiao","Qie","Qin","Qing","Qiong","Qiu","Qu",  
  73.             "Quan","Que","Qun","Ran","Rang","Rao","Re","Ren","Reng","Ri","Rong","Rou",  
  74.             "Ru","Ruan","Rui","Run","Ruo","Sa","Sai","San","Sang","Sao","Se","Sen",  
  75.             "Seng","Sha","Shai","Shan","Shang","Shao","She","Shen","Sheng","Shi","Shou","Shu",  
  76.             "Shua","Shuai","Shuan","Shuang","Shui","Shun","Shuo","Si","Song","Sou","Su","Suan",  
  77.             "Sui","Sun","Suo","Ta","Tai","Tan","Tang","Tao","Te","Teng","Ti","Tian",  
  78.             "Tiao","Tie","Ting","Tong","Tou","Tu","Tuan","Tui","Tun","Tuo","Wa","Wai",  
  79.             "Wan","Wang","Wei","Wen","Weng","Wo","Wu","Xi","Xia","Xian","Xiang","Xiao",  
  80.             "Xie","Xin","Xing","Xiong","Xiu","Xu","Xuan","Xue","Xun","Ya","Yan","Yang",  
  81.             "Yao","Ye","Yi","Yin","Ying","Yo","Yong","You","Yu","Yuan","Yue","Yun",  
  82.             "Za""Zai","Zan","Zang","Zao","Ze","Zei","Zen","Zeng","Zha","Zhai","Zhan",  
  83.             "Zhang","Zhao","Zhe","Zhen","Zheng","Zhi","Zhong","Zhou","Zhu","Zhua","Zhuai","Zhuan",  
  84.             "Zhuang","Zhui","Zhun","Zhuo","Zi","Zong","Zou","Zu","Zuan","Zui","Zun","Zuo"  
  85.         };  
  86.   
  87.         /// <summary>  
  88.         /// 把汉字转换成拼音(全拼)  
  89.         /// </summary>  
  90.         /// <param name="hzString">汉字字符串</param>  
  91.         /// <returns>转换后的拼音(全拼)字符串</returns>  
  92.         public static string GetWholePinyin(string hzString)  
  93.         {  
  94.             // 匹配中文字符  
  95.             Regex regex = new Regex("^[\u4e00-\u9fa5]$");  
  96.             byte[] array = new byte[2];  
  97.             string pyString = "";  
  98.             int chrAsc = 0;  
  99.             int i1 = 0;  
  100.             int i2 = 0;  
  101.             char[] noWChar = hzString.ToCharArray();  
  102.   
  103.             for (int j = 0; j < noWChar.Length; j++)  
  104.             {  
  105.                 // 中文字符  
  106.                 if (regex.IsMatch(noWChar[j].ToString()))  
  107.                 {  
  108.                     array = System.Text.Encoding.Default.GetBytes(noWChar[j].ToString());  
  109.                     i1 = (short)(array[0]);  
  110.                     i2 = (short)(array[1]);  
  111.                     chrAsc = i1 * 256 + i2 – 65536;  
  112.                     if (chrAsc > 0 && chrAsc < 160)  
  113.                     {  
  114.                         pyString += noWChar[j];  
  115.                     }  
  116.                     else  
  117.                     {  
  118.                         // 修正部分文字  
  119.                         if (chrAsc == -9254)  // 修正"圳"字  
  120.                             pyString += "Zhen";  
  121.                         else  
  122.                         {  
  123.                             for (int i = (pyValue.Length – 1); i >= 0; i–)  
  124.                             {  
  125.                                 if (pyValue[i] <= chrAsc)  
  126.                                 {  
  127.                                     pyString += pyName[i];  
  128.                                     break;  
  129.                                 }  
  130.                             }  
  131.                         }  
  132.                     }  
  133.                 }  
  134.                 // 非中文字符  
  135.                 else  
  136.                 {  
  137.                     pyString += noWChar[j].ToString();  
  138.                 }  
  139.             }  
  140.             return pyString;  
  141.         }  
  142.     }  
  143. }  

 

 

[JQuery]仿google 的输入提示框JS类下载(jQuery plugin: Autocom

mikel阅读(754)

JQuery plugin: Autocomplete

Autocomplete an input field to enable users quickly finding and selecting some value, leveraging searching and filtering.

By giving an autocompleted field focus or entering something into it, the plugin starts searching for matching entries and displays a list of values to choose from. By entering more characters, the user can filter down the list to better matches.

This can be used to enter previous selected values, eg. for tags, to complete an address, eg. enter a city name and get the zip code, or maybe enter email addresses from an addressbook.

Current version: 1.0.2
Compressed filesize: 7596 bytes
License: MIT/GPL
Tested in: Firefox 2, IE 6 & 7, Opera 9, Safari 3

Files:

Download
Changelog
Demos
Documentation (Plugin Options)

Dependencies

Required

Optional

  • optional: bgiframe plugin to fix select-problems in IE, just include to apply to autocomplete

Support

  • Please post questions to the jQuery discussion list, putting [autocomplete] into the subject of your post, making it easier to spot it and respond quickly. Keep your question short and succinct and provide code when possible; a testpage makes it much more likely that you get an useful answer in no time.
  • Please post bug reports and other contributions (enhancements, features) to the jQuery bug tracker (requires registration). Please put [autocomplete] into the title of a ticket.

JQuery plugin: Autocomplete

Autocomplete an input field to enable users quickly finding and selecting some value, leveraging searching and filtering.

By giving an autocompleted field focus or entering something into it, the plugin starts searching for matching entries and displays a list of values to choose from. By entering more characters, the user can filter down the list to better matches.

This can be used to enter previous selected values, eg. for tags, to complete an address, eg. enter a city name and get the zip code, or maybe enter email addresses from an addressbook.

Current version: 1.0.2
Compressed filesize: 7596 bytes
License: MIT/GPL
Tested in: Firefox 2, IE 6 & 7, Opera 9, Safari 3

 

官方JS下载地址:http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/

[hadoop]Hadoop相关网络资源汇总

mikel阅读(1022)

(NOTE: 之前研究过的一些hadoop相关资料,在这里汇总起来,方便他人学习)
第一手资源
hadoop官方网站

最权威的官方资源之一

hadoop.cn(偶尔有一些有用信息)
手册

相关Blog
facebook工程师blog
hadoop0.19特性归纳
这个家伙很有意思,并且是研究hadoop的

http://www.blogjava.net/killme2008/archive/2008/06/05/206043.html


hadoop源码剖析不错的

http://caibinbupt.javaeye.com/blog/292073

也研究MapReduce的家伙



相关主题和文档



http://zkl-1987.javaeye.com/blog/365172

http://www.javaeye.com/topic/365172
hadoop namenode 高可用性(容灾)(Redundant Network Architecture, 相关软件有: Linux bonding, heartbeat
, DRBD Disk
)
http://www.hadoop.org.cn/document/Hadoop%20Namenode%20High%20Availability.pdf
图书

<<Pro hadoop>>
<<hadoop: the definitive guide>> (hadoop作者写的)
MISC

清华大学的分布式相关课程




[Flex]Flex与.NET互操作系列文章

mikel阅读(720)

    本系列文章主要介绍了关于Flex与.NET结合开发中的一些互操作性,包括网络通信、数据加载、数据传输、文件传输、以及应用于Flex与.NET协作开发的通信网关开源项目FluorineFx的相关知识点。

     开源项目FluorineFx就是专门针对.NET平台与Flex通信提供的AMF协议通信网关,我们可以通过FluorineFx很方便的完成与.NET的通信。 另外还可以轻松的实现及时文字沟通、视频语音通信等及时交互系统的开发。

     FluorineFx官方提供了安装包的下载和在线文档,可以帮助我们有效的利用FluorineFx来开发。 

     FluroineFx官方网站http://www.fluorinefx.com/    

     FluroineFx下载地址:http://www.fluorinefx.com/download.html

     FluroineFx在线文档:http://www.fluorinefx.com/docs/fluorine/index.html

     

     本系列文章的程序开发环境选择如下:

     .NET:Microsoft Visual Studio 2008 + .NET Framework 3.5

     Flex:Adobe Flex Builder CS3 + Flex SDK 3.2

     FluroineFx:FluorineFx v1.0.0.15 (点击可下载)

     文章目录如下:

     1、Flex与.NET互操作(一):基于Socket的网络连接

     2、Flex与.NET互操作(二):基于WebService的数据访问(上)

     3、Flex与.NET互操作(三):基于WebService的数据访问(下)

     4、Flex与.NET互操作(四):使用HttpService、URLReqeust和URLLoader加载/传输数据 

     5、Flex与.NET互操作(五):使用FileReference+HttpHandler实现文件上传/下载

     6、Flex与.NET互操作(六):Flex和.NET协同开发利器FluorineFx

     7、Flex与.NET互操作(七):了解FluorineFx的环境配置(远程对象、网关、通道、目的地)

     8、Flex与.NET互操作(八):使用FluorineFx网关实现远程访问

     9、Flex与.NET互操作(九):FluorineFx.NET的认证(Authentication )与授权(Authorization) 

   10、Flex与.NET互操作(十):FluorineFx.Net的及时通信应用(ApplicationAdapter)(一)  

   11、Flex与.NET互操作(十一):FluorineFx.Net的及时通信应用(Remote Procedure Call)(二)

   12、Flex与.NET互操作(十二):FluorineFx.Net的及时通信应用(Remote Shared Objects)(三)

   13、Flex与.NET互操作(十三):FluorineFx.Net实现视频录制与视频回放 (回复中有视频聊天的实现)

   14、Flex与.NET互操作(十四):FluorineFx的AMF(Action Message Format)协议通信

   15、Flex与.NET互操作(十五):使用FluorineFx中的字节数组(ByteArray)实现图片上传

 

      本系列文章暂时就写到这里,希望对学习基于.NET后台的Flex开发的朋友起到一定的帮助作用。另外在此谢谢长期以来支持我这一系列文章的朋友。

 

版权说明

  本文属原创文章,欢迎转载,其版权归作者和博客园共有。  

  作      者:Beniao

 文章出处:http://beniao.cnblogs.com/  或  http://www.cnblogs.com/

 

[Mobile]Windows Mobile开发资源文章列表

mikel阅读(642)

智能手机

手机词汇

研发手机基本流程

我理解的Windows moblie

J2ME,CompactFramework,c++,我该如何取舍

Windows Mobile Jump Start Guide

从0开始Windows Mobile 开发

3G 手机流媒体应用,看上去很美

基于rtsp的手机视频点播实现和研究

手机流媒体 
 

UI开发 

WINCE应用的UI实现方案 —— 上篇:几种UI实现方案比较

Windows Mobile 和 Wince 下的 WTL(Windows Template Library) 界面开发

Mobile个人开发(绘制背景图片)

怎样在Windows Mobile上设计一个美观的用户界面程序(Win32)

EVC中的图片背景透明处理

Windows Mobile载入位图的方法

[翻译]Windows Mobile应用程序设计指导-软键和菜单

创建Windows Mobile上兼容性好的UI 程序

windows mobile 5.0 下创建菜单

在Visual Studio 2005下创建WM for Smartphone/Standard 软键菜单的问题

AP的全屏与非全屏的切换

如何创建在 PocketPC 全屏幕应用程序(转)

关于wince中的全屏显示

用本地代码实现屏幕方向自适应的Windows Mobile程序

mobile手机上窗体最小化后置icon在消息栏的处理.

 

GPRS开发系列 

GPRS入门知识

GPRS开发系列文章之入门篇(转)

GPRS开发系列文章之进阶篇

GPRS开发系列文章之实战篇(转)

GPRS技术在配电监控系统中的应用[转载]

WM5.0下连接移动GPRS

Windows Mobile中如何建立GPRS连接以便Socket能正常通信

PDA/PPC下如何获取GPRS的网络流量(ZT)

windows ce gprs 拨号程序(转)

C# wm6通过udp协议和pc通讯

 

.NET Compact Framework

.NET Compact Framework 多线程下的等待事件

.NET Compact Framework 多线程环境下的UI异步刷新

定时关闭窗口 For Windows Mobile SP/PPC

Microsoft .NET CF 与非托管代码交互注意事项

.NET Compact Framework 下的3G应用

在.NET Compact Framework调用PPC设备的震动功能

.Net Compact Framework 基础篇(1)

.Net Compact Framework 基础篇(4)

.Net Compact Framework 高级篇(1)

列车时刻表 开发回顾 (一):后台线程更新前端界面

 

开发环境 + 模拟器使用 + 疑难杂症 

VS无法调试智能设备程序的解决方案

在Windows Mobile Emulator建立网络连接

配置PPC模拟器网络环境,调试TCP/UDP套接字程序

Windows Mobile 2003 SE 模拟器上网设置

Ring Tone Manager on Windows Mobile

Windows Mobile Device Emulator In-Depth–(1)

Windows Mobile Device Emulator In-Depth–(2)

在Visual Studio 2005里,用ActiveSync来同步模拟器(Windows Mobile 5.0 For Smartphone)

也谈EVC工程移植

手机音频流媒体应用与优化指南

ANSI码和UNICODE码转化

WCHAT、TCHAT、CString和char*的转换(WM5.0)

WinCe和Windows Mobile下的字符串转换

【转】使用 AYGShell 实现 Windows CE .NET 和 Pocket PC 2002 外壳兼容性

[转]从AP中获取电池和电源信息变更通知的方法

中文问题-Mobile-UrlEncode

如何判断当前WM系统是否是Smartphone?

利用tmail.exe 命令参数来发送邮件

 

其它资源 

Wince 

Windows Mobile

Windows Mobile 开发工具和资源

移动开发索引贴  

平时收获,供需及取(PPC)

Mobile开发之路_之小总结

WINCE 开发资料汇集

iPhone开发知识介绍

symbian中的新手问题整理(均有解答)

Mobile.ConnectionMonitor

Windows Mobile-Bookmarks

Windows Mobile 系列文章索引—不断整理中(2009-04-04)

H.264系列视频编解码器代码下载(Windows和Windows CE/Windows Mobile版本)

手机音视频流媒体开发一些有用资料

水煮TCPMP

WinCE开发流媒体播放器--MPEG4

Windows Mobile 开发资源

Windows Mobile 常用键值(VK)对应表及系统文件夹简单介绍

 

 

具体应用开发文章 

WM性能优化的一些经验

Windows Mobile SP/PPC 中 Menu Bar 使用完美方案

Windows Mobile平台上重写Back健的行为

也谈Windows Mobile中打开/关闭WIFI

VC通用控件自适应屏幕类

在非纯色背景上,叠加背景透明的BUTTON和STATIC_TEXT控件

在Windows mobile 5.0下操作INI文件

WinMoblie 利用EVC读写INI,XML配置文件

windows mobile 5.0 下创建菜单

Windows Mobile 发送短信的问题

3G应用—windows mobile和symbian平台下rtsp流媒体播放器

[流媒体]实例解析MMS流媒体协议,下载LiveMediaVideo[1][修正版,增加了带宽测试包]

[J2ME]手机看交通监视器实时录像 实现说明

[J2ME]手机流媒体之实作[附源码][与RTSP/MMS协议无关]

【蛙蛙推荐】手机通讯录实现

[Flex]Flex与.NET互操作(十五):使用FluorineFx中的字节数组(ByteArra

mikel阅读(876)

     前几天一位朋友问我一个问题,他说:“我用HTTP接口或是WebService接口可以实现图片上传功能,那么用FluorineFx 如何实现图片上传功能呢?”,其实仔细看官方文档和示例程序的自己都可以找到答案,实现上传可以有很多种实现,这里我以官方所提供是示例为基础稍加改动, 通过ByteArray类实现图片上传。

      首先建立FluorineFx库和网站,在远程服务器类里添加一个处理文件上传的方法,详细代码如下:

namespace ByteStream.Services
{
    [RemotingService]
    
public class ByteStreamService
    {
        
public ByteArray UploadImage(ByteArray ba)
        {
            MemoryStream ms 
= new MemoryStream(ba.GetBuffer());
            Image img 
= Bitmap.FromStream(ms);

            Bitmap newImage 
= new Bitmap(img);
            MemoryStream tempStream 
= new MemoryStream();
            newImage.Save(tempStream, System.Drawing.Imaging.ImageFormat.Png);
            
string path = HttpContext.Current.Server.MapPath("UpLoad/ByteArray.png");
            FileStream fs 
= new FileStream(path, FileMode.Create);
            tempStream.WriteTo(fs);
            fs.Close();
            ByteArray result 
= new ByteArray(tempStream);
            
return result;
        }
    }
}

 

      处理图片上传的方法通过把flex客户端传递来的字节数组包装为内存流,然后通过写文件的形式将图片保存到指定的目录下。示例中提供了 一个画图板,用户可以通过选择颜色自画不同的图象,然后保存到服务器上指定的目录。画图板的实现是根据鼠标按下的移动路线做的,代码如下:

private function doMouseDown():void
{
    x1 
= myCanvas.mouseX;
    y1 
= myCanvas.mouseY;
    isDrawing 
= true;
}
private function doMouseMove():void
{
    x2 
= myCanvas.mouseX;
    y2 
= myCanvas.mouseY;
    
if (isDrawing)
    {
        myCanvas.graphics.lineStyle(
2, drawColor);
        myCanvas.graphics.moveTo(x1, y1);
        myCanvas.graphics.lineTo(x2, y2);
        x1 
= x2;
        y1 
= y2;
    }
}
private function doMouseUp():void
{
    isDrawing 
= false;
}
//清空画图板
private function onErase(event:MouseEvent):void
{
    myCanvas.graphics.clear();
}

      

      在官方实例中是使用的RemoteObject实现的,这里我将其修改为通过编程实现AMF通信实现当程序初始化的时候就建立与FluorineFx网关的AMF通信连接:

private var nc:NetConnection;
private var rs:Responder;
private function init():void
{
    rs 
= new Responder(onResult,onFault);
    nc 
= new NetConnection();
    nc.connect(
"http://localhost:2453/FluorineFxWeb/Gateway.aspx")
    nc.client 
= this;
}

 

      在Flex客户端通过当前网络连接的call()方法实现远程方法调用,并指定通过Responder来处理服务器端方法的返回结果。

private function onSaveImage(event:MouseEvent):void
{
    var bd:BitmapData 
= new BitmapData(myCanvas.width,myCanvas.height);
    bd.draw(myCanvas);
    var ba:ByteArray 
= new PNGEncoder().encode(bd);
    nc.call(
"ByteStream.Services.ByteStreamService.UploadImage",rs,ba);
}

 

小提示

      在进行Flex开发中,能够通过编程实现的最好通过编程实现,尽量少的去使用Flex组件,这样可以有效的给Flex程序瘦身。

 

      服务器端将传递过去的ByteArray数据返回到了客户端,客户端接收到这些数据通过处理将字节数组转化为显示对象后显示到界面上。

private function onResult(result:ByteArray):void
{
    var loader:Loader 
= new Loader();
    loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loaderCompleteHandler);
    loader.loadBytes(result);
}
private function loaderCompleteHandler(event:Event):void
{
    var loader:Loader 
= (event.target as LoaderInfo).loader;
    loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,loaderCompleteHandler);
    var pictureHolder:UIComponent 
= new UIComponent();
    pictureHolder.addChild(loader);
    
this.resultImage.width = myCanvas.width;
    
this.resultImage.height = myCanvas.height;
    
this.resultImage.addChild(pictureHolder);
}
private function onFault(event:Object):void
{}

 

      到此就完成了图片上传功能,下面是完整的Flex客户端代码:


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" fontSize="12" creationComplete="init()">
    
<mx:Script>
        
<![CDATA[
            import mx.core.UIComponent;
            import mx.controls.Alert;
            import mx.events.ResizeEvent;
            import mx.graphics.codec.PNGEncoder;
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
            
            
private var isDrawing:Boolean=false;
            
private var x1:int;
            
private var y1:int;
            
private var x2:int;
            
private var y2:int;
            
private var drawColor:uint;
            
            
private var nc:NetConnection;
            
private var rs:Responder;
            
private function init():void
            
{
                rs 
= new Responder(onResult,onFault);
                nc 
= new NetConnection();
                nc.connect(
"http://localhost:2453/FluorineFxWeb/Gateway.aspx")
                nc.client 
= this;
            }

            
            
private function onSaveImage(event:MouseEvent):void
            
{
                var bd:BitmapData 
= new BitmapData(myCanvas.width,myCanvas.height);
                bd.draw(myCanvas);
                var ba:ByteArray 
= new PNGEncoder().encode(bd);
                nc.call(
"ByteStream.Services.ByteStreamService.UploadImage",rs,ba);
            }

            
            
private function onResult(result:ByteArray):void
            
{
                var loader:Loader 
= new Loader();
                loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loaderCompleteHandler);
                loader.loadBytes(result);
            }

            
private function loaderCompleteHandler(event:Event):void
            
{
                var loader:Loader 
= (event.target as LoaderInfo).loader;
                loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,loaderCompleteHandler);
                var pictureHolder:UIComponent 
= new UIComponent();
                pictureHolder.addChild(loader);
                
this.resultImage.width = myCanvas.width;
                
this.resultImage.height = myCanvas.height;
                
this.resultImage.addChild(pictureHolder);
            }

            
            
private function onFault(event:Object):void
            
{}
            
            
private function doMouseDown():void
            
{
                x1 
= myCanvas.mouseX;
                y1 
= myCanvas.mouseY;
                isDrawing 
= true;
            }

            
private function doMouseMove():void
            
{
                x2 
= myCanvas.mouseX;
                y2 
= myCanvas.mouseY;
                
if (isDrawing)
                
{
                    myCanvas.graphics.lineStyle(
2, drawColor);
                    myCanvas.graphics.moveTo(x1, y1);
                    myCanvas.graphics.lineTo(x2, y2);
                    x1 
= x2;
                    y1 
= y2;
                }

            }

            
private function doMouseUp():void
            
{
                isDrawing 
= false;
            }

            
//清空画图板
            private function onErase(event:MouseEvent):void
            
{
                myCanvas.graphics.clear();
            }

        ]]
>
    
</mx:Script>
    
    
<mx:Panel x="10" y="10" width="348" height="306" layout="absolute">
        
<mx:Canvas x="10" y="10" width="315" height="210" id="myCanvas"
            mouseDown
="doMouseDown()"
            mouseMove
="doMouseMove()"
            mouseUp
="doMouseUp()">
        
</mx:Canvas>
        
<mx:ControlBar>
            
<mx:ColorPicker change="drawColor = event.target.selectedColor"/>
            
<mx:Button label="清除" click="onErase(event)"/>
            
<mx:Button label="保 存" click="onSaveImage(event)"/>
        
</mx:ControlBar>
    
</mx:Panel>
    
<mx:Image x="382" y="10" id="resultImage"/>
</mx:Application>

 

      本文示例程序下载:ByteStreamDemo.rar

版权说明

  本文属原创文章,欢迎转载,其版权归作者和博客园共有。  

  作      者:Beniao

 文章出处:http://beniao.cnblogs.com/  或  http://www.cnblogs.com/

 

[MVC]Asp.net MVC FluentHTML and Fluent Interface

mikel阅读(718)

      赏花归去马如飞, 去马如飞酒力微.
        酒力微醒时已暮
, 醒时已暮赏花归. —苏轼

        

  我们力求页面层代码简洁并具有较好的可读性,ASP.NET MVC的平台上,我们以新的起点来实现这一目标.MvcContrib.FluentHtmlSpark ViewEngine给我们做出了榜样.本文将以MvcContrib.FluentHtml为例探究它的实现机制:Fluent Interface.

 

       读过开篇的诗句,不知是否感受到文字之美.不仅仅是在文学作品中,在代码中,这种美一样存在.

 MvcContrib.FluentHtml的应用中,我们随处可以见到下面的代码:

 

    <%= this.TextBox(x => x.Person.Name).Title("Enter the person's name").Label("Name:"%><br />
        
        …  …        
        
<%= this.Select(x => x.Person.Gender).Options(Model.Genders).Size(5).Label("Gender:")
                .Title(
"Select the person's gender"%><br /> 
 浏览器中生成的代码为:
<label id="Person_Name_Label" for="Person_Name">Name:</label>
<input id="Person_Name" type="text" value="Jeremy" title="Enter the person's name" name="Person.Name" maxlength="50"/>
 .
<select id="Person_Gender" title="Select the person's gender" size="5" name="Person.Gender">
<option value="M" selected="selected">Male</option>
<option value="F">Female</option>
</select>

 

上面对动态生成TextBoxSelect的代码很有意思,我们使用普通的方式在页面上生成同样的客户端代码,CS代码大致是这样的:

                 Label label = new Label();

        label.Text = "Name";

        TextBox textbox= new TextBox();

        textbox.ToolTip ="Enter the person's name";

        textbox.ID = "No.10001";

        textbox.ID = "Person.Name";

 

FluentHtml创建页面元素的方式让我们很容易联想到StringBuilder的使用:

   StringBuilder stringbuilder = new StringBuilder();

   stringbuilder.Append("Hello").Append(" ").Append("World!");

 

Fulent Interface

     这种实现编程方式就是"Fluent Interface",这并不是什么新概念,2005Eric Evans Martin Fowler就为这种实现方式命名.源文档 <http://www.martinfowler.com/bliki/FluentInterface.html> 可以通过维基百科中对Fluent Interface的描述获得一个基本的了解:In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is a way of implementing an object oriented API in a way that aims to provide for more readable code.

我们分解上面的话:

  • 它是面向对象API的一种实现方式
  • 目的是增加代码的可读性

既然我们最熟悉的是StringBuilder,我们就从这个线索追下去:打开Re

flector,很容易找到StringBuilderAppend方法:

public StringBuilder Append(string value)
{
    
if (value != null)
    
{
        
string stringValue = this.m_StringValue;
        IntPtr currentThread 
= Thread.InternalGetCurrentThread();
        
if (this.m_currentThread != currentThread)
        
{
            stringValue 
= string.GetStringForStringBuilder(stringValue, stringValue.Capacity);
        }

        
int length = stringValue.Length;
        
int requiredLength = length + value.Length;
        
if (this.NeedsAllocation(stringValue, requiredLength))
        
{
            
string newString = this.GetNewString(stringValue, requiredLength);
            newString.AppendInPlace(value, length);
            
this.ReplaceString(currentThread, newString);
        }

        
else
        
{
            stringValue.AppendInPlace(value, length);
            
this.ReplaceString(currentThread, stringValue);
        }

    }

    
return this;
}

 

阅读这段有两个特别要注意的点:1.方法的返回值是StringBuilder类型 2.最后一句:return this;为了深刻理解,我们写一个简单的StringBuilder:

 

public interface IContentBuilder
    {
        
void WriteContent();
        IContentBuilder Append(
string partialContent);
    }
    
public class TestContentBuilder : IContentBuilder
    {
        
string temp;
        
#region IContentBuilder Members
        
void IContentBuilder.WriteContent()
        {
            Console.Write(temp);
        }
        IContentBuilder IContentBuilder.Append(
string partialContent)
        {
            temp 
+= partialContent;
            
return this;
        }
        
#endregion
    }
… …
//调用代码
IContentBuilder t = new TestContentBuilder();
 t.Append(
"test").Append("Hello").WriteContent();

 

跑一下代码,StringBuilder效果是一样的.从上面的应用也可以看出:Fluent Interface经常用来完成对象的构造和属性赋值.

 

言归正传:FluentHTML

      了解了Fluent Interface,我们来看一下MVCContrib.FluentHTML的实现,这里以TextBox为例进行考察,首先看一下它的继承关系:

public class TextBox : TextInput<TextBox>

public abstract class TextInput<T> : Input<T>, ISupportsMaxLength where T : TextInput<T>

public abstract class Input<T> : FormElement<T> where T : Input<T>, Ielement

泛型是一种高层次的算法抽象,我们就通过Input<T>一窥端倪:

 

public abstract class Input<T> : FormElement<T> where T : Input<T>, IElement
{
    
protected object elementValue;
    
protected Input(string type, string name) : base(HtmlTag.Input, name)
    {
        builder.MergeAttribute(HtmlAttribute.Type, type, 
true);
    }
    
protected Input(string type, string name, MemberExpression forMember, IEnumerable<IBehaviorMarker> behaviors)
        : 
base(HtmlTag.Input, name, forMember, behaviors)
    {
        builder.MergeAttribute(HtmlAttribute.Type, type, 
true);
    }
    
/// <summary>
    
/// Set the 'value' attribute.
    
/// </summary>
    
/// <param name="value">The value for the attribute.</param>
    public virtual T Value(object value)
    {
        elementValue 
= value;
        
return (T)this;
    }
    
/// <summary>
    
/// Set the 'size' attribute.
    
/// </summary>
    
/// <param name="value">The value for the attribute.</param>
    public virtual T Size(int value)
    {
        Attr(HtmlAttribute.Size, value);
        
return (T)this;
    }
    
protected override void PreRender()
    {
        Attr(HtmlAttribute.Value, elementValue);
        
base.PreRender();
    }
}

 

Size方法为例,可以看出这是一种典型的Fluent Interface实现:

public virtual T Size(int value)

{

Attr(HtmlAttribute.Size, value);

return (T)this;

}

分析到这里,上面的语句中还有一点比较奇怪,就是Lambda表达式的部分:

this.TextBox(x => x.Person.Name).Title("Enter the person's name").Label("Name:")

TextBox的实现代码里面我们没有看到对Lambda表达式的支持.那是在什么地方完成的呢?通过跟进,我们来到了ViewDataContainerExtensions,它是IViewDataContainer Extension Method:

 

namespace MvcContrib.FluentHtml
{
    
/// <summary>
    
/// Extensions to IViewDataContainer
    
/// </summary>
    public static class ViewDataContainerExtensions
    {
        
/// <summary>
        
/// Generate an HTML input element of type 'text' and set its value from ViewData based on the name provided.
        
/// </summary>
        
/// <param name="view">The view.</param>
        
/// <param name="name">Value of the 'name' attribute of the element.  Also used to derive the 'id' attribute.</param>
        public static TextBox TextBox(this IViewDataContainer view, string name)
        {
            
return new TextBox(name).Value(view.ViewData.Eval(name));
        }
… … 

  看一下return new TextBox(name).Value(view.ViewData.Eval(name));所以这里就成了TextBox定义方法链的第一步.

 

总结

       为了能够在View中能够简洁清晰的构造HTML元素,ASP.NET MVC中通过htmlHelper.InputHelper来实现页面元素的构造. 页面层所使用的<%= Html.TextBox("username") %>,HTML也是htmlHelperExtension Method.相比较起来,htmlHelper提供了基础的页面控件定义和构造,FluentHTML表现的更为灵活.除了FluentHTML,著名的Spark View Engine也有类似的实现,大家可以关注一下.