[转载]简单但有用的SQL脚本Part6:特殊需要的行转列

mikel阅读(1073)

[转载]简单但有用的SQL脚本Part6:特殊需要的行转列 – 我帅故我在 – 博客园.

一、数据库SQL Server行转列

需求:原始表的数据的结构如图1所示,把相同的guidcode值转换为列值。


(图1

目标:我们希望达到的效果如图2所示,这里的guid变成唯一的了,这行的记录中包含了这个guid所对应的code字段值。


(图2

分析与实现:要实现图1到图2的转变,这就是所谓的行转列,下面我们来讲讲具体的实现:

1. 首先我们先创建一个测试表,方便后面的效果展现;

创建表
if exists (select * from sysobjects where id = OBJECT_ID([TempTable_Base]) and OBJECTPROPERTY(id, IsUserTable) = 1)
DROP TABLE [TempTable_Base]

CREATE TABLE [TempTable_Base] (
[id] [int] IDENTITY (1, 1) NOT NULL,
[guid] [varchar] (50) NULL,
[code] [varchar] (50) NULL)

SET IDENTITY_INSERT [TempTable_Base] ON

INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 1,91E92DCB-141A-30B2-E6CD-B59EABD21749,A)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 2,91E92DCB-141A-30B2-E6CD-B59EABD21749,C)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 3,91E92DCB-141A-30B2-E6CD-B59EABD21749,E)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 4,91E92DCB-141A-30B2-E6CD-B59EABD21749,O)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 5,91E92DCB-141A-30B2-E6CD-B59EABD21749,G)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 6,79DD7AB9-CE57-9431-B020-DF99731FC99D,A)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 7,79DD7AB9-CE57-9431-B020-DF99731FC99D,O)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 8,79DD7AB9-CE57-9431-B020-DF99731FC99D,E)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 9,79DD7AB9-CE57-9431-B020-DF99731FC99D,F)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 10,79DD7AB9-CE57-9431-B020-DF99731FC99D,O)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 11,79DD7AB9-CE57-9431-B020-DF99731FC99D,B)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 12,79DD7AB9-CE57-9431-B020-DF99731FC99D,D)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 13,79DD7AB9-CE57-9431-B020-DF99731FC99D,F)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 14,D61651D9-1B0A-0362-EE91-A805AA3E08F2,O)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 15,D61651D9-1B0A-0362-EE91-A805AA3E08F2,D)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 16,D61651D9-1B0A-0362-EE91-A805AA3E08F2,F)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 17,D61651D9-1B0A-0362-EE91-A805AA3E08F2,C)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 18,D61651D9-1B0A-0362-EE91-A805AA3E08F2,U)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 19,D61651D9-1B0A-0362-EE91-A805AA3E08F2,F)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 20,4802F0CD-B53F-A3F5-1C78-2D7424579C06,A)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 21,3CCBFF9F-827B-6639-4780-DA7215166728,O)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 22,3CCBFF9F-827B-6639-4780-DA7215166728,M)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 23,3CCBFF9F-827B-6639-4780-DA7215166728,C)
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 24,3CCBFF9F-827B-6639-4780-DA7215166728,M)

SET IDENTITY_INSERT [TempTable_Base] OFF

SELECT * FROM [TempTable_Base]

2. 使用SQL Server2005row_number()函数来进行分组排名,把同一个guid的数据进行标识,这样就可以让不同的guid具有数字1以后的数值,这样就可以作为新的列名来进行行转列了,执行下面的SQL就可以达到图3所示的效果了。

对数据进行分组
select base.*,row_number() over (partition by guid order by ID) as depth
from [TempTable_Base] as base
order by id


