2013年10月31日 星期四

[CSS]使用CSS3 pointer-events解決z-index造成控制項失效之問題(含舊瀏覽器解決方案)

今天幫朋友解決一個問題,有時網頁的設計就好像一幅畫一樣,可能用一個大區塊當背景,而這個背景上有很多的不同形狀的小區塊擺在上方,大區塊在html的語言可能就叫做<body>、或者是<div>,而小區塊可能就是不同的html標籤,如<section>、<h1>、<p>…等等,而有時因為視覺設計很複雜,會將這些小區塊變成圖層的概念,設計成有先後順序,這時候就可以用CSS的z-index屬性,來讓圖層有高低順序,而順序比較低的如果有一些控制項,去點擊後是不會觸發的(因為多了一層擋住),標題有點難下,以下這張圖可以說明:

layers-steps1
圖片來源

 

問題解決


我寫了一個簡單範例:JsFiddle
這個範例是點擊無效的程式,而要修正這個問題,其實只要在藍色的div加入CSS3的屬性pointer-events即可:
pointer-events比較廣泛應用到html5的SVG裡面,此篇暫不探討,對其他標籤來講,有效的只有auto、none這兩個值,如果不加這個屬性,效果跟auto一樣,所以加上none屬性之後,就可觸發較低層級的click事件。

舊瀏覽器解決方式


好吧,寫網頁常常就要跟IE瀏覽器相容性做抗爭,因為CSS3在舊的瀏覽器支援度較差(支援度查詢),所以我們常常要想另外一條路來完成。本例會使用JQuery來實做怎麼觸發這個click。完整程式碼如下:

html

<div id="control">
    <input type="submit" onclick="alert('ok');return false;" value="送出"/>
</div>

<div id="block">
    <div id="content">
        <h3>優先順序較高的圖層</h3>
    </div>
</div>



CSS


#control
{
    position:fixed;
}
#block {
    position:fixed;
    z-index:50;
    display:inline-block;
    opacity:.80;
    pointer-events:none; /* 解決無法觸發click事件 */
}

#content {
    margin:auto;
    width:300px;
    background-color:#7db0f4;
    border:1px solid #CCC;
    text-align:center;
}



解決相容性的Script


$(function() {
    $('#content').click(function(event) {
        //先將這個div內容隱藏
        $(this).hide();
        //取得目前座標
        var element = document.elementFromPoint(event.pageX, event.pageY); 
        //再將div內容顯示
        $(this).show();
        //判斷這個座標是否在Submit按鈕
        if ($(element).is('input[type="submit"]')) {
            //觸發click
            $(element).trigger('click');
        }
    });
});



--

Reference

http://www.qianduan.net/css3-pointer-event-description.html

http://css-tricks.com/pointer-events-current-nav/

http://jsfiddle.net/DC9MF/4/

http://www.w3school.com.cn/jquery/traversing_is.asp

2013年10月29日 星期二

[MS SQL]使用#Temp Table在if…else if 條件分支使用小筆記

前言


因為工作的關係,這幾個月來開始大量接觸複雜T-SQL,所以遇到有些問題都會筆記下來,順便做個分享(真懷念程式與DB權責分離的時候 T___T)

 

Temporary Tables


在SQL Server裡,創建方式又分為Create及Declare,前者儲存於DB的TempDB中,後者儲存於記憶體裡,當Session關閉連線時,暫存Table將會Drop掉。
暫存表的使用方式可以參考以下文章:

MS SQL 建立暫存表格 temp table
建立#TempTable與Declare @TempTable有何差別

 

條件分支遇到的問題


今天撰寫Temp Table遇到了if…else if遇到了執行錯誤的問題,我試著用簡單的邏輯來記錄下來。
這是一個很簡單的if…else if判斷,但在不同的分支下加入暫存表的寫法就會發生2714的錯誤

image

在into之前drop掉也無法:

image

