[转载]PDFSharp生成PDF. - 天天不在 - 博客园

mikel阅读(959)

[转载]PDFSharp生成PDF. – 天天不在 – 博客园.

在上面用OpenXML生成word后,原来利用Word2010里的导出成PDF功能就不能用.

然后找开源组件生成PDF,最开始用的是iTextSharp,做完导出报表了才发现,这个开源协议用的是AGPL,只能放弃,重新查找后,找到 PDFSharp(MTI协议).结合了MigraDoc来生成PDF,过程大同小异,对比iTextSharp,在画相关元素时,会慢不少,20页A4 内容,OpenXML和iTextSharp都能保持在2S内输出完成,而PDFSharp需要5-10S,不知是不是因为GDI+的原因.

代码不讲解了,只贴出来,只说明一点,对中文的支持,需要设置下.

System.Drawing.Text.PrivateFontCollection pfcFonts = new System.Drawing.Text.PrivateFontCollection();
string strFontPath = @”C:/Windows/Fonts/msyh.ttf”;//字体设置为微软雅黑
pfcFonts.AddFontFile(strFontPath);
Style style = document.Styles[“Normal”];
style.Font = new MigraDoc.DocumentObjectModel.Font(pfcFonts.Families[0].Name, 12);

复制代码
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Text;
  4 using System.IO;
  5 using PdfSharp;
  6 using PdfSharp.Drawing;
  7 using PdfSharp.Pdf;
  8 using PdfSharp.Pdf.IO;
  9 using MigraDoc.DocumentObjectModel;
 10 using MigraDoc.DocumentObjectModel.Tables;
 11 using MigraDoc.DocumentObjectModel.Shapes;
 12 using System.Drawing;
 13 using MigraDoc.Rendering;
 14 namespace EDM.ReportTemplate
 15 {
 16     public class ExportPDF : ExportReport
 17     {
 18         private Section section;
 19         private SizeF PdfSize;
 20 
 21         public override void Execute()
 22         {
 23             var size = InitPage();
 24             Document doc = new Document();
 25             section = doc.AddSection();
 26             section.PageSetup = InitPage();
 27             DefineStyles(doc);
 28             PForm.ReportProgress(PShow.StartExecute, null);
 29             //CreateHead();
 30             foreach (ReportCommon common in Commons)
 31             {
 32                 if (common is ReportTable)
 33                 {
 34                     ReportTable table = common as ReportTable;
 35                     // ChangeTableColumn(table);
 36                     AddTable(table, doc);
 37                 }
 38                 if (common is ReportText)
 39                 {
 40                     ReportText table = common as ReportText;
 41                     AddText(table, doc);
 42                 }
 43                 if (common is ReportImage)
 44                 {
 45                     ReportImage table = common as ReportImage;
 46                     AddImage(table, doc);
 47                 }
 48                 if (common is ReportValueList)
 49                 {
 50                     ReportValueList table = common as ReportValueList;
 51                     AddValueList(table, doc);
 52                 }
 53                 if (common is ReportValue)
 54                 {
 55                     ReportValue table = common as ReportValue;
 56                     AddValue(table, doc);
 57                 }
 58                 SetExectueProgress(common);
 59             }
 60             PForm.ReportProgress(PShow.EndExecute, null);
 61             PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer(true);
 62             pdfRenderer.Document = doc;
 63             pdfRenderer.RenderDocument();
 64             pdfRenderer.Save(FileName);
 65         }
 66 
 67         public static void DefineStyles(Document document)
 68         {
 69             System.Drawing.Text.PrivateFontCollection pfcFonts = new System.Drawing.Text.PrivateFontCollection();
 70             string strFontPath = @"C:/Windows/Fonts/msyh.ttf";//字体设置为微软雅黑 
 71             pfcFonts.AddFontFile(strFontPath);
 72             Style style = document.Styles["Normal"];
 73             style.Font = new MigraDoc.DocumentObjectModel.Font(pfcFonts.Families[0].Name, 12);
 74             style.Font.Color = Colors.Black;
 75 
 76             style = document.Styles["Heading1"];
 77             //style.Font.Name = "Tahoma";
 78             style.Font.Size = 20;
 79             style.Font.Bold = true;
 80             style.ParagraphFormat.Alignment = ParagraphAlignment.Center;
 81             // style.Font.Color = Colors.DarkBlue;
 82             style.ParagraphFormat.PageBreakBefore = true;
 83             style.ParagraphFormat.SpaceAfter = 6;
 84 
 85             style = document.Styles["Heading2"];
 86             style.Font.Size = 16;
 87             style.Font.Bold = true;
 88             style.ParagraphFormat.PageBreakBefore = false;
 89             style.ParagraphFormat.SpaceBefore = 6;
 90             style.ParagraphFormat.SpaceAfter = 6;
 91             style.ParagraphFormat.Alignment = ParagraphAlignment.Left;
 92 
 93             style = document.Styles["Heading3"];
 94             style.Font.Size = 14;
 95             style.Font.Bold = true;
 96             style.Font.Italic = true;
 97             style.ParagraphFormat.SpaceBefore = 6;
 98             style.ParagraphFormat.SpaceAfter = 3;
 99             style.ParagraphFormat.Alignment = ParagraphAlignment.Left;
100 
101             style = document.Styles["Heading4"];
102             style.Font.Size = 12;
103             style.Font.Bold = true;
104             style.Font.Italic = true;
105             style.ParagraphFormat.SpaceBefore = 3;
106             style.ParagraphFormat.SpaceAfter = 3;
107             style.ParagraphFormat.Alignment = ParagraphAlignment.Left;
108 
109             style = document.Styles[StyleNames.Header];
110             style.ParagraphFormat.AddTabStop("16cm", TabAlignment.Right);
111 
112             style = document.Styles[StyleNames.Footer];
113             style.ParagraphFormat.AddTabStop("8cm", TabAlignment.Center);
114 
115             // Create a new style called TextBox based on style Normal
116             style = document.Styles.AddStyle("TextBox", "Normal");
117             style.ParagraphFormat.Alignment = ParagraphAlignment.Justify;
118             style.ParagraphFormat.Borders.Width = 2.5;
119             style.ParagraphFormat.Borders.Distance = "3pt";
120             //TODO: Colors
121             style.ParagraphFormat.Shading.Color = Colors.SkyBlue;
122 
123             // Create a new style called TOC based on style Normal
124             style = document.Styles.AddStyle("TOC", "Normal");
125             style.ParagraphFormat.AddTabStop("16cm", TabAlignment.Right, TabLeader.Dots);
126             style.ParagraphFormat.Font.Color = Colors.Blue;
127 
128             // Create a new style called Table based on style Normal
129             style = document.Styles.AddStyle("Table", "Normal");
130             style.Font.Name = pfcFonts.Families[0].Name;
131             style.Font.Size = 12;
132 
133             // Create a new style called Reference based on style Normal
134             style = document.Styles.AddStyle("Reference", "Normal");
135             style.ParagraphFormat.SpaceBefore = "5mm";
136             style.ParagraphFormat.SpaceAfter = "5mm";
137             style.ParagraphFormat.TabStops.AddTabStop("16cm", TabAlignment.Right);
138         }
139 
140         public PageSetup InitPage()
141         {
142             PageSetup pageSetup = new PageSetup();
143             pageSetup.PageFormat = PageFormat.Letter;
144             PdfSharp.PageSize size = PdfSharp.PageSize.Letter;
145             if (PageSize == "A4")
146             {
147                 pageSetup.PageFormat = PageFormat.A4;
148                 size = PdfSharp.PageSize.A4;
149             }
150             if (PageSize == "B4")
151             {
152                 pageSetup.PageFormat = PageFormat.B5;
153                 size = PdfSharp.PageSize.A5;
154             }
155             var psize = PageSizeConverter.ToSize(size);
156             if (IsOrientation)
157             {
158                 pageSetup.Orientation = Orientation.Landscape;
159                 double width = psize.Width;
160                 psize.Width = psize.Height;
161                 psize.Width = width;
162             }
163             PdfSize = psize.ToSizeF();
164             return pageSetup;
165         }
166 
167         public void CreateHead()
168         {
169             var image = section.Headers.Primary.AddImage("../../PowerBooks.png");
170             image.Height = "2.5cm";
171             image.LockAspectRatio = true;
172             image.RelativeVertical = RelativeVertical.Line;
173             image.RelativeHorizontal = RelativeHorizontal.Margin;
174             image.Top = ShapePosition.Top;
175             image.Left = ShapePosition.Right;
176             image.WrapFormat.Style = WrapStyle.Through;
177         }
178 
179         public void AddTable(ReportTable table, Document document)
180         {
181             var ptable = section.AddTable();
182             ptable.Style = "Table";
183             ptable.Borders.Width = 0.25;
184             ptable.Borders.Left.Width = 0.5;
185             ptable.Borders.Right.Width = 0.5;
186             ptable.Rows.LeftIndent = 0;
187             int colIndex = 0;
188             int cols = table.Column;
189             for (int i = 0; i < cols; i++)
190             {
191                 double width = GetWidth(table.GetWidth(i));
192                 if (width != 0.0)
193                     ptable.AddColumn(width);
194                 else
195                     ptable.AddColumn();
196             }
197 
198             foreach (List<string> strs in table.Table)
199             {
200                 Row row = ptable.AddRow();
201                 for (int i = 0; i < cols; i++)
202                 {
203                     string text = string.Empty;
204                     if (strs.Count > i)
205                     {
206                         if (!string.IsNullOrEmpty(strs[i]))
207                             text = strs[i];
208                     }
209                     //如果有4栏,但是只有三列数据,那到第三列时,开始合并
210                     if (strs.Count != cols && i >= strs.Count - 1)
211                     {
212                         var cell = row.Cells[strs.Count - 1];
213                         if (i == strs.Count - 1)
214                         {
215                             cell.AddParagraph(text);
216                             cell.MergeRight = 0;
217                         }
218                         if (i > strs.Count - 1)
219                         {
220                             cell.MergeRight = cell.MergeRight + 1;
221                         }
222                     }
223                     else
224                     {
225                         row.Cells[i].AddParagraph(text);
226                     }
227                     if (colIndex == 0 && table.IsHaveColumn)
228                     {
229                         row.Format.Font.Bold = true;
230                     }
231                     if (table.IsHaveLevel && colIndex != 0)
232                     {
233                         if (!strs[0].StartsWith(" "))
234                         {
235                             row.Format.Font.Bold = true;
236                         }
237                     }
238                 }
239                 colIndex++;
240             }
241         }
242 
243         public void AddText(ReportText text, Document document)
244         {
245             if (text.Size == 20)
246             {
247                 var paragraph = section.AddParagraph(text.Text, "Heading1");
248             }
249             else if (text.IsHead)
250             {
251                 var paragraph = section.AddParagraph(text.Text, "Heading" + (text.HeadSize - 1));
252             }
253             else
254             {
255                 var paragraph = section.AddParagraph(text.Text);
256                 paragraph.Format.Font.Size = text.Size;
257                 paragraph.Format.Alignment = GetParagraphAlignment(text.Alignment);
258                 paragraph.Format.Font.Bold = text.IsBold;
259             }
260         }
261 
262         public void AddImage(ReportImage image, Document document)
263         {
264             try
265             {
266                 var pImage = section.AddImage(image.Value);
267                 pImage.Width = PdfSize.Width - 100;
268                 pImage.Left = ShapePosition.Center;
269                 section.AddParagraph("");
270             }
271             catch (Exception e)
272             {
273             }
274         }
275 
276         public void AddValueList(ReportValueList valueList, Document document)
277         {
278             var ptable = section.AddTable();
279             ptable.Borders.Visible = false;
280             ptable.Rows.LeftIndent = 0;
281             for (int c = 0; c < valueList.Column; c++)
282             {
283                 ptable.AddColumn(PdfSize.Width / valueList.Column);
284             }
285 
286             for (int i = 0; i < valueList.Values.Count; i++)
287             {
288                 var value = valueList.Values[i];
289                 //当前行数
290                 int rowindex = i / valueList.Column;
291                 //当前列数
292                 int colindex = i % valueList.Column;
293                 if (colindex == 0)
294                 {
295                     ptable.AddRow();
296                 }
297                 var cell = ptable[rowindex, colindex];
298                 cell.Borders.Visible = false;
299                 this.AnalysisText(value);
300                 cell.AddParagraph(value.Text + value.Value);
301             }
302 
303         }
304 
305         public void AddValue(ReportValue value, Document document)
306         {
307             this.AnalysisText(value);
308             var paragraph = section.AddParagraph(value.Text + value.Value);
309             //paragraph.Format.Alignment = GetParagraphAlignment(text.Alignment);
310         }
311 
312         public ParagraphAlignment GetParagraphAlignment(int alignment)
313         {
314             ParagraphAlignment result = ParagraphAlignment.Left;
315             if (alignment == 0)
316                 result = ParagraphAlignment.Center;
317             if (alignment == 1)
318                 result = ParagraphAlignment.Right;
319             return result;
320         }
321 
322     }
复制代码

总的来说,和OpenXML一样,在用OpenXML导出数据时,已经把数据整理为,输出数据,输出图形,输出表格,输出一组数据.这几种形式,我用PDFSharp时,只是针对这几个类型进行处理一下就行了.

毕竟OpenXML只能导出word2007及以上识别的文件,word2003还是需要Ms office com组件,这个类我就不贴了,搜导出word几乎都用的这种.

[转载]纯手工打造漂亮的垂直时间轴,使用最简单的HTML+CSS+JQUERY完成100个版本更新记录的华丽转身! - 三生石上 - 博客园

mikel阅读(979)

[转载]纯手工打造漂亮的垂直时间轴,使用最简单的HTML+CSS+JQUERY完成100个版本更新记录的华丽转身! – 三生石上 – 博客园.

前言

FineUI控件库发展至今已经有 5 个年头,目前论坛注册的QQ会员 5000 多人,捐赠用户 500 多人(捐赠用户转化率达到10%以上,在国内开源领域相信这是一个梦幻数字!也足以证明FineUI旺盛的生命力!)。这一切的得来不是无缘无故的,而是 来自于FineUI的发布理念 – Release Early! Release Often!

时至今天,FineUI总共发布了 100 多个版本

这 100 多个版本更新列表只是文本文件就有 120K 大小,放在页面上更是长的要命,如何恰当的向用户展示 FineUI 勤劳的身影就成了一个问题。之前的展示页面只是简单的将所有的更新记录放在一个 PRE 标签中,显得有点死气沉沉,如下图所示。

image

 

站在巨人的肩膀上

由于前段时间时间轴形式的展示方式比较火,就考虑采用这种方式。但是查阅了网上的JQuery timeline plugin,大部分都比较臃肿,还需要创建Google Spreadsheet Template,并且通过JavaScript调整时间轴中每个记录的位置,也不适合软件更新记录这样大数据集的展现。

其实我需要的只是一个简单、漂亮的数据展示方式,很快我找到了这个例子:http://tympanus.net/Blueprints/VerticalTimeline/

image

这个界面风格给人眼前一亮的感觉。在快速浏览之后,我发现这里面用到了内嵌字体和CSS3的诸多知识来生成哪些漂亮的图片,所以在IE7、IE8下浏览会乱作一团,如下图所示:

image

 

没关系,我们就用简单的图片来代替,其实我最想要的就是左侧的那个垂直直线和那个圆粑粑,网页截图,然后用PhotoShop做简单的处理,得到如下三张图片。

1. 垂直线(10*7)

version_line

2. 浅色的圆粑粑(56*56)

version_dot_alt

3. 深色的圆粑粑(56*56)

version_dot

两个不同颜色的圆粑粑是为了让列表看起来更灵动一点。

 

俺的PhotoShop功底不咋地,你会发现那两个圆粑粑不是透明背景,而是白色背景的,没关系,只要我们使用精确的CSS定位,看不出破绽的,^_^

 

最终我们希望实现的效果如下图所示。

image

其中圆粑粑中的数字表示软件的第几个版本,是不是看着比原来的好多了。

 

下面我们就动手实现,纯手工哦,用到的开发工具只有Notepad++(My favorite!)。

 

最简单的HTML结构

HTML结构一定要保持简单,其实就是一个列表嘛,那就用 UL 标签实现。

   1:  <ul class="timeline">
   2:      <li>
   3:          <div class="time">时间</div>
   4:          <div class="version">版本号</div>
   5:          <div class="number">第几个版本</div>
   6:          <div class="content">
   7:              <pre>
   8:                  更新记录
   9:              </pre>
  10:          </div>
  11:      </li>
  12:  <ul>

 

初步的设想是content左边留白,time/version/number全部浮动起来,这样方便定位。

特别是number的定位要准确,否则圆粑粑和背景垂直线就重合不到一起了。这就要看CSS的了。

 

最简单的CSS

我们主要来看看如何对number的定位,完整的代码在文章最后会给出。

   1:  ul.timeline {
   2:      list-style-type: none;
   3:      background: url("../res/img/version_line.png") repeat-y scroll 120px 0 transparent;
   4:      margin: 50px 0;
   5:      padding: 0;
   6:  }
   7:  ul.timeline li {
   8:      position: relative;
   9:      margin-bottom: 20px;
  10:  }
  11:  
  12:  ul.timeline li .number {
  13:      position: absolute;
  14:      background: url("../res/img/version_dot.png") no-repeat scroll 0 0 transparent;
  15:      width: 56px;
  16:      height: 56px;
  17:      left: 97px;
  18:      line-height: 56px;
  19:      text-align: center;
  20:      color: #fff;
  21:      font-size: 18px;
  22:  }

 

首先,将垂直蓝色的背景线放在最外层的 UL 标签上,距离左侧 120px;

其次,设置 LI 为相对定位,为 LI 中元素的绝对定位做铺垫;

最后,将number浮动起来,主要是number的left属性一定要精确!

 

如何计算 number 的 left 属性那,大家看看如下的公式是否合你口味:

number.left = line.left + line.width/2 – number.width/2

= 120 + 10/2 – 56/2

=  97

 

最简单的JQuery

剩下就是JQuery的任务了,我们需要使用jQuery完成如下两点任务:

1. 动态计算 number 的数字;

2. 为间隔行的 LI 节点添加 alt 类。

   1:  $(function() {
   2:  
   3:      var liNodes = $('ul.timeline li'), count = liNodes.length, i, liNode;
   4:      for(i=0; i<count; i++) {
   5:          liNode = $(liNodes.get(i));
   6:          if(i % 2 !== 0) {
   7:              liNode.addClass('alt');
   8:          }
   9:          liNode.find('.number').text(count - i);
  10:      }
  11:  
  12:  });

 

 

最简单的数据迁移(正则表达式替换)

还有一项重要的任务,如何把 100 多条数据迁移到新的 HTML 结构中去,没人愿意手工去做,没关系我们有好帮手 Notepad++。

image

查找目标:\+(\d{4}-\d{2}-\d{2})\s+(v\d+.*)$

替换为:</pre></div></li>\r\n<li><div class=”time”>$1</div><div class=”version”>$2</div><div class=”number”></div><div class=”content”><pre>

 

查找目标用来匹配类似“+2013-07-29 v3.3.1”的字符串,一次搞定,是不是很舒服。

 

完成效果

image

列表实在是太长,这里只是 5% 不到的截图!

 

优化!将页面大小由150K减少为20K

本来文章就此结束了,可是吃完饭我就不满意了,还有改进的余地!

1. 一次展示 100 多个记录,用户也看不完,反而影响显示效果,长长长长长长长长长的滚动条;

2. 用户关心的可能只是最近的几次更新记录,如果需要看更多的,提供一种方法即可!

 

基于以上考虑,我们可以将 100 多个记录分成 20 个记录一个文本文件保存起来,需要的时候通过 AJAX 获取就行了。

页面首次加载只需要前 10 条左右的记录即可,在列表的最后添加一个大大的按钮,如下图所示。

image

 

最终的目录结构如下所示。

image

 

来体验一下最终的效果吧:

http://fineui.com/version

 

 

全部源代码

   1:  <style>
   2:      ul.timeline {
   3:          list-style-type: none;
   4:          background: url("../res/img/version_line.png") repeat-y scroll 120px 0 transparent;
   5:          margin: 50px 0;
   6:          padding: 0;
   7:      }
   8:  
   9:      ul.timeline li {
  10:          position: relative;
  11:          margin-bottom: 20px;
  12:      }
  13:      ul.timeline li .time {
  14:          position: absolute;
  15:          width: 90px;
  16:          text-align: right;
  17:          left: 0;
  18:          top: 10px;
  19:          color: #999;
  20:      }
  21:      ul.timeline li .version {
  22:          position: absolute;
  23:          width: 290px;
  24:          text-align: right;
  25:          left: -200px;
  26:          top: 30px;
  27:          font-size: 40px;
  28:          line-height: 50px;
  29:          color: #3594cb;
  30:          overflow: hidden;
  31:      }
  32:      ul.timeline li .number {
  33:          position: absolute;
  34:          background: url("../res/img/version_dot.png") no-repeat scroll 0 0 transparent;
  35:          width: 56px;
  36:          height: 56px;
  37:          left: 97px;
  38:          line-height: 56px;
  39:          text-align: center;
  40:          color: #fff;
  41:          font-size: 18px;
  42:      }
  43:      ul.timeline li.alt .number {
  44:          background-image: url("../res/img/version_dot_alt.png");
  45:      }
  46:      ul.timeline li .content {
  47:          margin-left: 180px;
  48:  
  49:      }
  50:      ul.timeline li .content pre {
  51:          background-color: #3594cb;
  52:          padding: 20px;
  53:          color: #fff;
  54:          font-size: 13px;
  55:          line-height: 20px;
  56:      }
  57:      ul.timeline li.alt .content pre {
  58:          background-color: #43B1F1;
  59:      }
  60:  </style>
  61:  <ul class="timeline">
  62:      <li>
  63:          <div class="time">2013-07-29</div>
  64:          <div class="version">v3.3.1</div>
  65:          <div class="number"></div>
  66:          <div class="content">
  67:              <pre>
  68:              -将工具YUICompressor替换为Microsoft Ajax Minifier(需要指定-evals:immediate)。
  69:              ...
  70:              </pre>
  71:          </div>
  72:      </li>
  73:      ...
  74:  </ul>
  75:  <script>
  76:      $(function() {
  77:  
  78:          var nextDataNumber = 5;
  79:  
  80:          var ulNode = $('ul.timeline');
  81:  
  82:          function initLiNodes() {
  83:              var liNodes = ulNode.find('li'), count = liNodes.length, i, liNode, leftCount = nextDataNumber * 20;
  84:              for(i=0; i<count; i++) {
  85:                  liNode = $(liNodes.get(i));
  86:                  if(i % 2 !== 0) {
  87:                      liNode.addClass('alt');
  88:                  } else {
  89:                      liNode.removeClass('alt');
  90:                  }
  91:                  liNode.find('.number').text(leftCount + count - i);
  92:              }
  93:          }
  94:  
  95:  
  96:          $('#fetchNextData').click(function() {
  97:              var $this = $(this);
  98:              $this.addClass('disabled').text('......');
  99:  
 100:              $.get('./version_data_' + nextDataNumber +'.txt', function(data) {
 101:                  ulNode.append(data);
 102:                  $this.removeClass('disabled').text('后二十条数据');
 103:                  nextDataNumber--;
 104:  
 105:                  if(nextDataNumber === 0) {
 106:                      $this.hide();
 107:                  }
 108:  
 109:                  initLiNodes();
 110:              });
 111:  
 112:          });
 113:  
 114:          initLiNodes();
 115:  
 116:      });
 117:  </script>

 

小结

如何向用户有效的展示 100 多条更新记录,是个技术活。需要我们认真思考,学以致用,用最简单的HTML、CSS、jQuery来实现最好的用户体验。

[转载]创业干货分享:初创公司移动应用开发工具库(集合) | 36氪

mikel阅读(865)

[转载]创业干货分享:初创公司移动应用开发工具库(集合) | 36氪.

编者按:本文来自@wuswoo投稿,wuswoo拥有两年移动开发经验,现在在人人猎头担任技术总监。根据自己两年多的开发经验,wuswoo为创业者们整理并推荐了包括产品、设计、项目管理、开发、以及部署和运帷在内的,几乎所有应用开发需要的第三方的工具和解决方案,方便大家快速的集成和使用。

更多创业服务介绍,欢迎点击查看36氪+“创业服务”专辑

Android开源项目推荐

对于 Android 工程师而言,了解当前的开源项目很必要,前一段时间网上很火的 Github 上开源项目,这里就不多说了。

最火的开源项目(一): http://www.csdn.net/article/2013-05-03/2815127-Android-open-source-projects

最火的开源项目(二): http://www.csdn.net/article/2013-05-08/2815145-Android-open-source-projects-two

最火的开源项目(三): http://www.csdn.net/article/2013-05-21/2815370-Android-open-source-projects-finale

iOS开源项目推荐

iOS 每次的改变,会引起开源项目的变化,开发者可以直接那来用在自己项目开发中。

最火的开源项目(一): http://www.csdn.net/article/2013-06-05/2815530-GitHub-iOS-open-source-projects-one

最火的开源项目(二): http://www.csdn.net/article/2013-06-18/2815806-GitHub-iOS-open-source-projects-two

最火的开源项目(三): http://my.eoe.cn/sisuer/archive/5682.html

ui4app.comhttp://ui4app.com/

UI 设计师 / 美工:你可以在 UI4App 按照分类来查看众多优秀的 App 的优秀设计,从而找到你个人的设计灵感和素材; iOS 开发者:苦逼一个人在战斗的时候,没有美工,没有设计师。来逛逛 UI4App,也能熏陶熏陶一下自己的美感吧。
2.code4app.com code4app 是一个移动平台的共享代码库,收集了 iOS 平台共享代码,并且配有效果图和演示视频,避免苦逼的程序员重复造轮子。

Ucloudhttp://www.ucloud.cn

建议初创公司使用云平台来托管整个业务,可以降低 IT 支出成本,同时进入门槛低,可以根据业务的发展弹性调整基础 IT 资源。 Ucloud 相对于其他云平台,Ucloud 本身是一家创业正在成长型公司,Uhost 和 Udb 基本上能满足初创公司各种 IT 需求,同时跟阿里云相比价格便宜 1/4 到 1/3。使用 Ucloud 后,对方服务态度好以及能够快速地解决各种问题。

个推http://www.igetui.com/

在开发 Android 应用,经常需要推送功能, 但是 Android 没有像 Apple Apns 官方的推送服务, Google 的推送服务在响应速度以及稳定性有一定的问题。推荐使用国内第三方推送服务供应商个推, 个推的优势是推送及时和稳定,有 Android SDK 和后台推送 API。个推的计费是按照一个月中一天最高同时在线人数计算,1 万同时在线以下是免费。按照个推所说,最高同时在线数平均统计是所有留存用户的 20% 左右。比如 50 万 Android 下载量,留存率 30%。

50 万*30%= 15 万 *20%(同时在线)=3 万-1 万(免费)=2 万
2 万*0.2(每个用户每月费用) = 4000 元/月

实际中每个用户每月费用可以有优惠折扣。但是在实际开发的应用中,发现同时在线用户是留存用户的 50% 左右。

Blasamiq Mockups(http://balsamiq.com/

Blasamiq Mockups 是我最喜欢的移动应用原型设计软件。能让你以最快的速度把原型画出来,用它画出来的是手绘风格的界面,很酷。同时内置了很多常用的控件和图标,基本够用了。

Popapphttp://popapp.in/

Popapp 可以让你快速地让手绘的 AppUI 跃然纸上,协助开发者快速地将原本纸上的 App 界面草图(比如 Blasamiq Mockups 导出的草图)在 iphone 做模拟。

Axurehttp://www.axure.com/

Axure 已经成为产品经理、产品设计师以及交互设计师的必备工具,便于建立低保真的模型,以及便于于整个开发团队的沟通。

CC视频http://www.bokecc.com/

CC 视频愿景是让所有网站和应用轻松使用视频,提供基于云平台,集发布,转码,存储,播放,统计等功能。为移动应用者开发提供 ios,android 的 SDK,(基于可以自定义小窗口视频录制),浏览器 Flash 播放器,以及服务端的 API 接口和视频审核。典型应用是唱吧录制 MV 功能。

又拍云https://www.upyun.com/

开发基于大量图片的移动应用,不妨采用又拍云图片云平台。又拍云存储分布全国 CDN 加速网络,以及丰富的 HTTP RESTful API 和采用图片无损压缩技术,自动生成 30 种自定义缩略图尺寸,按照用户实际使用量计费,以及支持弹性扩容。

Sendcloudhttp://sendcloud.sohu.com/

Sendcloud 是搜狐旗下的为企业提供邮件群发以及邮件营销服务平台。Sendcloud 专注邮件发送,邮件发送追踪,同时保证邮件高效到达,不易作为垃圾邮件处理,让公司专注业务的开发,同时提供实时的数据分析功能。价格每月发送量少于 2 万封,59 元 / 月,超过在 2-3 元/千封邮件,相对比较便宜。

Xmindhttp://www.xmind.net

Xmind 是最好用的一款思维导图的软件,对于移动应用开发者,可以用于 App 的初步构想设计、整体功能分布、以及不同版本功能展示等。同时 Xmind 可以用于设计鱼骨图,二维图,逻辑图,组织结构图等。

JQuery/Bootstrap(http://twitter.github.io/bootstrap/index.htm

有很多的 JavaScript 架构可以选择, 建议用 JQuery 和 Bootstrap。Bootstrap 是基于 JQuery 的,它非常方便用于网站和管理后台以及微信公共账号开发。 Bootstrap 包含一套 css 和 JavaScript,包括各种组件和效果,
以及支持各种版本的通用浏览器以及通过响应式 CSS(Responsive CSS)支持平板和手机。

Trellohttps://trello.com/

Trello 是一款免费的,面向轻量级团队敏捷开发最好的平台了。Trello 上的工作都围绕 Board 进行,同一小组的用户可以在这里创建 To Do List,并分配给同事,同事完成后可以包任务标记为完成。

Githttp://git-scm.com

Git 是开源的分布式版本控制系统,可以有效、高速的处理从小到大的各种项目管理。对于轻量级的团队而言,一个 Master 和 Development 分支和平时版本发布打上 TAG 就能满足需求了,其他优点这里就不累赘了。

Redminehttp://www.redmine.org

Redmine 是一个开源基于 Web 的项目管理和 Bug 跟踪工具,在实际开发中,用的最多的就是 Wiki 和 Bug 跟踪。

Godaddyhttp://www.godaddy.com

如果不是注册 CN 域名,建议把域名注册在 Godaddy 上,只需要一张信用卡就可以注册。价格相对国内便宜一些,同时可以自动续费,以及便捷地域名交易,直接可以过户到另外一个 Godaddy 账号。

DnsPodhttp://www.dnspod.cn

DnsPod 是国内提供免费智能 DNS 解析服务,DnsPod 界面简洁易用,以及提供高质量的电信、网通、教育网双线或者三线智能解析。你可以把在 Godaday 上注册的域名用 DnsPod 解析。

TalkingDatahttp://www.talkingdata.net

TalkingData 专注移动互联网综合数据服务创业公司。TalkingData Analytics 是针对移动应用的数据统计分析平台,可以实时监测用户的变化,包括用户新增、活跃、留存、转化、流失来监测用户生命周期的变化,同时提供分析工具来帮助解 析更深入的问题。转化漏斗允许你分析用户一连串使用行为的转化率。

ShareSDKhttp://www.sharesdk.cn

ShareSDK 是目前移动应用中最简单易用,功能最强大社会化分享工具。支持新浪微博,腾讯微博 SSO 认证,开发者只需要 10 分钟就可以轻松集成到自己移动应用中。它不仅支持 QQ,新浪微博,腾讯微博,微信,Facebook 等国内外主流社交网站。还有强大的后台统计功能,可以实时了解用户、回流率、传播效应等数据。

二维码扫瞄

随着二维码应用越来越广,这里推荐 iphone 和 android 的二维码识别第三方 SDK

Zbar: http://zbar.sourceforge.net/

ZXing: http://code.google.com/zxing/

监控宝http://www.jiankongbao.com/

如果你寻求第三方监控,监控宝是一个不错的选择。可以监控 CPU,Memory,Network 等使用情况,以及其他服务比如:mySQL ,redis, memorycache, mongdb 等,以及高级自定义监控,和实时自定义邮件和短信警报通知等。对于初创公司标准版 59 元 / 月完全可以满足要求了。

Face++ 人脸识别http://cn.faceplusplus.com/

Face++ 是人脸识别的计算云平台,包括人脸检测,人脸识别,人脸分析等功能,以及提供 Android,IOS,Rubby, JAVA,C# 等 SDK 下载,如果开发基于人脸识别相关应用 Face++ 是很好的选择。

应用名称

移动应用的应用名称在 Apple Store 要求是唯一,今年六月份开始 Apple Store 应用可以是随时从不同苹果开发者账号转移,可以轻松地交易 Apple Store 中应用,应用名称将成为稀缺资源。建议在开发应用之前就在 Apple Store 中注册应用,一来可以看看是否有人注册同样应用名称,二来可以防止他人抢注你的应用名称。同时提醒初创团队,应用发布一定要牢牢掌握在自己的手中,不来将 来有纠纷,就很麻烦,可能为他人作嫁衣。

推荐阅读

最于初创团队而言一定要多读一些书,这里推荐几本给大家:《精益创业》、《别独自用餐》、《至关重要设计》、《大数据时代》、《平台战略》。

[转载].NET框架设计—常被忽视的C#设计技巧 - 王清培 - 博客园

mikel阅读(911)

[转载].NET框架设计—常被忽视的C#设计技巧 – 王清培 – 博客园.

阅读目录:

  • 1.开篇介绍
  • 2.尽量使用Lambda匿名函数调用代替反射调用(走进声明式设计)
  • 3.被忽视的特性(Attribute)设计方式
  • 4.扩展方法让你的对象如虎添翼(要学会使用扩展方法的设计思想)
  • 5.别怕Static属性(很多人都怕Static在Service模式下的设计,其实要学会使用线程本地存储(ThreadStatic))
  • 6.泛型的协变与逆变(设计架构接口(Interface)时要时刻注意对象的协变、逆变)
  • 7.使用泛型的类型推断(还在为参数类型烦恼吗)
  • 8.链式编程(设计符合大脑思维习惯的处理流程)
    • 8.1.链式编程(多条件(方法碎片化)调用
  • 9.部分类、部分方法的使用(扩大设计范围)

1.】开篇介绍

本文中的内容都是我无意中发现觉得有必要分享一下的设计经验,没有什么高深的 技术,只是平时我们可能会忽视的一些设计技巧;为什么有这种想法是因为之前跟一些同事交流技术的时候会发现很多设计思维被固化了,比如之前我在做客户端框 架开发的时候会去设计一些关于Validator、DTO Transfer等常用的Common function,但是发现在讨论某一些技术实现的时候会被弄的云里雾里的,会自我郁闷半天,不会及时的明白对方在说的问题;

后来发现他们一是没有把概念分清楚,比如.NETFrameworkC#VisualStudio, 这三者之间的关系;二是没有理解.NET中各个对象的本质含义,比如这里的特性(Attribute),大部分人都认为它是被用来作为代码说明、标识使用 的,而没有突破这个思维限制,所以在设计一些东西的时候会绕很多弯路;还有一点是很多人对C#中的语法特性分不清版本,当然我们要大概的了解一下哪些特性 或者语法是C#2的哪些是C#3的,这样在我们设计东西的时候不会由于项目的版本问题而导致你无法使用设计技巧,比如扩展方法就无法使用在低 于.NET3.0版本中,LINQ也无法在低于.NET3.O的版本中使用;

.NETFramework的版本不断的在升级,目前差不多5.0都 快面世了;.NETFramework的升级跟C#的升级没有必然的关系,这个要搞清楚;C#是为了更好的与.NET平台交互,它提供给我们的都是语法 糖,最后都是.NETCTS中的类型;就比如大家都在写着LINQ,其实到最后LINQ也就被自动解析成对方法的直接调用;

2.】尽量使用委托调用代替反射调用

委托相信大家都玩的很熟,委托的发展到目前为止是相当不错的,从原本很繁琐的每次使用委托的时候都需要定义一个相应的方法用来实例化委托,这点在后来的C#2中得到了改进,支持匿名委托delegate{…}的 方式使用,再到现在的C#3那就更方便了,直接使用面向函数式的Lambda表达式;那么这样还需要反射调用对象的方法吗?(当然特殊场合我们这里不考 虑,只考虑常用的场景;)当然反射不是不好,只是反射需要考虑很多性能优化方面的东西,增加了代码的复杂性,也让框架变的很重(现在都是在追求轻量级,只 有在DomainModel中需要将平面化的数据抽象;),所以何不使用简单方便的委托调用呢;

注:如果你是初学者,这里的委托可以理解成是我们平时常用的Lambda表达式,也可以将它与Expression<T>结合起来使用,Expression<T>是委托在运行时的数据结构,而非代码执行路径;(兴趣的朋友可以查看本人的:LINQ系列文章

下面我们来看一下演示代码:

复制代码
 1 /*==============================================================================
 2  * Author:深度训练
 3  * Create time: 2013-07-28
 4  * Blog Address:http://www.cnblogs.com/wangiqngpei557/
 5  * Author Description:特定领域软件工程实践;
 6  *==============================================================================*/
 7 using System;
 8 using System.Collections.Generic;
 9 using System.Linq.Expressions;
10 using System.Linq;
11 using Infrastructure.Common.Cache;
12 using Infrastructure.Common.Validator;
13 
14 namespace ConsoleApplication1.DomainModel
15 {
16     /// <summary>
17     /// Order.
18     /// </summary>
19     [EntityCache(10, true)]
20     [EntityValidator(ValidatorOperationType.All)]
21     public class Order
22     {
23         /// <summary>
24         /// Order code.
25         /// </summary>
26         public string OrderCode { get; set; }
27 
28         /// <summary>
29         /// Items filed.
30         /// </summary>
31         private List<Item> items = new List<Item>();
32         /// <summary>
33         /// Gets items .
34         /// </summary>
35         public IEnumerable<Item> Items { get { return items; } }
36 
37         /// <summary>
38         /// Submit order date.
39         /// </summary>
40         public DateTime SubmitDate { get; set; }
41 
42         /// <summary>
43         /// Mark <see cref="DomainModel.Order"/> Instance.
44         /// </summary>
45         /// <param name="orderCode">Order code. </param>
46         public Order(string orderCode)
47         {
48             this.OrderCode = orderCode;
49         }
50 
51         /// <summary>
52         /// Sum items prices.
53         /// </summary>
54         /// <param name="itemUsingType">item type.</param>
55         /// <returns>prices .</returns>
56         public double SumPrices(int itemUsingType)
57         {
58             double resultPrices = 0.00;
59             var currentItems = items.GroupBy(item => item.ItemUsingType).Single(group => group.Key == itemUsingType);
60             if (currentItems.Count() > 0)
61             {
62                 foreach (var item in currentItems)
63                 {
64                     resultPrices += item.Price;
65                 }
66             }
67             return resultPrices;
68         }
69 
70         /// <summary>
71         /// Add item to order.
72         /// </summary>
73         /// <param name="item">Item.</param>
74         /// <returns>bool.</returns>
75         public bool AddItem(Item item)
76         {
77             if (!item.ItemCode.Equals(string.Empty))
78             {
79                 this.items.Add(item);
80                 return true;
81             }
82             return false;
83         }
84     }
85 }
复制代码

这是一个订单领域实体,它里面引用了一个Item的商品类型;

复制代码
 1 /*==============================================================================
 2  * Author:深度训练
 3  * Create time: 2013-07-28
 4  * Blog Address:http://www.cnblogs.com/wangiqngpei557/
 5  * Author Description:特定领域软件工程实践;
 6  *==============================================================================*/
 7 using System;
 8 
 9 namespace ConsoleApplication1.DomainModel
10 {
11     /// <summary>
12     /// Order item.
13     /// </summary>
14     public class Item
15     {
16         /// <summary>
17         /// Item code.
18         /// </summary>
19         public Guid ItemCode { get; set; }
20 
21         /// <summary>
22         /// Item price.
23         /// </summary>
24         public float Price { get; set; }
25 
26         /// <summary>
27         /// Item using type.
28         /// </summary>
29         public int ItemUsingType { get; set; }
30     }
31 }
复制代码

上面代码应该没有问题,基本的订单领域模型大家都太熟了;为了保证上面的代码是绝对的正确,以免程序错误造成阅读者的不爽,所以都会有100%的单元测试覆盖率;这里我们主要使用的是Order类中的SumPrices方法,所以它的UnitTest是100%覆盖;

图1:

Order中的SumPrices方法的UnitTest代码:

复制代码
 1 using System;
 2 using Microsoft.VisualStudio.TestTools.UnitTesting;
 3 using NSubstitute;
 4 
 5 namespace ConsoleApplication.UnitTest
 6 {
 7     using ConsoleApplication1.DomainModel;
 8 
 9     /// <summary>
10     /// Order unit test.
11     /// </summary>
12     [TestClass]
13     public class DomainModelOrderUnitTest
14     {
15         /// <summary>
16         /// Order sumprices using type 1 test.
17         /// </summary>
18         [TestMethod]
19         public void DomainModelOrderUnitTest_SumPrices_ItemUsingTypeIs1_UnitTest()
20         {
21             Order testOrder = new Order(Guid.NewGuid().ToString());
22 
23             testOrder.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 1, Price = 10.0F });
24             testOrder.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 1, Price = 15.0F });
25 
26             testOrder.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 2, Price = 20.0F });
27             testOrder.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 2, Price = 30.0F });
28 
29             double result = testOrder.SumPrices(1);
30 
31             Assert.AreEqual(result, 25.0F);
32         }
33 
34         /// <summary>
35         /// Order sumprices using type is 2 test.
36         /// </summary>
37         [TestMethod]
38         public void DomainModelOrderUnitTest_SumPrices_ItemUsingTypeIs2_UnitTest()
39         {
40             Order testOrder = new Order(Guid.NewGuid().ToString());
41 
42             testOrder.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 1, Price = 10.0F });
43             testOrder.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 1, Price = 15.0F });
44 
45             testOrder.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 2, Price = 20.0F });
46             testOrder.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 2, Price = 30.0F });
47 
48             double result = testOrder.SumPrices(2);
49 
50             Assert.AreEqual(result, 50.0F);
51         }
52     }
53 }
复制代码