(图3

3. 生成分组表,把上面的结构插入到一张新的表中,把数据保存为一个表是为了方便后面的统计使用。

生成分组表
select base.*,row_number() over (partition by guid order by ID) as depth
into [TempTable_Depth]
from [TempTable_Base] as base
order by id

SELECT * FROM [TempTable_Depth]

4. 动态行转列的SQL,因为你不知道列数据会有多少,所以我们使用下面的SQL来动态的生成列名,结果就如图2所示。

行转列
declare @s nvarchar(max)
set @s=
Select @s=@s+,+quotename([depth])+=max(case when [depth]=+quotename([depth],””)+ then code else null end)
from [TempTable_Depth] group by [depth] order by [depth]
exec(select guid +@s+ from [TempTable_Depth] group by guid order by guid)

二、数据库SQL Server生成矩阵数据

需求:我们回过头来看看图1,比如guid91E92DCB141A30B2E6CDB59EABD21749code值包括A,C,E,O,G这五个,我们可以想象guid为一个用户,这五个code就是这个用户访问网站页面的顺序,那如果我想看到一个从A->CC-> EE-> OO -> G这个矩阵中两两对应在数据库中出现了多少次?

目标:我们希望达到的效果如图4所示,这个图可以解读为A->A的个数是0A->C的个数是1D->F的个数是2,这些统计方法可能会在一些需要进行对比分析的过程中用到。


(图4

分析与实现:要实现图4的效果,这就需要我们对数据进行矩阵转换,下面我们来讲讲具体的实现:

1. 首先我们需要巧用left joindepth字段,depth就相当于用户访问的顺序,所以我们可以把之前有序的拷贝一份到右边去,效果如图5所示。

巧用左连接和depth字段进行处理
select a.id,a.guid,a.code as code_from,b.code as code_to
from [TempTable_Depth] as a
left join [TempTable_Depth] as b
on a.guid = b.guid and a.[depth] = b.[depth]1


(图5

2. 为了方便统计,把上面的成果保存到一个表中,之后就是为所有唯一的code值生成一个以code作为元素的二维矩阵的原始数据,它就相当于一个临时表一样,用来保存每一个code对应的个数,效果如图6所示。

生成From和To的对应关系
select a.id,a.guid,a.code as code_from,b.code as code_to
into [TempTable_FromTo]
from [TempTable_Depth] as a
left join [TempTable_Depth] as b
on a.guid = b.guid and a.[depth] = b.[depth]1

生成矩阵
select distinct code_from ,1 as num
into [TempTable_t1]
from [TempTable_FromTo]
order by code_from

select * from [TempTable_t1]

生成一个矩阵表
select a.code_from ,b.code_from as code_to,0 as counts
into [TempTable_t2]
from [TempTable_t1] as a
left join [TempTable_t1] as b
on a.num = b.num
order by a.code_from ,b.code_from

select * from [TempTable_t2]


(图6

3. 现在就需要把统计的A->A这样数据的个数,并把它放入图6中的表中,效果如图7所示。

统计
select code_from ,code_to, count(1) as counts
into [TempTable_t3]
from [TempTable_FromTo]
where code_to is not null
group by code_from ,code_to,guid
order by code_from ,code_to

select * from [TempTable_t3]

更新统计的数字
update a set a.counts = b.counts
from [TempTable_t2] as a,[TempTable_t3] as b
where a.code_from = b.code_from
and a.code_to = b.code_to
and b.counts is not null

select * from [TempTable_t2]


(图7

4. 现在需要做的就是把行转列了,这也没有违背我们的标题啊,呵呵,效果如图8所示。

查询矩阵
declare @s nvarchar(max)
set @s=
Select @s=@s+,+quotename([code_to])+=max(case when [code_to]=+quotename([code_to],””)+ then counts else null end)
from [TempTable_t2] group by [code_to] order by [code_to]
exec(select [code_from] +@s+ from [TempTable_t2] group by [code_from] order by [code_from])

(图8

总结:其实这篇文章我想表达正是这个矩阵的生成方法,在现实中也许并不常用到,但是还是有些技巧性的东西在里面,比如那个dept的用处;再比如a.[depth] = b.[depth]-1这个SQL的巧用;再比如行转列解决矩阵问题;还有动态生成行转列的SQL,其实这里还可以使用SQL Server 2005pivot来解决行转列的问题,这里就不列出来了。希望这篇文章能给你遇到的问题带来一些帮助和启示。

[转载]asp.net mvc 2.0+Silverlight播放器开发的TeamVideo视频播放网站--系列1

mikel阅读(1039)

[转载]asp.net mvc 2.0+Silverlight播放器开发的TeamVideo视频播放网站–系列1 – 爱因斯坦的小脑 – 博客园.

背景:经常有一些电影大家想一起分享,为了照顾到很多同事,以及大家来交流评论电影,我最近抽时间使用ASP.NET mvc2.0和Silverlight播放器来做个视频播放网站。今天就来这里和大家分享下。

播放界面展示:

,,,,ASP.NET mvc这个我知道大家都写了好多,当然我这里不会重点去说明ASP.NET MVC了。我主要想和大家分享的是如何在ASP.NET MVC中使用Silverlight来播放不同的视频。通过不同的id来播放不同的视频。

我使用的Silverlight团队开发的Silverlight Media Framework 2.0来作为播放器的。

smf_block_diagram.png

下载地址:http://smf.codeplex.com/

当然这里有提供了Smooth Streaming播放器,也就是视频直播的那种。结合Smooth Stream Client可以进行视频直播。参考文档:http://smf.codeplex.com/documentation

使用asp.net mvc来创建网站速度确实快。。。。。。我接下来就说明下如何在两天内抽空把整个网站给架好(很简单的网站,所以2,3天搞定)。

1.数据库模型的创建:

image

自己手绘了几下,思考着应该有哪些哪些字段和字段的类型,如上图。

a. Entity Data Model的创建:

数据模型有了,我们就来创建数据库,为了节省时间,我没使用POCO或是Code-First来创建Entity Data Model,直接使用的是系统自动生成edmx文件。

image

b.对Model的验证规则的创建:

没错,对于用户输入的数据我们需要来验证是否符合我们在数据库定义的长度和范围等,所以验证规则的定义是必要的。你当然可以使用JQuery的Validation来在客户验证。例如Video实体的验证如下:

1 [MetadataType(typeof(VideoMetaData))]
2 public partial class Video
3 {
4 // Validation rules for Video class
5
6 [Bind(Exclude = Id)]
7 public class VideoMetaData
8 {
9 [ScaffoldColumn(false)]
10 public object Id { get; set; }
11
12 [Required(ErrorMessage=An Title is required)]
13 [StringLength(255)]
14 public object Title { get; set; }
15
16 [DisplayName(Video URL)]
17 [Required(ErrorMessage=Url is required)]
18 [StringLength(255)]
19 public object Url { get; set; }
20
21 [DisplayName(Leading Actors)]
22 [Required(ErrorMessage=Leading Actors are required)]
23 [StringLength(100)]
24 public object Actors { get; set; }
25
26 [Required(ErrorMessage=Review information is required)]
27 public object Review { get; set; }
28
29 [Required(ErrorMessage=Year is required)]
30 [RegularExpression(@”^\d{4}$, ErrorMessage = Year is not valid)]
31 public object Year { get; set; }
32 }
33 }

需要注意的是这里有’Year’字段是个四位整数,所以我们需要用正则表达式来确定是否年份填写正确。

而在Rating实体的验证规则中需要注意Rating的范围1-5且只能是整数

1 [Required(ErrorMessage=Rating is required)]
2 [Range(1,5,ErrorMessage=Rating must be between 1 and 5)]
3 public object Rating { get; set; }

c.ViewModel部分的创建:

对于ViewModel的部分创建,主要是为了在controller对于view时能够更加容易的传递数据,所以我们定义了ViewModel部分。

例如在视频播放页面的布局如下:

image

所以我们需要给此页面的Model数据包含Video=>Comments=>Rating。它的ViewModel代码如下:

1 public class VideoBrowseViewModel
2 {
3 public Video Video { get; set; }
4
5 int Rating { get; set; }
6
7 public List<Comment> Comments { get; set; }
8 }

d.Controller部分的创建:

先贴上代码来看看:

1 public ActionResult Index()
2 {
3
4 // Retrieve Video from database
5 var VideoModel = mediaDB.Videos.Include(Comments).Include(Ratings).FirstOrDefault();
6
7 float sum = VideoModel.Ratings.Sum(r => r.Rating1);
8
9
10 var viewModel = new VideoBrowseViewModel()
11 {
12 Video = VideoModel,
13 rate=Convert.ToInt32(sum/VideoModel.Ratings.Count),
14 Comments = VideoModel.Comments.ToList()
15 };
16
17 return View(viewModel);
18
19 }

使用include属性来同时得到Video对应的Comments和Ratings。最后需要得到的rate是对于该video的所有rating的平均值,所以需要计算下来传递给view。

e.View界面的传值和Silverlight播放器的源文件选择

上面的传值传过来,在view界面直接绑定很简单,但是如何给Silverlight的播放器来传递数据源呢?

首先需要把xap文件包含在项目中,如下图:

image

接下来是使用JavaScript来为创建一个播放器的object:

1 <script type=text/JavaScript>
2 $(document).ready(function () {
3
4 // the media player
5 var obj = <object data=’data:application/x-silverlight-2,’ type=’application/x-silverlight-2′ width=’100%’ height=’320′>\n;
6 obj = obj + <param name=’source’ value=’ProgressiveDownloadPlayer.xap’ /> \n ;
7 obj = obj + <param name=’onError’ value=’onSilverlightError’ /> \n ;
8 obj = obj + <param name=’background’ value=’#3E344A’ /> \n ;
9 obj = obj + <param name=’minRuntimeVersion’ value=’4.0.50401.0′ /> \n ;
10 obj = obj + <param name=’autoUpgrade’ value=’true’ /> \n ;
11 obj = obj + <param name=’InitParams’ value=’mediaurl=<%=Model.Video.Url %>’ /> \n ;
12 obj = obj + <a href=’http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50401.0′ style=’text-decoration:none’> <img src=’http://go.microsoft.com/fwlink/?LinkId=161376′ alt=’Get Microsoft Silverlight’ style=’border-style:none’/></a>;
13 obj = obj + </a>;
14
15 // set it as host control html ,and fade in slowly ^_^
16 $(#silverlightControlHost).html(obj).slideDown(slow);
17 });
18 </script>

这里注意‘mediaurl的是通过我们来绑定Model.Video.Url来得到的。比如传过去的Video信息如下:

image

传过来值后,我们把这些拼好的字符串作为div的html来显示,就可以播放视频了。

在下面的文章中我会给大家介绍电影的List展示盒分类的展示,以及其它Rating的ajax实现和评论的ajax方法实现。

最后一篇文章中是结合TinyMac编辑器来进行后台的维护以及权限的管理等等。。。。。。。

Cheers

BRs

Nic

[转载]ASP.NET MVC表单的组件化

mikel阅读(1102)

[转载]ASP.NET MVC表单的组件化 – 阿不 – 博客园.

ASP.NET WebForm最重要的特性之一就是它的界面元素的组件化,简单的输入控件就不必多说,特别是那些类似于Repeater,GridView这样的模板控 件,真的给开发人员带来了极大的方便。而在ASP.NET MVC的视图中,虽然技术上我们仍然可以使用这WebForm的Server Control,但是从理念上,我们是必须要完全避免这种情况的发生。很多习惯WebForm开发模式的开发人员,除了不习惯没有Postback外,可 能最大的抱怨就是MVC的表单开发方式。在大部分情况,他们需要自己完全去控件HTML标签。在显示数据列表时,需要通过foreach控制数据的输出, 当有一些特殊的输出控制时(比如奇偶行不同模板),还要做额外的工作,在界面上定义各种临时变量。这样重复的工作,除了会让开发人员烦躁不说,当一个表单 开发下来,充斥着if..else这样的逻辑判断,不规则的“{”“}”,也给我们阅读和日后的修改带来相当大的麻烦。本文的目的就是为解决这些问题提供 一些思路。

输入表单

对于输入表单的组件化,我们的解决思路来源于MvccontribMvccontrib是一个致力于改善和提高开发人员在使用ASP.NET MVC框架开发Web时的开发体验和开发效率的辅助框架。在里面有一个InputBuilder的功能,Mvccontrib首先根据不同的数据类型定义了一些常用的输入,输出模板。在开发人员在设计Model时,预先设置好一些必须的元数据供View使用,这样就可以提高HTML代码的复用性,更多细节请阅读:http://www.lostechies.com/blogs/hex/archive/2009/06/09/opinionated-input-builders-for-asp-net-mvc-using-partials-part-i.aspx

这种通过在Model添加元数据,来支持View开发的模型在ASP.NET MVC2中得到了极大的应用。下面的代码就是MVC2项目模板的例子:

01 [PropertiesMustMatch("Password", "ConfirmPassword", ErrorMessage = "The password and confirmation password do not match.")]
02 public class RegisterModel
03 {
04 [Required]
05 [DisplayName("User name")]
06 public string UserName { get; set; }
07
08 [Required]
09 [DataType(DataType.EmailAddress)]
10 [DisplayName("Email address")]
11 public string Email { get; set; }
12
13 [Required]
14 [ValidatePasswordLength]
15 [DataType(DataType.Password)]
16 [DisplayName("Password")]
17 public string Password { get; set; }
18
19 [Required]
20 [DataType(DataType.Password)]
21 [DisplayName("Confirm password")]
22 public string ConfirmPassword { get; set; }
23 }

View是这样的:

1 <div class="editor-label">
2 <%: Html.LabelFor(m => m.UserName) %>
3 </div>
4 <div class="editor-field">
5 <%: Html.TextBoxFor(m => m.UserName) %>
6 <%: Html.ValidationMessageFor(m => m.UserName) %>
7 </div>

以上的LabelFor,就会从UserName这个属性的元数据中去得到[DisplayName(“User name”)],显示作为label。TextBoxFor会自动生成input标签,并且把UserName的值也赋给标签值。添加<%: Html.ValidationMessageFor(m => m.UserName) %> ,则会把数据验证消息输出到这里。我们会发现这样,虽然已经可以帮我节省了大量了时间。但是你会也发现,每一个字段都复制和拷贝这两个DIV的内容,这部 分也是一个相当重复和繁琐的工作。当我们把TextBoxFor替换成EditorFor,就会进一步发现原来每个字段都是这样的结构和内容,我们根本不 需要任何修改,那为何还要去复制呢?如果我们能直接使用EditorFor来代替上面的两个Div,根据不同的输入类型,定义不同的输入控件模板。于是, 我们的输入表单就变成这样:

01 <%Html.EnableClientValidation();%>
02 <% using (this.Html.BeginForm())
03 {  %>
04 <%: Html.EditorFor(m=>m.UserName)%>
05 <%: Html.EditorFor(m=>m.Password) %>
06 <%: Html.EditorFor(m=>m.Password)%>
07 <%: Html.EditorFor(m=>m.ConfirmPassword) %>
08 <%: Html.EditorFor(m=>m.Email) %>
09 <input type="submit" value="Submit" />
10 <%} %>

对于这样一个高度模式化的表单,一行一行去写代码也是相当的讨厌,特别是我可能必须要去检查一下有没有哪一个字段漏掉了。我们还可以进一步简化开发,写一个VS扩展,得到当前强类型模板所使用的Model类型,自动生成所有的字段模板,然后再根据需要手工去调整:

捕获

这篇博客就是为了写这个扩展时,得到当前上文Model类型实例而遇到的难题的记录。

列表表单

相对于输入表单,列表表单一般情况都是一行一行的输出数据。在WebForm中,我们可以使用Repeater,GridView这样的模板,给我们提供了非常大的便利。但是在MVC中,目前还没有一个非常好,非常方便的办法让我们方便快速去显示一个列表。在Mvccontrib中,给我们提供了一个强类型的Grid扩展,让我们可以以强类型的方式来输出table,但我并不喜欢那样的做法,要生成一个字段相对多点的列表,那个表达式写起来没有HTML标签来的轻松。

继承元数据和控件模板的做法,我把Model中,要显示在Grid的字段,都加上特定的元数据:

01 [GridAction(ActionName = "Delete", DisplayName = "Delete", RouteValueProperties = "UserName")]
02 public class RegisterModel
03 {
04 [GridColumn]
05 [Required]
06 [DisplayName("User name")]
07 public string UserName { get; set; }
08
09 [GridColumn]
10 [Required]
11 [DataType(DataType.EmailAddress)]
12 [DisplayName("Email address")]
13 public string Email { get; set; }
14
15 [Required]
16 [DataType(DataType.Password)]
17 [DisplayName("Password")]
18 public string Password { get; set; }
19
20 [Required]
21 [DataType(DataType.Password)]
22 [DisplayName("Confirm password")]
23 public string ConfirmPassword { get; set; }
24 }

以上加GridColumn的两个字段就是将来会被显示在grid的字段。同时Grid中的每一行都有一种操作,Delete。我们在列表中这样来写模板:

01 <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<System.Collections.Generic.IEnumerable<MvcFormSample.Models.RegisterModel>>" %>
02
03 <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
04 List
05 </asp:Content>
06 <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
07 <h2>
08 List</h2>
09 <%: Html.GridForModel() %>
10 </asp:Content>

在Views\Share写一个默认的Grid模板:

通过以上的封装,我们就可以大大减少在写列表表格时的HTML复制。有时间,字段在列表中的显示并不是简单的把值显示出来,有可能还需要格式化等操作。这时,我们可以通过在GridColumnAttribute添加相应的设置来进行输出的控制。

总之,我们总是希望找到一种就为经济实惠并且可行的表单开发方式。以上的做法,View Model的元数据是基础。而很多时候这些与视图相关的元数据并不会在设计业务模型时被设计好,这篇博客就是针对这种情况扩展。

上文的例子请从这里下载。

阿不 http://hjf1223.cnblogs.com

[转载]ASP.NET MVC 之如何创建自定义路由约束

mikel阅读(1064)

[转载]ASP.NET MVC 之如何创建自定义路由约束 – JasenKin – 博客园.

本文将讲解如何创建一个路由约束以及创建一个自定义路由约束

创建一个路由约束(C#)

你能够使用路由约束来限制匹配一个特殊路径的浏览器请求。你能够使用一个正则表达式来制定一个路由约束。
例如,假设你已经定义路由如下:

Listing 1 – Global.asax.cs

routes.MapRoute(
“Product”,
“Product/{productId}”,
new {controller=”Product”, action=”Details”}
);

Listing 1 包含一个命名为Product的路由. 你能够使用这个 Product route来将将浏览器请求映射到ProductController,如下:

Listing 2 – Controllers\ProductController.cs

using System.Web.Mvc;

namespace MvcApplication1.Controllers
{
public class ProductController : Controller
{

public ActionResult Details(int productId)
{
return View();
}

}
}

注意:Details() action 接收一个命名为 productId的单一参数. 这个参数是整型参数.

在Listing 1 will中定义的route将匹配一下的任何一个URLs:

?/Product/23
?/Product/7
遗憾的,这个route也同样匹配以下的URLs:

?/Product/blah
?/Product/apple

因为Details() action预期接收一个整型的参数,当请求中包含的内容不同于整数时,它将导致一个错误。

你真正想要做的,仅仅是匹配包含一个的整数productId的URLs。当你定义一个route时,你能够使用一个限制条件来限制URLs,使它匹配这个route。在Listing 3中,这个route包含一个只匹配整数的正则表达式约束。

Listing 3 – Global.asax.cs

routes.MapRoute(
“Product”,
“Product/{productId}”,
new {controller=”Product”, action=”Details”},
new {productId = @”\d+” }
);

这个真正表达式约束\d+ 匹配一个或多个整数. 这个约束导致Product route匹配如下的URLs:

?/Product/3
?/Product/8999

但不是如下的URLs:

?/Product/apple
?/Product

这个浏览器请求将被另一个route处理。或者,如果没有匹配的routes, “The resource could not be found ”错误将被返回.

创建一个自定义路由约束 (C#)

演示如何创建一个自定义的路由约束.约束接口中的Match方法如下:

IRouteConstraint.Match Method
bool Match(
HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection
)
你可以通过实现IRouteConstraint接口来创建一个路径约束,并且通过几个步骤把它添加到你的路径中。IRouteConstraint仅有一个Match方法,它返回一个布尔值。这个布尔值决定该请求是否应该被route对象处理。

如何创建一个ASP.NET MVC应用程序来模拟一个仅仅在视图中显示年份,月份,日期的文章系统,类似于博客系统的路径?

(一)首先,创建一个ArchiveController,它包含一个仅仅显示年份,月份,日期值的Index action 方法。

namespace MvcAppRouting.Controllers
{
public class ArchiveController : Controller
{
//
// GET: /Archive
public ActionResult Index(int year, int month, int day)
{
ViewData[
Year] = year;
ViewData[
Month] = month;
ViewData[
Day] = day;
return View();
}
}
}

(二)创建一个显示数据的view。

<%@ Page Title=“” Language=C# MasterPageFile=~/Views/Shared/Site.Master Inherits=System.Web.Mvc.ViewPage %>
<asp:Content ID=Content1 ContentPlaceHolderID=TitleContent runat=server>
Index
</asp:Content>
<asp:Content ID=Content2 ContentPlaceHolderID=MainContent runat=server>
<h2>Index</h2>
<fieldset>
<legend>Fields</legend>
<p>Year:
<%= ViewData[Year] %>
</p> <p>
Month:
<%= ViewData[Month]%>
</p> <p>
Day:
<%= ViewData[Day]%></p>
</fieldset>
</asp:Content>

(三)最主要的步骤,需要创建年份,月份,日期验证的三个分离的约束。它们将在路径定义中应用。以创建一个DayConstraint来开始。

using System.Web.Routing;
using System.Globalization;

namespace MvcAppRouting.RouteConstraints
{
public class DayConstraint:System.Web.Routing.IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
if ((routeDirection == RouteDirection.IncomingRequest) && (parameterName.ToLower(CultureInfo.InvariantCulture) == day))
{
try {
int month = int.Parse(values[Month].ToString());
int day = int.Parse(values[Day].ToString());
if (month <= 0 || month > 12) return false;
if(day<1)return false;
switch (month)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
if (day< 32) return true;
break;
case 2:
if (day < 29) return true;
break;
case 4:
case 6:
case 9:
case 11:
if(day<31) return true;
break;
}
}
catch {
return false;
}
}
return false;
}
}
}

年份数据限制为1950-2010。同样,月份的值在1-12之间,此处不再叙述,详见源代码。

(四)最后一步是将所有的联系在一起,使ASP.NET MVC 应用程序能够运行。这里仅仅是定义一个routes。

namespace MvcAppRouting
{
// 注意: 有关启用 IIS6 或 IIS7 经典模式的说明,
// 请访问 http://go.microsoft.com/?LinkId=9394801

public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute(
{resource}.axd/{*pathInfo});

routes.MapRoute(
Default, // 路由名称
{controller}/{action}/{id}, // 带有参数的 URL
new { controller = Home, action = Index, id = UrlParameter.Optional } // 参数默认值
);

routes.MapRoute(
Archive,
archive/{year}/{month}/{day},
new
{
controller
= Archive,
action
= Index,
year
= “”,
month
= “”,
day
= “”
},
new
{
year = new RouteConstraints.YearConstraint(),
month = new RouteConstraints.MonthConstraint(),
day = new RouteConstraints.DayConstraint()
}
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();

RegisterRoutes(RouteTable.Routes);
}
}
}

实例中的“archive/{year}/{month}/{day}”模式,像正常的routes一样,同样为route设置了默认的值,并且增加了一个约束对象。这个约束对象将模式中的参数映射至它的约束实例中,因此这些值能够被验证。

现在我用一个验证的请求模式来运行这个应用程序,展示的页面如下。

同样,发送一个archive/2000/2/30这个请求,它是不能通过验证,并且得到一个错误。

总结:
应该注意约束条件必须继承IRouteConstraint,并且实现Match方法。

源代码下载: MvcAppRouting源代码

[转载]社交游戏(Social Game)开发简单教程与粗略总结之基础篇

mikel阅读(1059)

[转载]社交游戏(Social Game)开发简单教程与粗略总结之基础篇 – Minds book of my CS Road – 博客园.

为了使得整个系列文章的逻辑性更加严密,本文旨在介绍一些社交游戏的相关基础,当前的市场状况,发展情况,以及对未来的展望。当然文中的一些数字与表述可能不太准确,在不影响传达数字表意的前提下,读者可对数字做一些上下浮动的估量,或许会更准确些Smile

引入

当无数人在谈论微博时代的到来中国SNS去泡沫化之时,依附于SNS平台之上的社交游戏也开始展露出头角,在互联网的大蛋糕上寻找着自己的那块cheese,而随着年利润达若干亿美元的zynga高调地宣称自己的玩家过亿时,大家才真正开始注意起这个不起眼的蓝海来,当然如今已是大红海了(下文会详细的说明)。

当facebook定义了SNS时,zynga也定义了社交游戏,随后便是数不尽的跟随者,如myspace,orkut,开心网,如 playdom,6waves,五分钟等,当然也只有facebook和zynga赚的盆满钵满,跟随只能有残羹剩饭的份,但是那已是相当诱人的了。

与其它游戏形式的关系

那么社交游戏又是一种怎样的游戏类型,它与传统游戏、网络游戏、网页游戏有什么不同,下面对这几个问题加以分析。

社交游戏,即social game,从组词来看它由soical和game组成,game决定了其只是游戏的一个类别而已,与其它游戏类别也并无大的差别;而关键是social, 也即说明社交游戏是基于社会关系之上的一种游戏新类型,其建立在依附的SNS平台庞大的用户群之上,在具有某种社会关系的玩家之间,基于一定的社交元素来 保证与这些玩家之间的互动,最终将游戏的趣味娱乐性本质延展至社交层次。所以说,除了需要具有游戏本身的趣味性、娱乐性等基本元素外,将用户的游戏行为导向为社交行为则是一款社交游戏能否成功的根本因素,例如风靡的“偷菜”,许多玩家偷的已不是菜,而是一种社交目的,如暧昧,亲昵,友谊等。

当然你也许会说,网游也具有同样互动的因素呀,且不闻借某款游戏来赢得一辈子幸福的同学也不在少数哈,还有大量的公会,还有“贾君鹏,你妈喊你吃饭”,这 不是社交吗?我不否认这种网游建立起的关系的存在和普遍性,但相比于建立在已有大量关系基础上的社交游戏,网游的社交性显得少了许多。试想,你去玩偷菜 时,你的邻居列表都是自己所熟知的人,其中不乏自己喜欢或者厌恶的人,你不是更有欲望去他们地里做些什么动作吗?当你去偷菜时只是为了简单的得到经验和升 级吗?显然,网游这方面具有先天的单薄性。总之,网游的社交性相比于社交游戏更显松弛和单薄。

同样,有很多同学或许也称开心网上的游戏为网页游戏,所以有必要区分下这两个概念。从词的范畴来说,网页游戏与社交游戏定义的角度不同,前者是基于游戏的呈现载体,而后者是基于游戏的功能目的,其从属关系可从下图简单说明。

web_vs_social_game

其中相交的部分即是定义的角度相同时二者的重合关系,换句话说,以社交为目的的网页游戏即是社交游戏,而以网页形式为呈现载体的社交游戏也是网页游戏,当然,网页游戏也可只是单机版,而同样社交游戏也可出现在ipad,ps等载体上。

作为本小节的结束语,社交游戏从传统游戏的追求游戏的乐趣与娱乐的基础上,延展至追求一种实际社会关系的某种影响上,而马斯洛的五种需求层次之中的“社交需求”也正解释了为什么社交游戏会得到强劲的发展的原因。看图不说话。

游戏与需求

市场状况

市场容量的分析通常由第三方的咨询公司来给出,这里引用相关的新闻(或者“所谓的”新闻)来给个直观的感受:

  1. 美国社交游戏的市场在2012年超过20亿美元
  2. zynga今年收入将达8.5亿美元,明年将达10亿美元
  3. 日本社交游戏市场规模将达10亿美元
  4. 据艾瑞统计,2008年中国休闲类社交网络市场规模为1.9亿元,较2007年的1.2亿元增长64.0%。2009年达到3.7亿元,并在2012年达到16.1亿元。这个增幅是每一个淘金者都会看红眼的。

除此而外,我们可以看看下面艾瑞关于社交游戏市场规模的一些预测,虽然各个版本的数字有一定的差异,但总体趋势是相同的。

社交游戏市场规模

本图引用自http://www.iresearch.com.cn/View/121267.html

而在CNNIC的2010年中国网页游戏调查报告有如下一段研究发现:

  1. 中国网页游戏用户规模达1.05 亿,其中社交类网页游戏用户规模最大,达到9209
    ,大型网页游戏用户规模2384万,网页单机游戏用户规模3791 万。
  2. 19岁到 30 岁用户构成网页游戏最大用户群体,比例为64.5%。
  3. 网页游戏用户的有收入人群比例较大,为77.1%, 其中平均月收入在1000元到 3000
    的用户比例最大,占到总体用户的43.7%。
  4. 朋友介绍与搜索引擎是网页游戏信息获取的主要渠道,比例均为71.5%。

推荐朋友可以阅读下CNNIC的报告

营利模式

社交游戏在营利上也采取与当下免费网游同样的策略,即游戏本身免费,而以出售道具或者增值产品来获得收入,当然随着游戏本身的发展相应的营利模式也在不断拓展,例如植入广告,周边产品的开发。具体可用下表来总结:

营利方式 典型示例 备注
道具出售 开心农场的道具 如种子等
植入广告 tikiisland中的可口可乐广告 还有开心网的相关广告植入等。
周边产品 泡泡鱼的淘宝店 不过似乎销售不是特别理想。

当然,社交游戏的社交性决定其必须依附于具有大量用户的SNS网络,如国外的facebook,myspace,国内的开心网,人人网等,平台商自不会看 着你独自享用这样的赢利机会,于是人人网,facebook等平台相继收取30%左右分成来压榨开发商的利润空间,这也是之前不久zynga与facebook之间以生掐架的原因。

除了平台商的分成外,如果开发商使用第三方的支付系统,仍需向其提供10%左右不等的分成。

当然上面是说开发商自己开发,自己运营所涉及到的额外支出,如果开发商是通过第三方的发布商来在某个平台上进行发布(原因是开发商的人力和财力所限,或者 发布商与平台商的关系等),那么发布商通常要分去50%左右的分成(如plinga在VZ上发布游戏),所以到头来能够回到游戏开发商的收入已是少之又少 了。

市场发展情况

正如文首说所的,社交游戏市场已经从蓝海变成了血腥的红海,而随着EA对playfish,Disney对playdom以及zynga对若干公司的收 购,整个社交游戏市场已经开始了新一轮的格局调整,在此过程中竞争力差的公司会相继出局,遗留的只能是那些有大量资源(流量,高质量产品)的开发商、发布 商等。

在如今的市场环境下,大量的开发商不再试图去创新,而是所谓的“山寨”(当然我们公司也逃不出),zynga出了款挖宝的游戏,国内的厂商开始也开 发;playdom出了款城市建造的游戏,国内连忙跟进,于是市场上充斥了大量的同类型的城市类游戏。更为可怕的是,其它领域在市场格局调整时的惨剧也同 样在社交游戏上上演——恶性的竞争与拷贝,这点在社交游戏上更为突出。从技术角度来讲,社交游戏前端通常采用flash,而拥有网络的任一个人都可将其下 载,使用反编译工具查看相关的源码,如果下载反编译的是一个公司,那么后果可想而知,原厂家用6个月心血开发而来的游戏,你(或者某个厂家)只用几周调通 前端写个后端即可,当然技术的话题可留作本系列文章的技术篇中细说。

在市场不断成熟的条件下,开发商的日子并不好过,特别是话语权低的小开发商,你不断要受到平台商的无理压榨,甚至随时删除你的游戏,也要小心同行的恶意拷贝,在受尽压榨的处境下充满中成为另一个中国zynga的美好梦想,当然或许仅是梦想而已。

未来的展望

一次去中关村买移动硬盘时,发现了一个有趣的事情,我循着海龙各个商贩的展台过时,看到的是各个店员“忙时则招揽生意,闲时则偷偷菜”,甚至我询问生意的声音也没能把沉迷的店员从泡泡龙中拉出来。

市场仍在向好发展,社会对社交游戏的认可也越来越高,对于购买道具也越来越习惯和接受(应该感谢QQ的市场培育),而且购买渠道也十分畅通(各个第三方的支付系统),相信社交游戏市场在剧烈的调整下正在逐步走向成熟和稳定,并且会构成游戏中的一个重要的分支。

当然,未来社交游戏的属性也会有一定的调整,除了更少的急功近利和恶性竞争,还需要建立起一定的行业标准,以及协调与各个利益方的关系,这样整个社交游戏产业才能更好的、保持良性的发展。

最后说一个小故事,说,某一天,大家都在公司上班,为成为中国的zynga在努力,突然一个同事震惊地要我们去看个东西,原来是在人人上看到了一款与 social city完全一样的游戏(叫A游戏吧),美工UI等完全相同(显然是直接拿人家的),不同的只是语言和开发商署名,我们在好奇版权问题时,这时一个同事冒 出个句,“人人网是山寨,A游戏也是山寨,山寨上的山寨,山寨中的山寨,严格的审核不是自己抽自己?”于是我们大呼经典继而继续努力。

最后附一张世界sns的布局图,当然或许太过粗略,也不完全符合实际,但是欣欣向荣的形势还是看得见的。

world-social-network-map

本图摘自http://www.mapsofworld.com/images/world-social-network-map.jpg

更多参考

  1. 全世界sns平台图
  2. social game的市场规模
  3. 2010年中国网页游戏调查报告

[转载]在 ASP.NET MVC Web 应用程序中输出 RSS Feeds

mikel阅读(1004)

[转载]在 ASP.NET MVC Web 应用程序中输出 RSS Feeds – 雪的梦幻 – 博客园.

RSS全称Really Simple Syndication。一些更新频率较高的网站可以通过RSS让订阅者快速获取更新信息。RSS文档需遵守XML规范的,其中必需包含标题、链接、描述信息,还可以包含发布时间、最后更新时间等信息。

本文将介绍通过LINQ to XML生成XML文档,并在ASP.NET MVC Web应用程序中输出。

在生成RSS文档前,先简单了解一下RSS的结构。根节点rss下有channel节点,channel节点的一些子节点 (title,link,description)包含了该RSS的部分描述信息。channel下可包含多个item节点用来表示多个内容信息,如博客 中的文章、论坛中的帖子。

代码

1 <rss version=”2.0″>
2 <channel>
3 <title>channel标题</title>
4 <link>网页地址</link>
5 <description>channel描述</description>
6 <item>
7 <title>内容1标题</title>
8 <description>内容1描述</description>
9 <link>内容1链接</link>
10 </item>
11 <item>
12 <title>内容2标题</title>
13 <description>内容2描述</description>
14 <link>内容2链接</link> </item>
15 </channel>
16 </rss>

1. 用LINQ to XML生成类似上述的文档。

1.1 新建一个XDocument,添加根节点和相关属性描述。

代码

1 XDocument doc = new XDocument(
2 new XDeclaration(1.0, utf-8, yes), // XML文档声明
3 new XElement(rss, // 根节点
4 new XAttribute(version, 2.0), // rss节点的属性
5 new XElement(channel // rss的子节点channel
6 )));                    )));

1.2 处理channel节点和它的相关描述。

代码

1 XElement channel = new XElement(channel); // channel节点
2 channel.Add(new XElement[]{
3 new XElement(title,Test), // channel标题
4 new XElement(link,http://localhost), // 页面链接
5 new XElement(description,Test RSS) // channel描述
6 });

1.3 往channel节点增加内容信息,rssFeedList是 List<RssFeed>类型的。由于item数量不固定,这里用了foreach将list中的每一个内容信息都加到channel。

代码

1 foreach (var rssFeed in rssFeedList) // 对rssFeed集合中的每个元素进行处理
2 {
3 XElement item = new XElement(item, new XElement[]{ // 生成一个新的item节点
4 new XElement(title,rssFeed.Title), // 为新的item节点添加子节点
5 new XElement(description,rssFeed.Description),
6 new XElement(link,rssFeed.Link),
7 new XElement(pubDate,rssFeed.PublishDate)
8 });
9 channel.Add(item); // 将新的item节点添加到channel中
10 }

2. 创建RssFeedResult类

我们写一个RssFeedResult类,继承自ActionResult,以便在ASP.NET MVC的controller中返回RSS。关于这部分内容可参考之前的一篇文章《让ASP.NET MVC页面返回不同类型的内容》。

代码

1 public class RssFeedResult : ActionResult
2 {
3 List<RssFeed> Data { get; set; }
4
5 public RssFeedResult(List<RssFeed> data)
6 {
7 Data = data;
8 }
9
10 public override void ExecuteResult(ControllerContext context)
11 {
12 if (context == null)
13 {
14 throw new ArgumentNullException(context);
15 }
16
17 HttpResponseBase response = context.HttpContext.Response;
18 response.ContentType = text/xml; // 设置HTTP头中的ContentType
19 XDocument result= RssFeedHelper.GetRssFeed(Data); // 获取XML数据
20 response.Write(result.ToString()); // 将XML数据写入response中
21 }
22 }

3. 在controller中使用

我们只要在controller中调用RssFeedResult(rssFeedList)方法即可返回RSS页面了。

代码

public RssFeedResult Rss()
{
// 添加2个测试用的数据
RssFeed r1 = new RssFeed { Description = Test1, Link = http://localhost/1, Title = Test1, PublishDate = DateTime.Now };
RssFeed r2
= new RssFeed { Description = Test2, Link = http://localhost/2, Title = Test2, PublishDate = DateTime.Now };
List
<RssFeed> rssFeedList = new List<RssFeed>();
rssFeedList.Add(r1);
rssFeedList.Add(r2);

// 返回RSS
return new RssFeedResult(rssFeedList);
}

示例下载 (Visual Studio 2010)

另外,还有一个工具ASP.NET RSS Toolkit,有需要的可以参考一下。

[转载]用Delphi从内存流中判断图片格式

mikel阅读(1013)

[转载]用Delphi从内存流中判断图片格式 – chybaby的专栏 – CSDN博客.

废话不多说了,利用内存流来判断文件的格式,其实判断文件的前几个字节就可以简单的判断这个文件是什么类型的文件,例如

jpg文件 是 FFD8 (从低位到高位就要反过来 D8FF 下面都是一样)

BMP文件 是 424D —4D42

其他的我就不一一列举了,想知道跟多文件类型分别是用什么字符作为文件的开头的话,下载个C32asm或者UE等这类16进制编辑器就可以看到了。

procedure TForm1.Button1Click(Sender: TObject); //Button1的单击事件
var
//声明变量
MyImage:TMemoryStream;   //内存流对象
Buffer:Word;
i:integer;
begin
if OpenDialog1.Execute then
//OpenDialog1是一个文件打开对话框,在Delphi组件面版的Dialog页中可以找到。
begin
MyImage:=TMemoryStream.Create; //建立内存流对象

try
MyImage.LoadFromFile(OpenDialog1.FileName);
//把刚刚用户选择的文件载入到内存流中
MyImage.Position := 0;
//移动指针到最开头的位置
if MyImage.Size = 0 then
//如果文件大小等于0,那么
begin
//错误
ShowMessage(‘错误‘);
Exit;
end;
MyImage.ReadBuffer(Buffer,2);
//读取文件的前2个字节,放到Buffer里面

if Buffer=$4D42 then
//如果前两个字节是以4D42[低位到高位]
begin
ShowMessage(‘BMP‘);
//那么这个是BMP格式的文件
end
else if Buffer=$D8FF
then //如果前两个字节是以D8FF[低位到高位]
begin
//JPEG
ShowMessage(‘JPEG‘); //……..一样 下面不注释了
end
else if Buffer=$4947
then
begin
//GIF
ShowMessage(‘GIF‘);
end
else if
Buffer=$050A
then
begin
//PCX
ShowMessage(‘PCX‘);
end
else if
Buffer=$5089
then
begin
//PNG
ShowMessage(‘PNG‘);
end
else if
Buffer=$4238
then
begin
//PSD
ShowMessage(‘PSD‘);
end
else if
Buffer=$A659
then
begin
//RAS
ShowMessage(‘RAS‘);
end
else if
Buffer=$DA01
then
begin
//SGI
ShowMessage(‘SGI‘);
end
else if
Buffer=$4949
then
begin
//TIFF
ShowMessage(‘TIFF‘);
end
else
//如是其他类型的文件的话,直接显示错误
begin
//ERR
ShowMessage(‘ERR‘);
end;
//if
end; //if

finally

MyImage.Free;   //释放内存流对象

end;
end;

上面的过程只是简单的判断文件的前2个字节,如果想更加精确一点的话,可以把文件最后2个字节也判断上。

[转载]actionscript3.0中的MVC,EventDispather,IEventDispather的学习

mikel阅读(1094)

[转载]actionscript3.0中的MVC,EventDispather,IEventDispather的学习 – bigbigdotnet – 博客园.

在as3.0中使用mvc来构建项目的时候,在model层,总免不了使用事件。在这个例子里,使用MVC创建了一个简单的数字时钟的功能。在model层,使用了4种方式来处理事件发送。并简单对比了一下。

方法1.model类继承自EventDispather

方法2.model类复合EventDispather

方法3.model类继承自Sprite

方法4.model类实现IEventDispatcher

当前代码注释默认设置方法1来实现,若设置对应的注释可以的尝试使用4种方法来实现这个简单的例子。

自我感觉除了方法2不太好以外,其它方法的都可行。

环境:Flash build4 ,sdk3.5

代码下载地址:http://www.helloshp.cn/bigbigdotnet.cnblogs.com_jpg/mvc.rar

QQ截图未命名

程序运行效果:

文档类(程序入口):

Main.cs

package
{
import Control.*;
import Model.*;
import View.*;
import flash.display.Sprite;
[SWF(width=”200″,height=”100″)]
public class Main extends Sprite
{
public function Main()
{
var model:Model_A = new Model_A();
//var model:Model_B = new Model_B();
//var model:Model_C = new Model_C();
//var model:Model_D = new Model_D();
var controller:Controller = new Controller(model);
var view:View = new View(model,controller);
addChild(view);
view.x = 30;
view.y = 30;
}
}
}

控制器(control):

Controller.cs

package Control
{
import flash.utils.Timer;
import flash.events.TimerEvent;
import Model.*;

public class Controller
{
private var model:Model_A;
//private var model:Model_B;
//private var model:Model_C;
//private var model:Model_D;
private var timer:Timer;
public function Controller(model:Model_A):void{
this.model = model;
}

public function startTime():void{
model.startTime();
}
}
}

视图器(view):

View.cs

package View
{
import Control.*;
import Model.*;
import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextField;
public class View extends Sprite
{
private var model:Model_A;
//private var model:Model_B;
//private var model:Model_C;
//private var model:Model_D;
private var controller:Controller;
private var tf:TextField;
public function View(model:Model_A,controller:Controller):void{
this.controller = controller;
tf = new TextField();
addChild(tf);
controller.startTime();
this.model = model;
//Mode层为Model_A时使用:
model.addEventListener(“action”,onActionHandler);
//Mode层为Model_B时使用:
//model.getSender().addEventListener(“action”,onActionHandler);
//Mode层为Model_C时使用:
//model.addEventListener(“action”,onActionHandler);
//Mode层为Model_D时使用:
//model.addEventListener(“action”,onActionHandler);
}
private function onActionHandler(e:Event):void{
tf.text = “时间:” + model.hour+” : “+model.minutes+” : “+model.second;
trace(e.target);
//当使用方法2的时候,以下这段代码,将会报错!这是因为mode_B中创建_dispather的时候,没有将this的引用注入到_dispatcher里面,
//即是说,没有把mode_B类的引用注入到_dispatcher里,侦听函数的target对象指向的是dispatcher,而不是mode_B本身
//尽管在mode_B类中发送消息,可以这样写:dispatcher = new EventDispatcher();,但以下代码就会报错!
//而如果mode_B类中实现IEventDispather接口,同时这样写:dispatcher = new EventDispatcher( this );以下代码就会正确执行。
trace(e.target.hour);
}
}
}

模型器(model):

方法一:Model_A.cs

package Model
{
import flash.events.*;
import flash.utils.Timer;

//方法1:Model继承自EventDispatcher
public class Model_A  extends EventDispatcher
{
public var hour    :String;
public var minutes    :String;
public var second    :String;
public var timer    :Timer;
public function Model_A(){}
public function startTime():void{
timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER,onTimerHandler);
timer.start();
}
private function onTimerHandler(e:TimerEvent):void{
var nowDate:Date = new Date();
hour     = nowDate.getHours()    >9    ?    String(nowDate.getHours())    :”0″    +    nowDate.getHours();
minutes = nowDate.getMinutes()    >9    ?    String(nowDate.getMinutes()):”0″    +    nowDate.getMinutes();
second     = nowDate.getSeconds()    >9    ?    String(nowDate.getSeconds()):”0″    +    nowDate.getSeconds();
//直接继承自EventDispatcher所以直接调用dispatchEvent广播事件
dispatchEvent(new Event(“action”));
}
}
}

方法二:Model_B.cs

package Model
{
import flash.events.*;
import flash.utils.Timer;
//方法1:Model没有继承自EventDispatcher
public class Model_B
{
public var hour    :String;
public var minutes    :String;
public var second    :String;
public var timer    :Timer;
//定义一个EventDispatcher对象
public var _dispatcher    :EventDispatcher;
public function Model_B(){
initSender();
}
public function startTime():void{
timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER,onTimerHandler);
timer.start();
}
public function getSender():EventDispatcher{
return _dispatcher;
}
private function initSender():void{
_dispatcher = new EventDispatcher();
}
private function onTimerHandler(e:TimerEvent):void{
var nowDate:Date = new Date();
hour     = nowDate.getHours()    >9    ?    String(nowDate.getHours())    :”0″    +    nowDate.getHours();
minutes = nowDate.getMinutes()    >9    ?    String(nowDate.getMinutes()):”0″    +    nowDate.getMinutes();
second     = nowDate.getSeconds()    >9    ?    String(nowDate.getSeconds()):”0″    +    nowDate.getSeconds();
//调用_dispatchEvent广播事件
_dispatcher.dispatchEvent(new Event(“action”));
}
}
}

方法三:Model_C.cs

package Model
{
import flash.display.Sprite;
import flash.events.*;
import flash.utils.Timer;
//方法3:继承自Sprite,同时Sprite也是属于EventDispather类的子类,
public class Model_C extends Sprite
{
public var hour    :String;
public var minutes    :String;
public var second    :String;
public var timer    :Timer;
public function Model_C(){
}
public function startTime():void{
timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER,onTimerHandler);
timer.start();
}
private function onTimerHandler(e:TimerEvent):void{
var nowDate:Date = new Date();
hour     = nowDate.getHours()    >9    ?    String(nowDate.getHours())    :”0″    +    nowDate.getHours();
minutes = nowDate.getMinutes()    >9    ?    String(nowDate.getMinutes()):”0″    +    nowDate.getMinutes();
second     = nowDate.getSeconds()    >9    ?    String(nowDate.getSeconds()):”0″    +    nowDate.getSeconds();
//直接调用Spreite所继承的EventDispather类的dispatchEvent广播事件
super.dispatchEvent(new Event(“action”));
}
}
}

方法四:Model_C.cs

package Model
{
import flash.events.*;
import flash.utils.Timer;
//方法4,Model直接实现IEventDispatcher,但要实现5个必须的方法
public class Model_D implements IEventDispatcher
{
public var hour    :String;
public var minutes    :String;
public var second    :String;
public var timer    :Timer;
private var _dispatcher:EventDispatcher;
public function Model_D(){
//this传进来很重要。也即是说把该类的引用传递给EventDispatcher.
//监听函数的target对象指向Model_D类的引用而不是_dispatcher;
_dispatcher = new EventDispatcher(this);
}
public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
{
_dispatcher.addEventListener(type,listener,useCapture,priority,useWeakReference);
}
public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
{
_dispatcher.removeEventListener(type,listener,useCapture);
}
public function dispatchEvent(event:Event):Boolean
{
return _dispatcher.dispatchEvent(event);
}
public function hasEventListener(type:String):Boolean
{
return _dispatcher.hasEventListener(type);
}
public function willTrigger(type:String):Boolean
{
return _dispatcher.willTrigger(type);
}
public function startTime():void{
timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER,onTimerHandler);
timer.start();
}
private function onTimerHandler(e:TimerEvent):void{
var nowDate:Date = new Date();
hour     = nowDate.getHours()    >9    ?    String(nowDate.getHours())    :”0″    +    nowDate.getHours();
minutes = nowDate.getMinutes()    >9    ?    String(nowDate.getMinutes()):”0″    +    nowDate.getMinutes();
second     = nowDate.getSeconds()    >9    ?    String(nowDate.getSeconds()):”0″    +    nowDate.getSeconds();
//调用dispatchEvent广播事件
_dispatcher.dispatchEvent(new Event(“action”));
}
}
}

[转载]用一个最简单方法解决asp.net页面刷新导致数据的重复提交

mikel阅读(814)

[转载]用一个最简单方法解决asp.net页面刷新导致数据的重复提交 – 该死的代码 – 博客园.

页面刷新导致数据重复提交这个问题困扰我也很久了,在网上搜了一个大家把解决的办法多聚焦在了如何判定是刷新还是正常提交上了。这个方法通过Session放一些识别数据也可以解决问题。

这里我只是想提供另外一个思路,供博友们参考。

“GET”与“POST”想必大家已经了解很多了,也只有在post时,才会担心刷新致使重复提交。自从ASP.NET出世,大家肯定大量 的烂用post。我觉得,大部分情况还是用get,大不了多加几个querystring,只有数据操作时才用post, 一量数据提交完毕之后,立即切换成get方式,这样用户都没有机会使用刷新重复提交数据。

每次执行完一次事件,立即调用Reload,用GET方法重新查看已经提交数据。当然,如果这个提交的过程很久,其间用户点了刷新,这段代码就无能为力了。

protected void Button1_Click(object sender, EventArgs e)
{
count
++;
this.Button1.Text = count.ToString();
Reload(
run success!);
}

private void Reload(string message)
{
string script1 = <script>alert(\{0}\);window.location.href='{0}’;</script>;
string script2 = <script>window.location.href=\{0}\;</script>;
string outstring;

if (string.IsNullOrEmpty(message))
{
outstring
= string.Format(script2, this.Request.Url.OriginalString);
}
else
{
outstring
= string.Format(script1, message, this.Request.Url.OriginalString);
}

Response.Write(outstring);
Response.End();
}

[转载]jQuery实现的几个你可能没用过的功能

mikel阅读(893)

[转载]jQuery实现的几个你可能没用过的功能 – 爱因斯坦的小脑 – 博客园.

JQuery好久了,都做了两个项目了。今儿晚上喝咖啡喝多了,这都两点多了睡不着,给大家分享下我在项目中用到的一些用JQuery实现的一些比较好的功能。希望对一些新手有点用。。。高手们可以拍砖哈。。。。我头很硬不怕疼。。。呵呵。

一.创建一个自己的dropdownlist

说到dropdown list,在html中你会想到

1 <select>
2 <option>hello 1</option>
3 </select>

但是它的显示会不大好看,我们可以使用div+ul来自己做一个drop down list,而且有很苦的slidedown和slideup功能。

在IE8下的效果对比:

image

首先说说思路,很简单的思路,

a. 需要用一个Div来代替drop down list中选中记录显示的那个容器,通过offset来得到这个Div应该显示的位置,offtset.top和offset.left。

b. 通过一个UL以及它的孩子们li来模拟下拉框。这里需要注意几个问题,

i:一定要把UL放在一个新建好的Div里面,而且这个Div的位置距离top的数据上一步中的Div(我们叫它iDiv)的top+iDiv.height;

ii:每次在点击一个li元件后一定要清空它,不然你的drop down list会越来越长。。。

iii:当鼠标在别的地方点击时,一点要隐藏掉dropdown list。

下面我来一步一步结合代码来给说明如何实现这个功能:

1.创建iDiv来作为drop down list选中值的容器。

在创建iDiv之前我们需要先来得到要显示这个drop down list的位置:

1 // get the select list ‘s position using offset,width and height
2 var offset = $(.select_css).offset();
3 var width = $(.select_css).width();
4 var height = $(.select_css).height();

接下来是创建iDivb并使用css()方法来为iDiv添加格式。

1 var iDiv = $(<Div id=’iDiv’ class=’iDiv’>).css({
top: offset.top,
left: offset.left,
width: width,
height: height,
border: 1px solid #aaaaaa,
fontSize: 12px,
textIndent: 4px,
cursor: default }).text(hello);

iDiv也给加了个class=’iDiv’,本来不需要的,但是后来我发现JQuery的css()无法去搞定背景图片的no-repeat 属性,google了半天老外也没有例子,所以只有通过这个clas=’iDiv’来设定:

1 .iDiv
2 {
3 background-image:url(‘images/select_right.gif’);
4 background-position:right;
5 background-repeat:no-repeat;
6 }

效果如下;

image

2.在iDiv发生点击事件时,来创建一个下拉框,并使用slidedown效果。

首先我们需要创建一个cDiv并把它添加到html的body,它的位置刚好是在iDiv的下面,所以需要cDiv的创建如下:

1 var cDiv = $(<div id=’cDiv’>).css({
2 position: absolute,
3 width: width,
4 top: offset.top + 22,
5 left: offset.left,
6 background: #f7f7f7,
7 border: 1px solid silver
8 }).hide();

而且默认我们要它隐藏掉。

有了这个cDiv,我们只需要在iDiv发生Click事件时创建一个UL列表,并把它append倒cDiv。

1 var UL = $(<ul style=’list-style:none;margin:0;padding:0;’></ul>).appendTo(cDiv);
2 for (var i = 1; i < 10; i++) {
3 $(<li style=’testIndent:4px;height:20px;lineheight:20px; cursor:pointer;’>).appendTo(UL).text(hello + i).mouSEOver(function () {
4 $(this).css(
5 {
6 color: white,
7 background: gray
8 }
9 );
10 }).mouSEOut(function () {
11 $(this).css(
12 {
13 color: black,
14 background: white
15 });
16 }).click(function () {
17 // disvisualble the cDiv and set the selected crrent li’s text as iDiv’s text
18 $(#cDiv).slideUp().hide();
19 $(#iDiv).html($(this).html());
20 });
21 }
22 // slide show the cDiv now
23 $(#cDiv).slideDown(slow);

可以看到在添加每条li记录时都为它添加了mouSEOver,mouseout和click事件。

在click事件发生时,我们不仅要把cDiv给slideUp还需要把它隐藏掉,并且在下次点击iDiv之前先清空cDiv。这两点非常重要。你可以试试不做这两点时会出现什么效果。

在click li时别忘了把当前li的html内容复制给iDiv,不然我们的控件就没实际作用啦。。。。。

3.使用Ajax从服务器获取下拉列表的值。

很多时候我们需要动态的从服务器获取下拉列表的值,这样就需要在点击iDiv时先通过jQuey的ajax方法(或者其他的ajax方法)从服务器load数据,在数据load完成时我们才开始创建UL列表。

我这里使用的是WCF Servece作为ajax请求的数据源。

image

为了增加用户友好型,在从服务器取数据时,我们让iDiv显示为一个load的图片。。。。。。。。。。。。

image

二.使用jQuery的append功能来无刷新切换播放的视频文件(flash或Silverlight播放器)。

之前有个minisite需要用到这个东西。我就试着研究了下,还真行的通。

http://haokan.lafaso.com/pretty.html 大家可以看一下。我这个不算做广告吧,大家基本都是男的基本上不会看这个的。呵呵。只是这个方法我觉得你说不定以后可以用到的。

由于这些播放器都是一个embed控件,所以我们可以通过替换embed的src属性来播放不同的视频。例如:

image

使用jQuery的append()方法我们来个偷梁换柱,就可以把embed的src给换掉,并重新把div1的html给换掉,在页面上就像是使用ajax技术。

1 $(#div1 embed).empty();
2 var placeHolder = $(<div />);
3 var tempParent = $(<div />);
4 var embed = $(#div1 embed);
5 embed.replaceWith(placeHolder);
6 tempParent.append(embed);
7 embed.attr(src, http://player.ku6.com/refer/DMFZdNYzKDEosiPG/v.swf&auto=1);
8 placeHolder.replaceWith(tempParent.html());

三.用jQuery来为HTML实现header和footer功能。

在php,ASP.NET中都有header和footer这种控件,php中用include,而在ASP.NET中我们用master或者是ascx都行。

在html中呢?我相信一直没有。但是客户要求我们做的页面必须是html,说是怕用户太多。。。。。

用footer和header的好处就是当需要修改这些部分的内容时,我们只需要修改一个页面,所有的页面就都会变化。

后来找到个办法是使用jquery的load()方法。

首先我们需要在html中添加两个Div一个在<body>的最上面,一个在最下面,最好是一个Id=’header’,一个id=’footer’。

然后在服务器端我们只需要创建一个header.html和一个footer.html。

在页面加载时我们会用jquery的load方法来loadheader.html和footer.html。

image

代码:

1 $(#header).load(controls/header.html, function (response, status, xhr) {
2 if (status == error) {
3 var msg = 服务器数据传输错误,请刷新页面;
4 // $(“#error”).html(msg + xhr.status + + xhr.statusText);
5 alert(msg);
6 }
7 });
8
9 // load footer from server
10 $(#footer).load(controls/footer.html, function (response, status, xhr) {
11 if (status == error) {
12 var msg = 服务器数据传输错误,请刷新页面;
13 // $(“#error”).html(msg + xhr.status + + xhr.statusText);
14 alert(msg);
15 }
16 });
17
18

后面有可能的话我会接着总结点jQuery的技巧和大家分享。。。。。。。。还有那个下拉框的代码我稍后给大家提供下载地址。

Cheers

Nic