後來找到微軟有官方的解答(機器翻譯),照他給的Sample Code進行些修改,將定義Table的抽出外層,不同的是,他的Temp欄位只有一個,而我的欄位有非常多所以不可能一個一個宣告,所以我先Select top 0 將欄位INTO到Temp Table,接著再依不同條件Inserty資料,改寫完的Code如下:
-- 如果Temp Table存在,則清除
IF object_id(N'tempdb.dbo.#TempTable') IS NOT NULL drop table TempTable

select TOP 0 * INTO #TempTable from DemoTable

if (1=1) 
    begin
        INSERT INTO #TempTable 
        select * from DemoTable where ColumnName = 'Filter1'
    end
else if (1=2)
    begin
        INSERT INTO #TempTable
        select *  from DemoTable where ColumnName = 'Filter2'
    end

SELECT * FROM #TempTable

--Do something ....

--

Reference

http://stackoverflow.com/questions/4155996/sql-insert-into-temp-table-in-both-if-and-else-blocks

http://social.msdn.microsoft.com/forums/sqlserver/en-US/42a377a6-8d2f-4666-bf86-f0d005cde51c/tsql-same-temp-table-in-if-else-block-error

http://deanma.blogspot.tw/2012/01/ms-sql-temp-table.html

2013年10月26日 星期六

[ASP.NET]C#列舉(Eunm)與switch應用小記錄

前言

以前寫程式的壞習慣,常常用單純的字串來做Switch,如下:

image 

其實這也沒什麼不對,但要避免字串不小心輸入錯導致維護困難,或者是程式碼的可讀性,應該改為使用列舉Enum,但今天在寫string轉成Enum switch突然鬼打牆忘記語法了,就來小記錄一下順便分享給不常用Enum的人。

先定義一個科目的Enum,裡面有三個option:

image

字串判斷很直覺的使用以下方式,會發現錯誤:

image

正確的使用方法應該為轉型,且Visuall Studio非常聰明會自動幫你列出所有的項目:

image

INT的判斷也可使用Enum :

image

--

Reference

http://stackoverflow.com/questions/15136134/c-sharp-how-to-use-enum-with-switch

http://stackoverflow.com/questions/1947645/net-c-sharp-switch-statement-string-compare-versus-enum-compare

http://www.dotblogs.com.tw/hatelove/archive/2011/08/02/refactoring-consolidate-duplicate-conditional-fragments.aspx

2013年10月23日 星期三

[ASP.NET]如何利用C#產生條碼圖片

前言

條碼的應用在生活上常常會遇到,其實對於程式來講,他讀出來就是一個字串,所以如果有購買掃描槍的話,等於是一個input裝置,可以把他想成是一個鍵盤,掃成功後等於是個複製貼上的動作,本篇將會Step by Step來實做C#產生條碼圖片。

 

安裝字型

要做成條碼其實很簡單,網路上有非常多的條碼免費字型可以下載,本篇字型使用的名稱為IDAutomationHC39M,從此連結下載,下載完後,應該會是個字型檔,直接點選安裝即可,這時候我們可以開個Word,會發現只要改變他的字型,就會變成條碼圖片。

b

 

開始實做

知道條碼其實是組字串後,程式也大概也有個方向可以朝向字串轉圖片的方式去實現。本篇將已WebForm的GridView來快速做個簡單的顯示:

Html頁面,需要注意的是,直接在Img指定寬度和高度並不會減小圖片的檔案大小,實際上在產生時要去做等比例縮放才是比較好的做法

<asp:GridView ID="gv_data" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="barcode" HeaderText="Barcode字串" />
<asp:TemplateField HeaderText="條碼圖片">
<ItemTemplate>
<img width="200" height="65" src='<%#Eval("Img") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>

 


後端在Page Load建立一個DataTable,創造5筆假資料

//產生五筆資料顯示
DataTable dt = new DataTable();
dt.Columns.Add("Barcode");
dt.Columns.Add("Img");

for (int i = 0; i < 5; i++)
{
DataRow dr = dt.NewRow();
dr["Barcode"] = "BC000000" + i;
dr["Img"] = GetBarCodeImage("BC000000" + i);//產生條碼圖片
dt.Rows.Add(dr);
}