在以往我基本上不写单元测试的,但是最近工作上基本上都需要写每个方法的单元测试,而且要求是100%覆盖,只有这样才能保证代码的正确性;也建议大家以后多写单元测试,确实很有好处,我们应该把单元测试做起来;下面我们言归正传;

由于我们的Order是在DomainModel Layer中,现在有一个需求就是在Infrastructure Layer 加入一个动态计算Order中指定Item.ItemUsingType的所有Prices的功能,其实也就是说需要将我们的一些关键数据通过这个功能发 送给远程的Service之类的;这个功能是属于Infrastructure中的Common部分也就是说它是完全独立与项目的,在任何地方都可以通过 它将DomainModel中的某些领域数据发送出去,那么这样的需求也算是合情合理,这里我是为了演示所以只在Order中加了一个SumPrices 的方法,可能还会存在其他一些DomainModel对象,然后这些对象都有一些关键的业务数据需要在通过Infrastructure的时候将它们发送 出去,比如发送给配送部门的Service Interface;

那么常规设计可能需要将扩展点配置出来放在指定的配置文件里面,然后当对象经 过Infrastructure Layer中的指定Component时触发事件路由,然后从缓存中读取出配置的信息执行,那么配置文件可能大概是这样的一个结 构:DomainEntity名称、触发动作、方法名称、参数,DomainEntity名称是确定聚合根,触发动作是对应Infrastructure 中的组件,当然你也可以放在DomainModel中;这里只关心方法名称、参数;