gv_data.DataSource = dt;
gv_data.DataBind();

 


GetBarCodeImage function主要在對圖片做一些處理,因為本範例為求方便,最終顯示在HTML上是用Base64的方法實現,實際上可以依照需求去修改此塊。

public string GetBarCodeImage(string BarcodeStr)
{
//產生圖片檔案
string SavePath = @"D:\barcode.png";
//Barcode條碼需在前後加上*字號代表開始與結束
Bitmap barcode = CreateBarCode("*" + BarcodeStr + "*");
barcode.Save(SavePath, ImageFormat.Png);
barcode.Dispose();

//將圖片檔案轉成Base64字串
using (var fs = new FileStream(SavePath, FileMode.Open, FileAccess.Read))
{
var buffer = new byte[fs.Length];
fs.Read(buffer, 0, (int)fs.Length);
string base64String = Convert.ToBase64String(buffer);
string ImgBase64 = string.Format("data:image/png;base64,{0}'", base64String);
return ImgBase64;
}
}

 


將字串轉為圖片:

/// <summary>
/// 將字串轉為Barcode圖片
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public Bitmap CreateBarCode(string data)
{
Bitmap barcode = new Bitmap(1, 1);
Font threeOfNine = new Font("IDAutomationHC39M", 60,
System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point);

Graphics graphics = Graphics.FromImage(barcode);

SizeF dataSize = graphics.MeasureString(data, threeOfNine);

barcode = new Bitmap(barcode, dataSize.ToSize());
graphics = Graphics.FromImage(barcode);
graphics.Clear(Color.White);

graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixel;

graphics.DrawString(data, threeOfNine, new SolidBrush(Color.Black), 0, 0);

graphics.Flush();
threeOfNine.Dispose();
graphics.Dispose();

return barcode;

}

 


最終結果


image


其他應用


學會字串轉圖片,就可以去網路上找很多免費字型,例如這個網站,來產生一些特殊圖案!


Reference


字型下載
Base64編碼顯示圖片
影像檔等比例縮放

2013年10月22日 星期二

[ASP.NET MVC]輸入Youtube連結,產生預覽影片

前言

之前有做過一個需求跟FaceBook類似:將Youtube連結複製至TextArea,然後產生一個預覽影片,可以直接撥放,我們先直接看完成的結果:

 

youtube

 

分析

Youtube的小視窗,事實上就是一個iframe的標籤,可以指定他的長跟寬,連結(src)部分只要指定為http://www.youtube.com/embed/影片參數?rel=0即可瀏覽,而影片參數的部分其實就是每個影片會有一個Key值,這個Key值在每個影片連結後面可以看到v=xxxxxxx的值,只要將xxxxxxx的Value套至以上的影片參數就可以完成。

image

了解要怎麼做後,接下來就是技術的實現,本文使用JQuery Ajax + ASP.NET MVC實現。

1.前端使用Jquery,當Textbox失去焦點後,將輸入的內容(Youtube的URL)以Ajax丟至後端。

2.後端接收URL並解析所有參數,將參數V的value,回傳給前端。

3.前端接收V參數的Value,改變Iframe的值。

 

程式碼

 

前端

<!DOCTYPE html>

<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<script src="~/Scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function () {
$('#txt_link').blur(function () {
$.ajax({
url: "@Url.Action("GetUrlArgument", "YoutubeSample")",
type: "POST",
data: { StrUrl: $('#txt_link').val() },
dataType: "html",
complete: function () {
},
success: function (data) {
if (data == "") {
$("#ifm_video").hide();
}
else {
$("#ifm_video").attr("src", "http://www.youtube.com/embed/" + data + "?rel=0");
$("#ifm_video").show();
}
},
Error: function () {
alert("發生錯誤");
}
});
});
});
</script>
</head>
<body>
<div>
@Html.Label("影片連結:")
@Html.TextBox("txt_link", "", new { style="width:200px" })
</div>
<div style="width: 800px;">
<iframe id="ifm_video" width="640" height="390" frameborder="0" allowfullscreen />
</div>

</body>
</html>
 

後端

/// <summary>解析URL參數</summary>
/// <param name="StrUrl"></param>
/// <returns></returns>
public ActionResult GetUrlArgument(string StrUrl)
{
if (StrUrl == "") return Content("");
string VideoKey = string.Empty;
try
{
Uri url = new Uri(StrUrl);
string queryString = url.Query; //取得所有參數
if (queryString != string.Empty)
{
NameValueCollection col = GetQueryString(queryString);
VideoKey = col["v"];
}
}
catch
{
VideoKey = string.Empty;
}

return Content(VideoKey);
}

/// <summary>
/// 解析所有參數
/// </summary>
/// <param name="queryString"></param>
/// <param name="encoding"></param>
/// <param name="isEncoded"></param>
/// <returns>回傳NameValueCollection</returns>
public static NameValueCollection GetQueryString(string queryString)
{
queryString = queryString.Replace("?", "");
NameValueCollection result = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
if (!string.IsNullOrEmpty(queryString))
{
string[] Query = queryString.Split('&');
foreach (string pars in Query)
{
string[] pas = pars.Split('=');
result[pas[0]] = pas[1];
}
}
return result;
}

[Coding 543]KendoUI錯誤:Unexpected end of input 崩壞現象

前言

如果你像我一樣有在Study KendoUI,然後卻發現官網Demo頁面卻報出一堆JavaScript的現象請看此篇…

事情經過

一如往常打開KendoUI頁面,來參考一些Sample Code,卻發現選單皆動彈不得,完全無作用,打開Chome開發者工具發現一堆JavaScript錯誤:

1

IE的錯誤訊息:

image

手機崩壞現象

__

不會把…Kendo.all.min.js的CDN有錯 !!! 基本上我覺得不太可能又剛好最近電腦怪怪的,Facebook異常的慢,開始覺得是我電腦的問題,所以開始做了以下事情:

清瀏覽器cache、確認防火牆、各種掃毒軟體、確認各平台裝置(Iphone、IPad)、確認家用網路跟3G網路,各個瀏覽器…和Google(只找到這篇),網路問別人(有問到跟我一樣情況的)等等,大致上確認無誤我就開始寫信給客服抱怨他們的CDN了,但後來得到的回覆是他們也不知道什麼情形,叫我做以上做過的事,試了好幾天又寫封信給客服,得到以下回覆:

In case you are located in the Asian region (China in particular), can it be that some global restriction or filter for your region prevents the execution of our scripts from CDN hosting? I know that this may sound a bit awkward, but I cannot think of any other cause of the issue

大意就是可能我是中國人所在的IP拒絕訪問,好吧,既然科學沒辦法解決,我開始懷疑我家磁場有問題,有些不乾淨的東西,果真沒錯,只要一踏進公司我的遠傳3G網路上該網站就正常了,很無言,後來只好照官方的建議下載離線板

到現在還是報一堆錯阿,提供給和我一樣被擋IP的人,不要跟我一樣糾結浪費一堆時間,換個地方寫Code吧 \(╯-╰)/

[ASP.NET]合併兩張DataTable資料

有時我們會有多個結構一樣但來源不同的資料,需要顯示在一個Grid裡面,這時我們就能用DataTable的Merge() 函數來實現,以我實務遇到的情況,大概就是一個DataTable資料來源為某個XML檔,而另外一個來源為DB(當然如果都是存在於DB,就可以直接用Join的方式來實現),以下就示範這兩種資料來源怎麼合併:

XML來源:

/// <summary>
/// 模擬XML資料
/// </summary>
/// <returns></returns>
private DataTable GetDataTableXml()
{
    string Xmlstring = @"<Datas>
<Data>
<ID>5</ID>
<來源>XML</來源>
</Data>
<Data>
<ID>6</ID>
<來源>XML</來源>
</Data>
<Data>
<ID>7</ID>
<來源>XML</來源>
</Data>
<Data>
<ID>8</ID>
<來源>XML</來源>
</Data>
</Datas>";
    XmlDocument Xmldoc = new XmlDocument();
    Xmldoc.LoadXml(Xmlstring);
    XmlReader Xmlreader = XmlReader.Create(new System.IO.StringReader(Xmldoc.OuterXml));
    DataSet ds = new DataSet();
    ds.ReadXml(Xmlreader);
    DataTable dt = ds.Tables[0];
    return dt;

}