当然这里只演示跟方法调用相关的代码,其他的不在代码中考虑;我们来看一下相关代码:

复制代码
1 using System;
2 namespace Infrastructure.Common
3 {
4     public interface IBusinessService
5     {
6         void SendBusinessData(object callAuthor, string methodName, object parameterInstance);
7         void SendBusinessData<P>(Func<P, object> callFun, P parameter);
8     }
9 }
复制代码

这是业务调用接口;

复制代码
 1 using System;
 2 using System.Reflection;
 3 using System.Linq;
 4 using System.Linq.Expressions;
 5 
 6 namespace Infrastructure.Common
 7 {
 8     /// <summary>
 9     /// Business service .
10     /// </summary>
11     public class BusinessService : IBusinessService
12     {
13         /// <summary>
14         /// Send service data interface .
15         /// </summary>
16         private ISendServiceData sendService;
17 
18         /// <summary>
19         /// Mark <see cref="Infrastructure.Common.ISendServiceData"/> instance.
20         /// </summary>
21         /// <param name="sendService"></param>
22         public BusinessService(ISendServiceData sendService)
23         {
24             this.sendService = sendService;
25         }
26 
27         /// <summary>
28         /// Send business data to service interface.
29         /// </summary>
30         /// <param name="callAuthor">Object author.</param>
31         /// <param name="methodName">Method name.</param>
32         /// <param name="parameterInstance">Method call parameter.</param>
33         public void SendBusinessData(object callAuthor, string methodName, object parameterInstance)
34         {
35             object result =
36                 callAuthor.GetType().GetMethod(methodName).Invoke(callAuthor, new object[] { parameterInstance });
37             if (result != null)
38             {
39                 sendService.Send(result);
40             }
41         }
42 
43         /// <summary>
44         /// Send business data to service interface.
45         /// </summary>
46         /// <typeparam name="P"></typeparam>
47         /// <param name="callFun"></param>
48         /// <param name="parameter"></param>
49         public void SendBusinessData<P>(Func<P, object> callFun, P parameter)
50         {
51             object result = callFun(parameter);
52             if (result != null)
53             {
54                 sendService.Send(result);
55             }
56         }
57     }
58 }
复制代码