image



SQL來源

/// <summary>
/// 模擬SQL來源,建立假資料
/// </summary>
/// <returns></returns>
private DataTable GetDataTable()
{
    DataTable dt = new DataTable();
    dt.Columns.Add("ID");
    dt.Columns.Add("來源");

    for (int i = 0; i < 6; i++)
    {
        DataRow dr = dt.NewRow();
        dr["ID"] = i;
        dr["來源"] = "SQL Server";
        dt.Rows.Add(dr);
    }

    return dt;
}

image







 


Merge使用方法

dt1 = GetDataTable();
gv_sql.DataSource = dt1;
gv_sql.DataBind();


dt2 = GetDataTableXml();
gv_xml.DataSource = dt2;
gv_xml.DataBind();

//如果不設Key的話,即使ID重複也會顯示兩筆
dt1.PrimaryKey = new DataColumn[] { dt1.Columns["ID"] };
dt2.PrimaryKey = new DataColumn[] { dt2.Columns["ID"] };

//如果有設Key,設true則保留dt1的資料;設false則保留dt2的資料
dt1.Merge(dt2, true);

gv_merge.DataSource = dt1;
gv_merge.DataBind();

Merge有幾個多載,我故意將兩個資料來源都存在ID為 5 的資料,如果不設Key則就會顯示兩筆ID為5的資料,如設定為true則會保留主表的資料(dt1),false則反之。

 


結果:


image



--

Reference
http://msdn.microsoft.com/zh-tw/library/system.data.datatable.merge.aspx
http://haoxiaoittoo.blogspot.tw/2011/07/datatable.html

2013年10月12日 星期六

[ASP.NET]一個輕鬆取得Facebook讚數的套件

SocialCounter.NET是一個極小的library能抓取一些熱門的社群網站資料,如Facebook、Twitter…如果你只是想抓一些統計資料,又不想去研究JavaScript API,可以嘗試看看此套件,我想對某些公司,會有大量的行銷頁面,抓取一些報表分析還蠻方便的:) 台灣比較多人用Facebook,故以下做個小實驗:

首先用Nuget安裝
image

此範例用MVC展示,並新增一個Controller,並using SocailConter.NET
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SocialCounter.NET;

namespace MyMVC.Controllers
{
    public class SocialCounterController : Controller
    {
        //
        // GET: /SocialCounter/

        public ActionResult Index()
        {
            string Article = "http://blogs.msdn.com/b/msdntaiwan/archive/2013/09/23/visual-studio-2013.aspx"; //MSDN某文章
            TempData["Gplikes"] = Counter.GetFacebookLikes("https://www.facebook.com/msdn.taiwan");//抓取MSDN粉絲團讚
            TempData["likes"] = Counter.GetFacebookLikes(Article); //文章讚數
            TempData["share"] = Counter.GetLinkedInShareCount(Article); //分享數
            TempData["Article"] = Article;
            return View();
        }

    }
}



非常簡易的方式,接著我們在View顯示出來,並來做個核對
<fieldset>
    <legend>MSDN粉絲團</legend>
    <div>粉絲團讚:@TempData["Gplikes"]</div>
    <div>文章:<a href="@TempData["Article"]">前端工程師的百寶盒 - Visual Studio 2013 開發工具</a></div>
    <div>讚:@TempData["likes"]</div>
    <div>分享數:@TempData["share"]</div>
</fieldset>



粉絲團讚數正確

image



但是文章這篇文章的讚數不一致

image



Anyway,分享給各位做個參考 :)

--