这里简单实现IBusinessService接口,其实代码很简单,第一个方法使用反射的方式调用代码,而第二个方法则使用委托调用;在实现类里面还包含了一个简单的接口;

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Infrastructure.Common
 8 {
 9     public interface ISendServiceData
10     {
11         void Send(object sendObject);
12     }
13 }
复制代码

目的是为了方便单元测试,我们来看一下单元测试代码;

复制代码
 1 using System;
 2 using Microsoft.VisualStudio.TestTools.UnitTesting;
 3 using Infrastructure.Common;
 4 using ConsoleApplication1.DomainModel;
 5 using NSubstitute;
 6 
 7 namespace Infrastructure.Common.UnitTest
 8 {
 9     [TestClass]
10     public class InfrastructureCommonBusinsessServiceUnitTest
11     {
12         [TestMethod]
13         public void InfrastructureCommonBusinsessServiceUnitTest_BusinessService_SendBusinessData()
14         {
15             Order order = new Order(Guid.NewGuid().ToString());
16 
17             order.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 1, Price = 10.0F });
18             order.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 1, Price = 15.0F });
19 
20             order.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 2, Price = 20.0F });
21             order.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 2, Price = 30.0F });
22 
23             ISendServiceData mockISendServiceData = Substitute.For<ISendServiceData>();
24             object sendresult = null;
25             mockISendServiceData.When(isend => isend.Send(Arg.Any<object>())).Do(callinfo => sendresult = callinfo.Arg<object>());
26 
27             BusinessService testService = new BusinessService(mockISendServiceData);
28             testService.SendBusinessData(order, "SumPrices", 1);
29 
30             Assert.AreEqual((double)sendresult, 25);
31         }
32 
33         [TestMethod]
34         public void InfrastructureCommonBusinsessServiceUnitTest_BusinessService_SendBusinessDataGen()
35         {
36             Order order = new Order(Guid.NewGuid().ToString());
37 
38             order.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 1, Price = 10.0F });
39             order.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 1, Price = 15.0F });
40 
41             order.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 2, Price = 20.0F });
42             order.AddItem(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 2, Price = 30.0F });
43 
44             ISendServiceData mockISendServiceData = Substitute.For<ISendServiceData>();
45             object sendresult = null;
46             mockISendServiceData.When(isend => isend.Send(Arg.Any<object>())).Do(callinfo => sendresult = callinfo.Arg<object>());
47 
48             BusinessService testService = new BusinessService(mockISendServiceData);
49             testService.SendBusinessData<Order>(ord => { return ord.SumPrices(1); }, order);
50 
51             Assert.AreEqual((double)sendresult, 25);
52         }
53     }
54 }
复制代码