Reference
http://www.nuget.org/packages/SocialCounter.NET/
http://gunnarpeipman.com/2012/07/using-socialcounter-net-with-asp-net-mvc/

2013年10月9日 星期三

[ASP.NET]C#清掉所有控制項的值

分享一個小技巧,今天在維護舊系統發現一段程式,主要邏輯是處理完一些事後,要將某區塊的表單欄位清掉,程式很直覺但寫起來會很煩:

.aspx

<!-- 拉一些常用的Controll -->
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<asp:DropDownList ID="DropDownList1" runat="server">
<asp:ListItem>1</asp:ListItem>
<asp:ListItem>2</asp:ListItem>
</asp:DropDownList>
<asp:HiddenField ID="HiddenField1" runat="server" />
<asp:CheckBox ID="CheckBox1" runat="server" />
<asp:CheckBoxList ID="CheckBoxList1" runat="server"></asp:CheckBoxList>
<asp:Button ID="btn_Clear" runat="server" Text="Button" OnClick="btn_Clear_Click" />

.aspx.cs

TextBox1.Text = "";
Label1.Text = "";
DropDownList1.Items.Clear();
CheckBox1.Checked = false;

因為實際上控制項很多,所以就一拖拉庫以上的程式Orz,所以花了一點時間重構此塊,寫成一個function:

/// <summary>清掉控制項的值</summary>
/// <param name="ctols">控制項ID</param>
private void ClearControlValue(params Control[] ctols)
{
foreach (Control ctol in ctols)
{
string cType = ctols.GetType().Name;
if (typeof(TextBox).Name == cType)
{
(ctol as TextBox).Text = string.Empty;
}
else if (typeof(DropDownList).Name == cType)
{
(ctol as DropDownList).Items.Clear();
}
else if (typeof(CheckBox).Name == cType)
{
(ctol as CheckBox).Checked = false;
}
else if (typeof(CheckBoxList).Name == cType)
{
(ctol as CheckBoxList).SelectedIndex = -1;
}
else if (typeof(RadioButton).Name == cType)
{
(ctol as RadioButton).Checked = false;
}
else if (typeof(RadioButtonList).Name == cType)
{
(ctol as RadioButtonList).SelectedIndex = -1;
}
else if (typeof(Label).Name == cType)
{
(ctol as Label).Text = string.Empty;
}
}
}

使用方法:

//把要清掉值的控制項ID傳入
ClearControlValue(TextBox1, CheckBoxList1, Label1);

2013年10月2日 星期三

[CSS]表單Textbox與Lable調整對齊

常常做一些表單欄位,如果欄位多又不調整版面看起來就會很亂,當然可以用table很方便的定位,但這樣又變成程式碼很亂,以下是我調整畫面&程式碼都看起來很簡潔的CSS程式碼,紀錄一下,每次都要重調還蠻惱人的!

改造前

<label for="txt_name">姓名:</label>
<input type="text" id="txt_name" /><br />
<label for="txt_birth">生日:</label>
<input type="text" id="txt_birth" /><br />
<label for="txt_phone">電話:</label>
<input type="text" id="txt_phone" /><br />
<label for="txt_id">身分證字號:</label>
<input type="text" id="txt_id" /><br />
image


改造後

<div class="Data-Content">
<div class="Data-Title">
<div class="AlignRight">
<label for="txt_name">姓名:</label><br />
<label for="txt_birth">生日:</label><br />
<label for="txt_phone">電話:</label><br />
<label for="txt_id">身分證字號:</label><br />
</div>
</div>
<div class="Data-Items">
<input type="text" id="txt_name" /><br />
<input type="text" id="txt_birth" /><br />
<input type="text" id="txt_phone" /><br />
<input type="text" id="txt_id" /><br />
</div>
</div>
<style type="text/css">
.Data-Content {
width: 100%; /* 表單寬度 */
line-height: 40px;
}

.Data-Title {
float: left;
width: 25%; /* Label寬度,視情況調整 */
margin-right: 20px;
}

.Data-Items {
float: left;
width: 25%;
}

.AlignRight {
text-align: right;
}
</style>
image