在第二个单元测试方法里面我们将使用Lambda方式将逻辑直接注入进BusinessService中,好就好这里;可以将Lambda封进 Expression<T>然后直接存储在Cache中或者配置中间,彻底告别反射调用吧,就好比委托一样没有人会在使用委托在定义个没用的 方法;(所以函数式编程越来越讨人喜欢了,可以关注一下F#;)总之使用泛型解决类型不确定问题,使用Lambda解决代码逻辑注入;大胆的尝试吧,将声 明与实现彻底分离;

(对.NET单元测试有兴趣的朋友后面一篇文章会详细的讲解一下如何做单元测试,包括Mock框架的使用;)

3】被忽视的特性(Attribute)设计方式

大部分人对特性的定义是代码的“数据注释”,就是可以在运行时读取这个特性用来做类型的附加属性用的;通常在一些框架中对DomainModel中的Entity进行逻辑上的关联用的,比如我们比较熟悉的ORM,都会在Entity的上面加上一个类似 [Table(TableName=”Order”)] 这样的特性声明,然后再在自己的框架中通过反射的方式去在运行时差找元数据找到这个特性,然后就可以对附加了这个特性的类型进行相关的处理;

这其实没有问题,很正常的设计思路,也是比较通用的设计方法;但是我们的思维被前人固化了,难道特性就只能作为代码的声明吗?问过自己这个问题吗?

我们继续使用上面2】小结中的代码作为本节演示代码,现在我们假设需要在DomainModel中的Entity上面加上两个特性第一个用来断定它是否需要做Cache,第二个用来确定关于Entity操作验证的特性;

看代码:

复制代码
1 /// <summary>
2     /// Order.
3     /// </summary>
4     [EntityCache(10, true)]
5     [EntityValidator(ValidatorOperationType.All)]
6     public class Order
7     {}
复制代码

代码应该很明了,第一EntityCache用来设计实体的缓存,参数是缓存的过期时间;第二个特性EntityValidator用来设置当实体进行相关处理的时候需要的验证类型,这里选择是所有操作;

现在的问题是关于特性的优先级,对于Order类的处理到底是先Cache然后验证,还是先验证然后Cache或者说内部没有进行任何的逻辑处理;如 果我们将特性的视为代码的标识而不是真正的逻辑,那么对于优先级的处理会比较棘手,你需要设计如何将不同的特性处理逻辑关联起来;比较合理的设计方法是特 性的处理链表;本人之前设计过AOP的简单框架,就遇到过对于特性的优先级的处理经验,也是用的链表的方式将所有的特性按照顺序串联起来然后将对象穿过特 性内部逻辑,这也符合DDD的中心思想;

下面我们来看代码:

复制代码
 1 Codeusing System;
 2 
 3 namespace Infrastructure.Common
 4 {
 5     [AttributeUsage(AttributeTargets.Class)]
 6     public abstract class EntityOperation : Attribute
 7     {
 8         protected EntityOperation NextOperation { get; set; }
 9     }
10 }
复制代码

我们抽象出所有的处理,然后在内部包含下一个处理逻辑的特性实例;然后让各自的Attribute继承自它;

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Infrastructure.Common.Cache
 8 {
 9     [AttributeUsage(AttributeTargets.Class)]
10     public class EntityCache : EntityOperation
11     {
12         public EntityCache(int cacheTime, bool IsEnable)
13         {
14             this.ExpireTime = cacheTime;
15         }
16 
17         public int ExpireTime { get; set; }
18 
19     }
20 }
复制代码

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Infrastructure.Common.Validator
 8 {
 9     public enum ValidatorOperationType
10     {
11         Insert,
12         Delete,
13         Update,
14         Select,
15         All
16     }
17 
18     [AttributeUsage(AttributeTargets.Class)]
19     public class EntityValidator : EntityOperation
20     {
21         public EntityValidator(ValidatorOperationType validatorType)
22         {
23 
24         }
25     }
26 }
复制代码

根据特性在类的先后顺序就可以控制他们的优先级;

图2:

上图很直观的表现了链表设计思想,再通过仔细的加工应该会很不错的;

4】扩展方法让你的对象如虎添翼(要学会使用扩展方法的设计思想)

扩展方法我们用的应该不算少的了,在一些新的框架中到处都能看见扩展方法的优势,比如:ASP.NETMVC、EntityFramework等等特别是开源的框架用的很多;

那么我们是不是还停留在原始社会,应该尝试接受新的设计思想,尽管一开始可能不太适应,但是当你适应了之后会让你的设计思想提升一个境界;

下面我们还是使用上面的演示代码来进行本节的代码演示,现在假如有一个这样的 需求,为了保证DomainModel的完全干净,我们在应用层需要对领域模型加入一些非业务性的行为,这些行为跟DomainModel本身没有直接关 系,换句话说我们这里的Order聚合实体可能需要一个获取Order在Cache中存活了多长时间的方法;那么在以往我们可能提供一个方法然后把 Order实例作为参数这样来使用,但是这里我们的需求是该方法是Order对象的方法而不是其他地方的方法;

所以这里使用扩展方法就可以在不改变对象本身业务逻辑的情况下扩展对象行为; 最关键的是扩展方法为后面的链式编程提供了基石;从长远来看DomainModel将会被独立到ThreadProcess总,当系统初始化时部分的 DomainModel将直接主流在内存中,然后通过系统本地化将扩展方法加入,这样就可以在不改变对象的情况下添加行为,这也为行为驱动设计提供了好的技术实现;

用纯技术性的假设没有说服力,上面说给领域本身加上获取Cache的方法,肯定会有朋友说这完全没有必要,提供一个简单的方法就OK了,恩 我觉得也有道理,那么下面的需求你将不得不说妙;

【需求简述】:对象本身的行为不是固定不变的,尤其我们现在设计对象 的时候会将对象在全局情况下的所有行为都定义在对象内部,比如我们正常人,在不同的角色中才具有不同的行为,我们只有在公司才具有“打开服务器”的行为, 只有在家里才可以“亲吻”自己的老婆的行为;难道我们在设计User类的时候都将这些定义在对象内部吗?显然不符合逻辑,更不符合面向对象设计思想,当然 我们目前基本上都是这么做的;

(有兴趣的朋友可以参考:BDD(行为驱动设计)、DCI(数据、上下文、交互)设计思想;)

现在我们来为Order添加一组行为,但是这组 行为只有在某些场景下才能使用,这里只是为了演示而用,真要在项目中设计还需要考虑很多其他因素;

复制代码
 1 namespace DomainModelBehavior.Order.ShippingBehavior
 2 {
 3     using ConsoleApplication1.DomainModel;
 4     public static class OrderBehavior
 5     {
 6         public static Order TaxRate(this Order order)
 7         {
 8             return order;
 9         }
10     }
11 }
12 
13 namespace DomainModelBehavior.Order.ShoppingCart
14 {
15     using ConsoleApplication1.DomainModel;
16     public static class OrderBehavior
17     {
18         public static Order Inventory(this Order order)
19         {
20             return order;
21         }
22     }
23 }
复制代码

这里有两个位于不同namespace中的行为,他们对应不同的场景;第一个 TaxRate用来计算税率的行为,只有在Order对象已经处于提交状态时用的;那么第二个行为Inventory用来计算库存的,用户在 Shoppingcart的时候用来确定是否有足够的库存;当然这里我只是假设;

然后我们就可以在不同的场景下进行命名空间的引用,比如我们现在Shoppingcart阶段将不会使用到TaxRate行为;

复制代码
 1 using System;
 2 
 3 namespace ConsoleApplication1
 4 {
 5     using DomainModelBehavior.Order.ShoppingCart;
 6     class Program
 7     {
 8         static void Main(string[] args)
 9         {
10             DomainModel.Order order = new DomainModel.Order(Guid.NewGuid().ToString());
11             order.Inventory();
12         }
13     }
14 }
复制代码

例子虽然有点简单,但是应该能说明扩展方法的基本使用方式,对于DCI架构的实现会复杂很多,需要好好设计才行;

5】别怕Static属性(很多人都怕Static在Service模式下的设计,其实要学会使用线程本地存储(ThreadStatic))

很多时候我们在设计对象的时候,尤其是面向Context类型的,很希望能通 过某个静态属性直接能拿到Context,所以会定义一个静态属性用来保存对象的某个实例;但是会有很多人都会排斥静态属性,动不动就说性能问题,动不动 就收多线程不安全等等借口,难道静态属性就没有存在必要了嘛;

不用静态属性你哪来的ASP.NET中的CurrentContext直接, 如果怕因为多线程问题导致数据不完整,建议使用线程本地存储;没有什么好怕的,多用就熟悉了;用也很简单,直接在静态属性上面加上这个特性就OK了,前提 是你已经考虑了这个属性是线程内部共享的不是应用程序级别的共享;

1 /// <summary>
2         /// 数据源的操作
3         /// </summary>
4         [ThreadStatic]
5         private static IDataSourceOperation datasourceoperation = IDataSourceOperationFactory.Create();

6】泛型的协变与逆变(设计架构接口(Interface)时要注意对象的协变、逆变)

越来越多的人喜欢自己捣鼓点东西出来用用,这很不错,时间长了设计能力自然会得到提升的;但是最近发现我们很多泛型在设计上缺乏转换的控制,也就是这里的协变和逆变;我们有一个Item类型,现在我们需要对它进行更加具体化,我们派生出一个Apple类型的Item;

1 List<Apple> apples = new List<Apple>();
2  List<Item> items = apples;

这段代码是编译不通过的,因为List<T> 在定义的时候就不支持逆变、但是如果换成下面这样的代码是完全可以的;

1 List<Apple> apples = new List<Apple>();
2  IEnumerable<Item> items = apples;

很容易的就可以得到集合的转换,虽然很简单的功能但是在设计上如果运用好的话 能大大改变接口的灵活性;你可能会有一个疑问,为什么具体实现List<T>不支持协变而IEnumerable<out T>反而支持协变;这就是面向对象设计的思想,接口本质是抽象的,抽象的不会有具体的实现所以它作为协变不会存在问题,但是逆变就会有问题;

7】使用泛型的类型推断(还在为参数类型烦恼吗)

在设计泛型方法的时候要学会使用类型推断技巧,这样会很方便的在调用的时候减 少你显示调用<>的代码,也会显得很优美;大家应该都比较熟悉Func泛型委托,它是C#3中的主角,也是函数式编程的基础,我们在设计某个 方法的时候会将逻辑暴露在外部,然后通过Lambda的方式注入进来;现在的LINQ都是这么实现的,比较熟悉的Where方法、Select方法,都需 要我们提供一个作为它内部逻辑的函数段;

复制代码
1 List<Item> items = new List<Item>();
2             items.Add(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 1, Price = 20 });
3             items.Add(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 1, Price = 20 });
4             items.Add(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 1, Price = 20 });
5             items.Add(new Item() { ItemCode = Guid.NewGuid(), ItemUsingType = 1, Price = 20 });
6 
7             items.Where<Item>(item => item.ItemUsingType == 1);
8             items.Where(item=>item.ItemUsingType==1);
复制代码

这里有两种调用Where的代码,哪一种看上去舒服一点有没一点,不用我说了;那我们看一下它的定义:

1 public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);

我们看到TSource类型占位符,很容易理解,这是一个扩展IEnumerable<TSource>类型的方法,系统会自动的匹配TSource;我们在设计的时候也要借鉴这种好的设计思想;

(有兴趣的朋友可以参见本人的:.NET深入解析LINQ框架(一:LINQ优雅的前奏)

8】链式编程(设计符合大脑思维习惯的处理流程)

其实那么多的C#新特性都是为了能让我们编写代码能更方便,总之一句话是为了更符合大脑思维习惯的编程模式;

C#从纯面向对象渐渐的加入了函数式模式,从静态类型逐渐加人动态类型特性;C#现在变成多范式编程语言,其实已经很大程度满足我们的日常需求;以往我们都会为了动态行为编写复杂的Emit代码,用很多CodeDom的技术;现在可以使用Dymanic解决了;

这节我们来看一下关于如何设计线性的链式方法,这不是技术问题,这是对需求的理解能力;可以将链式思想用在很多地方,只要有逻辑有流程的地方都可以进行相关设计,首先你要保证你是一个正常思考问题的人,别设计出来的方法是反的,那么用的人会很不爽的;这里我举一个我最近遇到的问题;

8.1】链式编程(多条件(方法碎片化)调用

我们都熟悉DTO对象,它是从UI传过来的数据集合,简单的业务逻辑 Application Layer将它转换成DomainModel中的Entity,如果复杂的业务逻辑是不能直接将DTO进行转换的;但是在转换过程中我们总是少不了对它的 属性判断,如果UserName不为空并且Password不为空我才能去验证它的合法性,等等;类似这样的判断;这里我们将运行扩展方法将这些逻辑判断 链起来,并且最后输出一个完整的Entity对象;

复制代码
 1 using System.Collections.Generic;
 2 
 3 namespace ConsoleApplication1
 4 {
 5     public static class DtoValidator
 6     {
 7         public static IEnumerable<TSource> IsNull<TSource>(this IEnumerable<TSource> tList)
 8         {
 9             return tList;
10         }
11         public static IEnumerable<TSource> IsLength<TSource>(this IEnumerable<TSource> tList, int max)
12         {
13             return tList;
14         }
15         public static IEnumerable<TResult> End<TResult>(this IEnumerable<object> tList, IEnumerable<TResult> result)
16         {
17             result = new List<TResult>();
18             return result;
19         }
20     }
21 }
复制代码

有一组扩展方法,用来做验证用的;

1 List<Order> orderList = null;
2 
3 List<Dto.OrderInfoDto> dtoList = new List<Dto.OrderInfoDto>();
4 
5 dtoList.IsNull().IsLength(3).End(orderList);

由于时间关系我这里只是演示一下,完全可以做的很好的,在判断的最后拿到返回的列表引用最后把数据送出来;

(有一个开源验证框架应该还不错,目前工作中在用:FluentValidator)

9】部分类、部分方法的使用(扩大设计范围)

部分类不是新的特性,而部分方法是新特性;我们通过灵活运用部分类可以将发挥很大作用,比如我们完全可以将类的部分实现完全隔离在外部,起到低耦合的作用,甚至可以将声明式设计元编程运用在C#中,比较经典就是ASP.NET后台代码和前台的模板代码,在运行时然后再通过动态编译合起来,我们不要忘记可以使用部分类、部分方法来达到在运行时链接编译时代码和运行时代码,类似动态调用的效果;由于这部分内容比较简单,是设计思想的东西,所以没有什么要演示的,只是一个总结;

 

总结:内容虽然简单,但是要想运用的好不简单,这里我只是总结一下,希望对大家有用,谢谢;

示例DEMO地址http://files.cnblogs.com/wangiqngpei557/ConsoleApplication1.zip

[转载]C#版二维码生成器附皮肤下载 - 狼性法则 - 博客园

mikel阅读(830)

[转载]C#版二维码生成器附皮肤下载 – 狼性法则 – 博客园.

前言

本文所使用的二维码生成代码是谷歌开源的条形码图像处理库完成的,C#版的代码可去https://code.google.com/p/zxing/downloads/list下载压缩包。

截止目前为止最新版本为2.2,提供以下编码格式的支持:

  • UPC-A and UPC-E
  • EAN-8 and EAN-13
  • Code 39
  • Code 93
  • Code 128
  • QR Code
  • ITF
  • Codabar
  • RSS-14 (all variants)
  • Data Matrix
  • PDF 417 (‘alpha’ quality)
  • Aztec (‘alpha’ quality)

同时官网提供了 Android、cpp、C#、iPhone、j2me、j2se、jruby、objc、rim、symbian等多种应用的类库,具体详情可以参考下载的源码包中。

本文已经下载好了,C#版的zxing代码,并编译生成了类库,供程序直接调用。

软件截图及说明

功能说明:1、根据文字输入及时生成二维码,支持保存,打印

2、支持解码,打开二维码文件解码

3、采用IrisSkin4皮肤美化

代码说明

复制代码
 1 public MainForm()
 2         {
 3             InitializeComponent();
 4             this.skinEngine1.SkinFile = Application.StartupPath + "//skins//SportsGreen.ssk";
 5             this.p1.Visible = true;
 6             //this.p2.Visible = false;
 7 
 8             //用于实现PictureBox的鼠标移动过去的提示
 9             ToolTip toolTip = new ToolTip();
10             toolTip.AutoPopDelay = 5000;//一下4个都是属性
11             toolTip.InitialDelay = 1000;
12             toolTip.ReshowDelay = 500;
13             toolTip.ShowAlways = true;
14             toolTip.SetToolTip(this.open, "打开");//参数1是button名,参数2是要显示的内容
15             toolTip.SetToolTip(this.save, "保存");
16             toolTip.SetToolTip(this.print,"打印二维码");
17             toolTip.SetToolTip(this.decod,"解码");
18             toolTip.SetToolTip(this.exit,"返回生成二维码");
19         }
复制代码

主窗体显示,皮肤,按钮图表鼠标移动显示提示等代码。

复制代码
 1 //随文本框输入内容生成二维码图片
 2         private void txtContent_TextChanged(object sender, EventArgs e)
 3         {
 4             string content = txtContent.Text;
 5             if (content == "")
 6             {
 7                 MessageBox.Show("请输入内容", "警告", MessageBoxButtons.OK, MessageBoxIcon.Error);
 8                 return;
 9             }
10             ByteMatrix byteMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, 200, 200);
11             Bitmap bitmap = toBitmap(byteMatrix);
12             orpic.Image = bitmap;
13             
14         }
15         //生成图片代码
16         public static Bitmap toBitmap(ByteMatrix matrix)
17         {
18             int width = matrix.Width;
19             int height = matrix.Height;
20             Bitmap bmap = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
21             for (int x = 0; x < width; x++)
22             {
23                 for (int y = 0; y < height; y++)
24                 {
25                     bmap.SetPixel(x, y, matrix.get_Renamed(x, y) != -1 ? ColorTranslator.FromHtml("0xFF000000") : ColorTranslator.FromHtml("0xFFFFFFFF"));
26                 }
27             }
28             return bmap;
29         }
30         //时间显示代码
31         private void timer_Tick(object sender, EventArgs e)
32         {
33             this.timeshowlable.Text = DateTime.Now.ToString();
34         }
复制代码

随文本框输入内容生成二维码图片及时间显示代码。

复制代码
 1 private void exit_MouseMove(object sender, MouseEventArgs e)
 2         {
 3             System.Drawing.Bitmap map = new Bitmap(Application.StartupPath+@"\image\exit-1.png");
 4             this.exit.Image = map;
 5         }
 6 
 7         private void exit_MouseLeave(object sender, EventArgs e)
 8         {
 9             System.Drawing.Bitmap map = new Bitmap(Application.StartupPath + @"\image\exit.png");
10             this.exit.Image = map;
11         }
12 
13         private void print_MouseMove(object sender, MouseEventArgs e)
14         {
15             System.Drawing.Bitmap map = new Bitmap(Application.StartupPath + @"\image\print-1.png");
16             this.print.Image = map;
17         }
18 
19         private void print_MouseLeave(object sender, EventArgs e)
20         {
21             System.Drawing.Bitmap map = new Bitmap(Application.StartupPath + @"\image\print.png");
22             this.print.Image = map;
23         }
24 
25         private void open_MouseLeave(object sender, EventArgs e)
26         {
27             System.Drawing.Bitmap map = new Bitmap(Application.StartupPath + @"\image\open.png");
28             this.open.Image = map;
29         }
30 
31         private void open_MouseMove(object sender, MouseEventArgs e)
32         {
33             System.Drawing.Bitmap map = new Bitmap(Application.StartupPath + @"\image\open-1.png");
34             this.open.Image = map;
35         }
36 
37         private void save_MouseLeave(object sender, EventArgs e)
38         {
39             System.Drawing.Bitmap map = new Bitmap(Application.StartupPath + @"\image\save.png");
40             this.save.Image = map;
41         }
42 
43         private void save_MouseMove(object sender, MouseEventArgs e)
44         {
45             System.Drawing.Bitmap map = new Bitmap(Application.StartupPath + @"\image\save-1.png");
46             this.save.Image = map;
47         }
48 
49         private void decod_MouseMove(object sender, MouseEventArgs e)
50         {
51             System.Drawing.Bitmap map = new Bitmap(Application.StartupPath + @"\image\encoding-1.png");
52             this.decod.Image = map;
53         }
54 
55         private void decod_MouseLeave(object sender, EventArgs e)
56         {
57             System.Drawing.Bitmap map = new Bitmap(Application.StartupPath + @"\image\encoding.png");
58             this.decod.Image = map;
59         }
复制代码

鼠标移动到按钮图片,图片切换代码。

复制代码
  1 private void open_Click(object sender, EventArgs e)
  2         {
  3             if (p1.Visible == true)
  4             {
  5                 if (this.openFileDialog1.ShowDialog() != DialogResult.OK)
  6                 {
  7                     return;
  8                 }
  9                 string path = this.openFileDialog1.FileName;
 10                 openFileDialog1.DefaultExt = "*.txt";
 11                 openFileDialog1.Filter = "*.txt|";
 12                 if (path.EndsWith(".txt"))
 13                 {
 14                     string content = File.ReadAllText(path, Encoding.Default);
 15                     this.txtContent.Text = content;
 16                 }
 17                 else
 18                 {
 19                     MessageBox.Show("只能读取txt文件","提示",MessageBoxButtons.OK,MessageBoxIcon.Error);
 20                 }
 21             }
 22             else
 23             {
 24                 if (this.openFileDialog1.ShowDialog() != DialogResult.OK)
 25                 {
 26                     return;
 27                 }
 28                 string path = this.openFileDialog1.FileName;
 29                 if (!path.EndsWith(".png"))
 30                 {
 31                     MessageBox.Show("图像格式不正确,只能读取png文件", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
 32                 }
 33                 else
 34                 {
 35                     Image img = Image.FromFile(path);
 36                     Bitmap bmap;
 37                     try
 38                     {
 39                         bmap = new Bitmap(img);
 40                     }
 41                     catch (System.IO.IOException ioe)
 42                     {
 43                         MessageBox.Show(ioe.ToString());
 44                         return;
 45                     }
 46                     if (bmap == null)
 47                     {
 48                         MessageBox.Show("Could not decode image");
 49                         return;
 50                     }
 51                     else
 52                     {
 53                         this.picOpenQr.Image = bmap;
 54                     }
 55                     LuminanceSource source = new RGBLuminanceSource(bmap, bmap.Width, bmap.Height);
 56                     com.google.zxing.BinaryBitmap bitmap = new com.google.zxing.BinaryBitmap(new com.google.zxing.common.HybridBinarizer(source));
 57                     Result result;
 58                     try
 59                     {
 60                         result = new MultiFormatReader().decode(bitmap);
 61                     }
 62                     catch (ReaderException re)
 63                     {
 64                         MessageBox.Show(re.ToString());
 65                         return;
 66                     }
 67 
 68                     this.txtDencoder.Text = (result.Text);
 69                 }
 70             }
 71         }
 72 
 73         private void save_Click(object sender, EventArgs e)
 74         {
 75             if (p1.Visible == true)
 76             {
 77                 saveFileDialog1.Filter = "*.png|";
 78                 //saveFileDialog1.DefaultExt = "*.png";
 79                 saveFileDialog1.RestoreDirectory = true;
 80                 if (this.saveFileDialog1.ShowDialog() == DialogResult.OK)
 81                 {
 82                     string localPath = saveFileDialog1.FileName.ToString();
 83                     Image qrcode = orpic.Image;
 84                     if (qrcode == null)
 85                     {
 86                         MessageBox.Show("无保存项", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
 87                     }
 88                     else
 89                     {
 90                         if (localPath.EndsWith(".png"))
 91                         {
 92                             qrcode.Save(localPath);
 93                         }
 94                         else
 95                         {
 96                             qrcode.Save(localPath + ".png");
 97                         }
 98 
 99                     }
100                 }
101             }
102             else
103             {
104                 saveFileDialog1.Filter = "*.txt|";
105                 //saveFileDialog1.DefaultExt = "*.txt";
106                 if(this.saveFileDialog1.ShowDialog()==DialogResult.OK)
107                 {
108                     string localPath = saveFileDialog1.FileName.ToString()+".txt";
109                     if (File.Exists(localPath))
110                     {
111                         DialogResult RESULT = MessageBox.Show("是否确认覆盖原有文件?", "信息提示", MessageBoxButtons.YesNo);
112                         if (RESULT.ToString().Equals("Yes"))
113                         {
114                             File.Delete(localPath);
115                             File.AppendAllText(localPath, this.txtDencoder.Text, Encoding.Default);
116                         }
117                         else
118                         {
119                             return;
120                         }
121                     }
122                     else
123                     {
124                         File.AppendAllText(localPath, this.txtDencoder.Text, Encoding.Default);
125                     }
126                 }
127             }
128         }
129 
130         private void exit_Click(object sender, EventArgs e)
131         {
132             this.p2.Visible = false;
133             this.p1.Visible=true;
134         }
135 
136         private void decod_Click(object sender, EventArgs e)
137         {
138             this.p2.Visible=true;
139             this.p1.Visible = !(p1.Visible);
140         }
复制代码

打开,保存,面板切换代码。

复制代码
 1 private void print_Click(object sender, EventArgs e)
 2         {
 3             PrintDialog printDialog = new PrintDialog();
 4             printDialog.Document = printDocument;
 5             if (printDialog.ShowDialog() == DialogResult.OK) { try
 6                 {
 7                     printDocument.Print();
 8                 }
 9                 catch
10                 {   //停止打印
11                     printDocument.PrintController.OnEndPrint(printDocument, new System.Drawing.Printing.PrintEventArgs());
12                 }
13             }
14         }
15 
16         private void printDocument_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
17         {
18             if (this.p1.Visible == true)
19             {
20                 e.Graphics.DrawImage(this.orpic.Image, 20, 20);
21             }
22             else
23             {
24                 e.Graphics.DrawImage(this.picOpenQr.Image, 20, 20);
25             }
26         }
复制代码

打印代码。

关键代码在txtContent_TextChanged()及打开方法中处理了。

最后说明:程序比较简单,不做过多说明,时间仓促代码存在很多不合理的地方,欢迎拍砖。

附件下载(带皮肤):点我去下载

[转载]说说jsonp - 轩脉刃 - 博客园

mikel阅读(936)

转载说说jsonp – 轩脉刃 – 博客园.

什么是jsonp

jsonp充其量只能说是一种“方法”。它可以让页面从其他域中获取资料。

 

首先要知道的是同源策略,在JavaScript中使用http请求(ajax)是会受到同源策略的限制的。A网站的页面是不能在JavaScript中访问B网站的资源的。但是,对于这种希望A网站访问B网站的资源的需求怎么办呢?(跨域访问)。jsonp就出现了。

 

html 中虽然说javascript是不能跨域的,但是有许多标签,比如<img>,<iframe>,<script> 这些有src属性的标签是不受同源策略的影响的。于是jsonp就把脑筋动到script标签上了。一般script都是静态的,但是script能否是 动态的呢?

 

比如我在script的src中的url带上用户id,这样来访问一个跨域的请求,请求返回这个用户的 个人信息,我再使用这个个人信息来渲染我的页面。这样不就可以完成了一个跨域请求了。但是呢?script中返回的必须是javascript,所以呢, 一般就约定,src中的url除了要带动态请求所需要的信息以外,还需要带一个回调信息(一般是一个回调函数),让请求返回的数据是一个可执行的 javascript的完整语句。

 

比如:

1
2
3
4
5
6
7
8
9
function handle_data(data) {
   // `data` is now the object representation of the JSON data
}
---
http://some.tld/web/service?callback=handle_data:
---
handle_data({"data_1": "hello world", "data_2": ["the","sun","is","shining"]});

再问个经常问到的问题,jsonp和ajax,json有什么关系呢?

首先jsonp和ajax完全是两个概念,可以说jsonp出现的理由就是弥补ajax无法跨域访问的缺陷而出现的。所以这两个概念没啥关系。至于有些框架,比如JQuery喜欢把ajax和jsonp放在一起,完全是由于他们的调用和使用方式很相像而已。

 

jsonp返回的数据并不是json,而是javascrip,比如上例中的handle_date中返回的数据一定要是json么?从来没人这么说过。再次吐槽下,特别是前端的这些概念的名词确实起的很容易让人迷糊。

jsonp有什么优点呢?

第一个优点当然是能跨域了。一个访问不再受限于域名了,这个代表什么呢?代表我可以提供一个公共的webservice了,这个服务可以给你服务,也可以给他服务,你们不需要一定是在我的域名下的。

 

其次的优点是将回调方法的权限给了调用方。这个就相当于将controller层和view层终于分开了。我提供的jsonp服务只提供纯服务的数 据,至于提供服务以后的页面渲染和后续view操作都由调用者来自己定义就好了。如果有两个页面需要渲染同一份数据,你们只需要有不同的渲染逻辑就可以 了,逻辑都可以使用同一个jsonp服务。

 

还有一个优点是它甚至不需要浏览器能支持XMLHTTPRequest,就是说所有的浏览器都可以使用这个技术。

json有什么缺点呢?

首先的缺点是安全性。万一假如提供jsonp的服务存在页面注入漏洞,即它返回的javascript的内容被人控制的。那么结果是什么?所有调用 这个jsonp的网站都会存在漏洞。于是无法把危险控制在一个域名下…所以在使用jsonp的时候必须要保证使用的jsonp服务必须是安全可信的。

 

其次是错误处理,jsonp在调用失败的时候不会返回各种HTTP状态码。只有200,没有404,没有500等状态码让你来标识是否要重新调用。

 

它只能支持GET,而不能支持POST请求,所以它的参数一定是带在HTTP头中的,会受到一些参数的限制,比如长度限制。

参考文章

http://blog.csdn.net/liaomin416100569/article/details/5480825

http://jingyan.baidu.com/article/eb9f7b6dbd3ff0869364e81c.html

http://www.json-p.org/

http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html

[转载]深入理解Kinect for Windows开发 - yangecnu - 博客园

mikel阅读(960)

[转载]深入理解Kinect for Windows开发 – yangecnu – 博客园.

这个周末看了两天的微软Build 2012大会,真的是一次盛会,上面有很多的演讲主题,都是微软相关技术和产品的最新动态,我比较关注.NET、WPF、Office及Kinect相关开发,上面的演讲视频和PPT都可以下载,个人觉得比较精彩的有The Evolution of .NET ,回顾了微软推出.NET以来的历次开发者大会推出的新版本和新特性,里面还有10多年前比尔盖子老师在开发者大会上宣布.NET战略时的演讲视频,不觉得感叹岁月是把杀猪刀啊。 What’s New for Developers in Office 2013 and SharePoint 2013 介绍了不同于以往的以VBA,SharedAddIn,以及VSTO的全新的Office开发方式OfficeApp,Building apps for Office and SharePoint 2013 using the web technologies you know and love, Part 1Part2介绍了如何使用各种我们熟悉的技术如Html、JavaScriptC#等来构建OfficeApp。上面还有很多关于Windows Phone 8,WPF4.5等相关的介绍,主题很多,强烈建议大家有空可以上去看看。

大会上关于Kinect开发有三个,第一个是微软研究院讲的Super-Natural Interaction这 个PPT比演讲视频都大,达到了罕见的997M,为啥这么大呢,因为里面嵌入了一个长达40分钟视频,哈哈,这个演讲主要演示了微软研究院正在进行的各种 人机交互,虚拟现实等研究,非常的Cutting-edge,里面也有和Kinect相关的部分,有兴趣的可以看看。第二个是Kinect Design Considerations,一则关于Kinect应用程序设计是应该考虑的问题比如交互方式的设计的演讲,我没有太仔细看,不过内容应该和Kinect Human Interface Guideline内容差不多,您可以在Kinect Developer Toolkit中查看。第三篇演讲是 Kinect for Windows Programming Deep Dive  我将这个翻译为了深入理解Kinect for Windows开发,相对来说该演讲和Kinect开发比较相关,现与大家分享,该演讲上面写的级别为 300-advanced,个人觉得这个演讲内容其实很简单,只是对Kinect能够获取的相关数据源,Kinect SDK处理过了的可供识别的数据源,以及未来的趋势和大家做了一下介绍。Kinect SDK中其实没有太多的东西,真正的则在于各种模式识别算法,比如通过深度数据,红外数据,进行各种物体识别等等,有了这些数据,尤其是1.6版本的 SDK提供的获取红外原始数据,就可以通过这个数据,结合深度数据做出很多非常令人惊叹的应用来。废话不多说了,下面和大家分享一下该演讲的主要内容,也 算是一个关于Kinect开发的比较好的入门介绍吧。

一 大纲

Slide2

演讲大体分为5个部分,第一部分介绍了Kinect SDK的开发方式以及运行环境,第二部分是写代码,讲解Kinect中的一些彩色,深度,骨骼等数据的处理和显示,第三部分讲解了传感器直接产生的数据 流,包括彩色,深度,红外,语音,加速器数据源,第四部分讲解了经过Kinect SDK对原始数据流处理后的可供用来进行直接识别的,骨骼,语音及面部识别数据源,最后一部分讲解了未来Kinect可进行的一系列应用。现在先来看第一 部分吧。

二 Kinect应用场景及开发环境

首先介绍了一下Kinect的应用场景。主要有三大类方面的应用。第一是自然人机交互界面。比如说一些像少数派报告中的那种用手指非接触即可操纵大屏幕上 的显示内容。这在一些高科技或者科幻类电影中经常能够看到这类的场景。还有一些就是在国外已经有的应用如Kinect虚拟试衣间,Kinect车展演示广 告,Kinect 手术室影像操作,还有Kinect操作幻灯片Kinect进行照片浏览 等等,这些自然人机交互界面的应用带来了新的用户体验。第二种是自然环境识别,比如根据Kinect 产生的深度数据,红外数据对物体进行三维扫描重建,利用Kinect进行机器人导航进行障碍物自动回避等。第三种是自然用户的识别,比如说利用 Kinect来进行姿势识别,人脸识别。比如说一些大家比较熟悉的XBOX360 中的 舞林大会运动会大冒险等体感游戏,这些都是利用Kinect的一些数据来进行用户的动作识别,从而参与到游戏中的互动。还有一些增强现实的应用,利用了上面的三个方面的特性,比如说利用Kinect来将荧幕变成触摸屏,并在上面可以进行各种操作,等等应用。

Slide3

 

要开发上面的应用,首先要了解一下开发环境,如这张幻灯片所示:

Slide4

Kinect 提供了非托管(C++)和托管(.NET)两种开发方式的SDK,如果您用C++开发的话,需要安装Speech Runtime(V11),Kinect for Windows Runtime和驱动的,如果您使用C#和VB.NET的话,需要Microsoft.Kinect.dll和Mirosoft.Speech.dll两 个dll,这两个其实是对前C++里面的两个dll的.NET封装,不论何种开发,您都需要安装driver,所有这些都包含在Kinect SDK安装包中,安装方法您可以参考之前的文章。 Kinect开发支持Windows7/Windows Embedded Standard/Windows8操作系统,最新的1.6版本的SDK还支持虚拟机里面的Windows系统,不过只要年代不太久远的Windows系 统应该都是可以的。上面写的最好使用.NET 4.0/4.5也只是建议,老版本的应该也行。如果是使用.NET开发方式的话,您需要安装.NET Framework,IDE可以使用Visual Studio 2010/2012。

三 代码演示

这部分主要是通过编写代码演示Kinect的各项功能,代码我在这里就不讲了。

首先第一个演示是显示彩色影像,比较简单。然后是结合深度影像数据显示彩色影像数据上对应某一点的深度值。

demo1

图上使用鼠标点击就能够加上一个标签,标签里面的值是该点的深度值,这个功能应该是比较好实现的,主要是展示如何使用彩色影像数据和深度数据,您如果感兴趣的话看完这篇文章应该就能实现这个功能。

然后演示了骨骼追踪功能,图中追踪了头部,双手的位置,并显示了两只手所处的深度值,头部上显示的Tracking ID,Kinect能同时追踪6个待选目标,但只有两个目标处于活动状态。每一次追踪都会分配给目标一个Tracking ID。

demo2

这个功能主要演示了如何使用骨骼数据,您如果感兴趣的话看完这篇文章应该就能实现这个功能。

除了1.5及之前能够提供的各种数据之外,1.6 的SDK提供了红外影像数据,您可以利用数据校准彩色影像数据,使得在较暗的条件下也能够进行人物识别。其实Kinect骨骼识别主要是通过深度数据来实 现的,而深度数据是通过红外发射接收产生的,1.6版本的SDK提供了我们直接访问和操作红外数据的能力。

demo7

第四个Demo是演示了Kinect的面部识别功能,Kinect的面部识别是在1.5 SDK中引入的,面部识别可以识别最多达一百多个面部特征点,下面是演示的Demo:

demo3

上面的功能在Kinect Developer Toolkit中有实例和源代码,您可以下载查看,入门的话,您也可以看这篇文章,比较简单的对使用FaceTracking的一点介绍。

Kinect除了这些功能之外还有强大的语音识别功能,在这篇演讲中没有演示出来,不过在Super-Natural Interaction这篇演讲的视频中,您可以体会该改功能的强大,Kinect语音识别不仅能够识别出声音,而且还能对声音的来源方向进行识别,且具有强大的去噪增强功能,要了解这些你可以看这篇文章,对Kinect的语音识别做了一些简单的介绍。

四 Kinect数据源及应用

Kinect开发涉及到的数据源分为两类:

一类是传感器本身产生的原始数据源,比如说彩色影像数据源,深度影像数据源,语音数据源,红外影像数据源,加速计数据源,其中红外影像数据源,加速计数据源是在1.6的SDK中新加入的。下面这张图很好的说明了各个数据源:

Sensor Resource Image

第二类数据源是,SDK中通过一些算法识别出来的可以直接拿来进行识别的数据源,他们包括:骨骼追踪,语音识别,面部识别数据源。

Recognize source

可以看到,骨骼追踪数据源是在深度影像数据源的再通过一系列算法实现的,语音识别是通过语音数据源再通过一系列算法实现的,而面部识别则综合了彩色影像、深度影像和骨骼追踪为系列数据源的再通过一系列算法实现的。这些功能都是通过SDK来实现的。

有了这些数据源,就能够进行各种应用了:

application

典型的应用有绿屏抠像,这个功能在一些电视节目录制,比如天气预报节目中都是应用的这个实现的,他把任务从背景中分离出来,然后可以随意的更换背景,这个功能用到了影像数据和深度数据,你可以参考这篇文章,里面有一个简单的例子。第二个应用是产生点阵云,就是通过Kinect的深度影像数据产生每个点的位置信息然后生成三维模型。如下面这个例子:

demo4

图中左边是通过Kinect的深度影像数据产的三维建模图像。

第三个应用是魔镜功能,我觉得应该是一些类似哈哈镜效果或者是IOS中的Photo Booth应用,主要用到了彩色影像数据,面部识别,骨骼识别等功能。还有一些就是虚拟试衣间这样的功能,最后的一个应用场景就是各种NUI交互界面了。

五 展望

除了以上的几种典型的数据源之外,还展示了下一步的计划,比如说针对景深数据进行进一步处理的Kinect Fusion数据源。

next

下面是演示的例子:图中,右边桌子上摆放了一个茶壶,然后利用Kinect对该茶壶进行了三维建模,然后。移除右边实物茶壶后,用户可以对虚拟的茶壶进行 各种操作,神奇吧,这些都是下一个版本或者是将来的SDK能够方便我们或者简化我们实现这些功能准备添加的功能。

demo6

到最后展望了下一步要进行的工作:

Slide22

可以看出Kinect的愿景是使得计算机能够看到、听到、能够更加理解周围的人和环境。

Kinect SDK的版本发布是很快的,自从今年二月份发布了Kinect Sensor for Windows 体感仪及Kinect for Windows SDK 1.0官方版本以来;5月21日 发布了1.5版本SDK以及1.5的Developer Toolkit及调试工具Kinect Studio 1.5,不久又发布了Developer Toolkit 1.5.1及Developer Toolkit 1.5.2;10月9日发布了1.6版本的SDK和Developer ToolKit,同时宣布正式在大陆开售Kinect Sensor for Windows体感仪。每一个版本都增加了一些新的功能。相信下一个版本的SDK 也会有新的功能加入。

相信大家看了这个演讲之后应该可以感受到Kinect带来的变化,也相信以后Kinect开发能应用到日常生活中的例子会越来越多。

最后,希望大家有空到Channel9上看真人演讲哦,上面还有很多有意思主题演讲,所有演讲的PPT都可以在线看,视频都提供下载,当您不确定那个演讲 想不想看时,可以看看下面的在线屁屁踢哦,当然除了那种900多M的变态PPT之外其他的都可以在线浏览,这样您就可以迅速的了解演讲内容以及对该内容有 没有兴趣啦。

[转载]多页面打印--web print - small-joker - 博客园

mikel阅读(1038)

[转载]多页面打印–web print – small-joker – 博客园.

背景:项目中要求做在一个页面中通过选择网址来打印多个页面的内容的功能

原理:通过iframe把各网址的页面内容加载进来,通过iframe.contentWindow拿到iframe的window对象,把所有网 址页面内容整合至一个里面,再通过样式page-break-after实现分页打印。iframe通过监听load事件确定页面加载结束,在load中 再加载下一个页面,来确保加载的顺序进行。

输入:字符串或者数组

输出:弹出打印框,接着打印操作。

实现:使用构造函数保存实例自己的属性,通过原型保存方法。

属性:urls:传入的网址数组,len:页面加载剩余个数,printHTML:保存所有打印内容的字符串,mainIframe:最终用于打印的iframe对象

方 法:createIframe:生成iframe对象,addIframe:把iframe加入当前页面,deleteIframe:删除 iframe,getHTML:得到想要的html字符串内容,print:mainIframe打印操作,scan:递归加载iframe页面。

兼容:ie7-9,ff,chrome,opera,safari

代码:

复制代码
;
(function (win, doc) {
    var REG = /\<\!--\s*print\s+start\s*--\>(.|\n)*\<\!--\s*print\s+end\s*--\>/ig;

    //add into window
    win.iframeprint = function (urls) {
        new IframePrint(urls);
    }
    //function
    function IframePrint(urls) {
        this.urls = typeof urls === "string" ? [].push(urls) : (urls instanceof Array ? urls : []);
        this.len = this.urls.length;
        if (this.len <= 0) {
            //this = null;  //赋值左侧无效
            alert("传入参数必须为string或者array。");
            return;
        }
        this.printHTML = '';
        this.mainIframe = this.createIframe(this.urls[0]);

        this.init();
    }
    //prototype
    IframePrint.prototype = {
        constructor : IframePrint,
        createIframe : function (url) {
            var iframe = doc.createElement("iframe"),
            style = iframe.style; ;
            style.zIndex = -100;
            style.width = 0;
            style.height = 0;
            style.border = "none";
            style.background = "none";
            iframe.src = url;
            return iframe;
        },
        addIframe : function (iframe) {
            doc.getElementsByTagName("body")[0].appendChild(iframe);
        },
        deleteIframe : function (iframe) {
            iframe.parentNode.removeChild(iframe);
        },
        getHTML : function (iframe) {
            var html = iframe.contentWindow.document.getElementsByTagName("body")[0].innerHTML;
            return html.match(REG).join("");
        },
        print : function () {
            var ifmWin = this.mainIframe.contentWindow;
            ifmWin.document.getElementsByTagName("body")[0].innerHTML = this.printHTML;

            //log
            console.log(new Date());
            console.log(this.printHTML);

            ifmWin.focus();
            ifmWin.print();
        },
        scan : function () {
            var iframe = this.createIframe(this.urls[this.urls.length - this.len]),
            _this = this,
            _callee = arguments.callee;
            iframe.onload = function () {
                var _html = _this.getHTML(this);
                if (_this.len <= 1) {
                    _this.printHTML += _html;
                    _this.print();
                    _this.deleteIframe(_this.mainIframe);
                } else {
                    _this.len--;
                    _this.printHTML += _html + '<p style="page-break-after:always; border:none; background:none;margin:0;padding:0;"></p>';
                    _callee.call(_this);
                    //log
                    console.log(">1");
                }
                this.onload = null;
                _this.deleteIframe(this);
            };
            this.addIframe(iframe);
        },
        init : function () {
            this.addIframe(this.mainIframe);
            this.scan();
            //不使用此方法
            /* while (this.len > 0) {
                this.scanBody();
                this.len--;
            } */
        }
    };
})(window, document);
复制代码

缺点:这里加载的页面不能ajax动态数据,那样打印不出来相应的数据。

demo下载

[转载]Apache Lucene 4.4 和 Solr 4.4 发布_IT新闻_博客园

mikel阅读(1050)

[转载]Apache Lucene 4.4 和 Solr 4.4 发布_IT新闻_博客园.

Apache 软件基金会今天发布了 Apache Lucene 4.4 版本和 Solr 4.4 版本。

Apache Lucene 是一个基于 Java、高性能的全文检索引擎,4.4 版本包含了一些 bug 修复、优化和改进,主要如下:

  • 新的复制模块,用于复制服务器和客户端之间的索引修订
  • 新的基于 infix 的搜索建议器 AnalyzingInfixSuggester
  • 新的过滤器 PatternCaptureGroupTokenFilter,可发出多个令牌,1 个令牌针对 1 个 Java 正则表达式捕获组
  • 新的 Lucene Facet 模块功能
  • FST 生成器现在可以处理超过 21 亿的“尾节点”,同时可构建一个最小的 FST 节点
  • 更容易的压缩标准
  • 分析器现在有一个 tokenStream (String fieldName, String text)方法,因此不再需要使用 StringReader 来封装
  • 新的 SimpleMergedSegmentWarmer,确保数据结构可以被初始化
  • 修复了 4.3.1 版本中的各种 bug

详细信息:Apache Lucene 4.4 released

下载地址:http://lucene.apache.org/core/mirrors-core-latest-redir.html

Apache Solr 是基于 Lucene 的企业级搜索平台,Solr 4.4 在 Lucene 4.4 的基础上,针对企业级搜索增加了一些新功能,并进行了优化。现在 Solr 索引和事务日志还可以存储在分布式文件系统中,并完全拥有读写能力。

详细信息:Apache Solr 4.4 released

下载地址:http://lucene.apache.org/solr/mirrors-solr-latest-redir.html