2011年7月28日 星期四

ASP.NET 自訂控制項 - GridView 固定標題列與凍結欄位

重要更新:
我們提供了一個更完整的方案,請到以下網址參考: http://gridviewscroll.aspcity.idv.tw/


經過相當多的測試,終於找出比較可行的GridView凍結欄位做法,以下是畫面擷圖與Demo.

P.S. 可以試著把瀏覽視窗稍微縮小一點,就可以看到凍結的效果.



[Live Demo]
http://www.aspcity.idv.tw/demo.aspx

選擇左邊選單的ScrollGridView

如果此範例在你的瀏覽器中有任何的問題,希望您可以讓我知道,謝謝!

2011年7月26日 星期二

ASP.NET 自訂控制項 - Live Demo (2011/07/26)

[2011/07/26]
[NEW] GroupButton
[FIX] 修正ScrollGridView在Mozilla Firefox的標題列高度問題



[Live Demo]
http://www.aspcity.idv.tw/demo.aspx

2011年7月25日 星期一

ASP.NET 自訂控制項 - Live Demo (2011/07/25)

[2011/07/25]
[FIX] 修正PopUp對齊問題
[FIX] DropDownButton -> DorpDownList
[NEW] DropDownButton
[NEW] SplitButton

新增了一個比較多功能的控制項SplitButton,功能說明如下:
1. 包含一個預設的按鈕
2. 可額外連結一個ContextMenu的控制項,按下控制項額外的指標就會以PopUp的方式顯示.
3. 可設定為大圖示顯示與小型圖示顯示



[Live Demo]
http://www.aspcity.idv.tw/demo.aspx

2011年7月21日 星期四

ASP.NET 自訂控制項 - Live Demo

目前已經開發完成的控制項有下列幾種
ContextMenu
DateBox
DateRangeBox
DialogBox
DropDownButton
GridViewPager
MultiItemBox
NavigationBar
ScrollGridView
SearchKeyPanel
SplitterPanel

我準備了一個範例的網頁,可以直接進行一些簡單的操作,有興趣的人可以到
http://www.aspcity.idv.tw/demo.aspx

2011年7月15日 星期五

提出您的想法或感興趣的議題!!

如果你有任何想法,或是對任何相關技術有興趣的,歡迎您直接EMail給我.

2011年7月14日 星期四

ASP.NET自訂控制項 - 簡單的日期選擇輸入框 DateBox (二)

此篇將延續
ASP.NET自訂控制項 - 簡單的日期選擇輸入框 DateBox

在上次的分享中,雖然這個控制項已經可以正常的運作,但是不知道有沒有人發現在設計階段(Design-Time)是有一些小問題的.


控制項在設計階段的確是可以正常顯示.


在屬性設定視窗中仍然有以下問題:

1. Date這個屬性應該是在執行階段中,用程式碼來進行存取使用的
2. ImageUrl沒有辦法像Image一樣可以使用挑選的方式進行設定

針對上述問題,我們可以透過以下方式進行處理

1. 使用Browsable Attribute隱藏屬性是否顯示
[
Browsable(false)
]
public DateTime Date
{
    get { return Convert.ToDateTime(this.DateText); }
    set { this.DateText = value.ToString(this.Format); }
}


2. 使用Editor Attribute指定屬性的編輯器
[
Editor("System.Web.UI.Design.ImageUrlEditor", typeof(UITypeEditor))
]
public string ImageUrl
{
    get
    {
        object value = this.ViewState["ImageUrl"];

        if (value == null) return "";

        return (string)value;
    }
    set { this.ViewState["ImageUrl"] = value; }
}


3. 透過DefaultValue Attribute來設定屬性預設值與Category Attribute來設定屬性的分類
[
DefaultValue("yyyy/MM/dd"),
Category("Likol")
]
public string Format
{
    get
    {
        object value = this.ViewState["Format"];

        if (value == null) return "yyyy/MM/dd";

        return (string)value;
    }
    set { this.ViewState["Format"] = value; }
}


修正完成後,就可以在設計階段中看到對應的效果





修改後的完整程式碼如下

DateBox.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using AjaxControlToolkit;
using System.ComponentModel;
using System.Drawing.Design;

namespace Likol.Web.DemoWebSite.WebControls
{
    [
    ToolboxData("<{0}:DateBox runat=server>")
    ]
    public class DateBox : CompositeControl
    {
        private TextBox txtValue;
        private ImageButton ibButton;
        private CalendarExtender ceCalendar;

        [
        DefaultValue(""),
        Category("Likol"),
        Editor("System.Web.UI.Design.ImageUrlEditor", typeof(UITypeEditor))
        ]
        public string ImageUrl
        {
            get
            {
                object value = this.ViewState["ImageUrl"];

                if (value == null) return "";

                return (string)value;
            }
            set { this.ViewState["ImageUrl"] = value; }
        }

        [
        DefaultValue("yyyy/MM/dd"),
        Category("Likol")
        ]
        public string Format
        {
            get
            {
                object value = this.ViewState["Format"];

                if (value == null) return "yyyy/MM/dd";

                return (string)value;
            }
            set { this.ViewState["Format"] = value; }
        }

        [
        DefaultValue(""),
        Category("Likol")
        ]
        public string DateText
        {
            get
            {
                this.EnsureChildControls();

                return this.txtValue.Text;
            }
            set
            {
                this.EnsureChildControls();

                this.txtValue.Text = value;
            }
        }

        [
        Browsable(false)
        ]
        public DateTime Date
        {
            get { return Convert.ToDateTime(this.DateText); }
            set { this.DateText = value.ToString(this.Format); }
        }

        protected override void CreateChildControls()
        {
            this.txtValue = new TextBox();
            this.txtValue.ID = "Value";
            this.txtValue.MaxLength = 10;

            this.ibButton = new ImageButton();
            this.ibButton.ID = "Button";
            this.ibButton.ImageUrl = this.ImageUrl;

            this.ceCalendar = new CalendarExtender();
            this.ceCalendar.ID = "Calendar";
            this.ceCalendar.TargetControlID = this.txtValue.ID;
            this.ceCalendar.PopupButtonID = this.ibButton.ID;
            this.ceCalendar.Format = this.Format;

            this.Controls.Add(this.txtValue);
            this.Controls.Add(this.ibButton);
            this.Controls.Add(this.ceCalendar);
        }
    }
}

ASP.NET自訂控制項 - 簡單的日期選擇輸入框 DateBox

有了AjaxToolkit之後,應該就可以很容易的使用CalendarExtender與TextBox來達到日期選擇的功能,不過仍然需要花費一點時間在CalendarExtender控制項上的設定,其實透過一些簡單的程式碼包裝成Server Control就可以很容易的使用這樣的功能.

1.先來看看整合的效果與使用方式
ASPX

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<ajaxToolkit:ToolkitScriptManager ID="scriptManager1" runat="server" />

<Demo:DateBox ID="DateBox1" runat="server"
ImageUrl="~/Images/DateBox.gif" Format="yyyy/MM/dd" /><br/>

<asp:Button ID="btnSubmit" runat="server" Text="Submit"
OnClick="btnSubmit_Click" /><br/>

Date: <asp:Label ID="lblDate" Font-Bold="true" runat="server" /><br/>
DateText: <asp:Label ID="lblDateText" Font-Bold="true" runat="server" />
</form>
</body>
</html>

C#

namespace Likol.Web.DemoWebSite
{
public partial class DateBox : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}

protected void btnSubmit_Click(object sender, EventArgs e)
{
this.lblDate.Text = this.DateBox1.Date.ToString("yyyy/MM/dd");
this.lblDateText.Text = this.DateBox1.DateText;
}
}
}

我們可以透過兩個屬性Date(DateTime), DateText(string)來取得輸入資料.

日期選擇輸入框 DateBox Demo
http://www.aspcity.idv.tw/DateBox.aspx

雖然在這個範例中似乎沒有帶來相當大的便利性,可是對程式設計師來說能少一個步驟就少一個步驟,能把更多的時間花費在重要的程式碼上,其實才是重要的.

DateBox.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using AjaxControlToolkit;

namespace Likol.Web.DemoWebSite.WebControls
{
[
ToolboxData("<{0}:DateBox runat=server>")
]
public class DateBox : CompositeControl
{
private TextBox txtValue;
private ImageButton ibButton;
private CalendarExtender ceCalendar;

public string ImageUrl
{
get
{
object value = this.ViewState["ImageUrl"];

if (value == null) return "";

return (string)value;
}
set { this.ViewState["ImageUrl"] = value; }
}

public string Format
{
get
{
object value = this.ViewState["Format"];

if (value == null) return "";

return (string)value;
}
set { this.ViewState["Format"] = value; }
}

public string DateText
{
get
{
this.EnsureChildControls();

return this.txtValue.Text;
}
set
{
this.EnsureChildControls();

this.txtValue.Text = value;
}
}

public DateTime Date
{
get { return Convert.ToDateTime(this.DateText); }
set { this.DateText = value.ToString(this.Format); }
}

protected override void CreateChildControls()
{
this.txtValue = new TextBox();
this.txtValue.ID = "Value";
this.txtValue.MaxLength = 10;

this.ibButton = new ImageButton();
this.ibButton.ID = "Button";
this.ibButton.ImageUrl = this.ImageUrl;

this.ceCalendar = new CalendarExtender();
this.ceCalendar.ID = "Calendar";
this.ceCalendar.TargetControlID = this.txtValue.ID;
this.ceCalendar.PopupButtonID = this.ibButton.ID;
this.ceCalendar.Format = this.Format;

this.Controls.Add(this.txtValue);
this.Controls.Add(this.ibButton);
this.Controls.Add(this.ceCalendar);
}
}
}


Updated: ASP.NET自訂控制項 - 簡單的日期選擇輸入框 DateBox (二)

2011年7月12日 星期二

Demo - ASP.NET自訂控制項 - 固定欄位標題列 ScrollGridView

重要更新:
我們提供了一個更完整的方案,請到以下網址參考: http://gridviewscroll.aspcity.idv.tw/


我準備了一個關於ScrollView的Demo網頁,大家可以去實際看一下它的效果是如何,有任何的問題或想法也可以讓我知道.

你可以試著將瀏覽的視窗拉大或拉小,這樣可以比較看得出來效果.

[固定欄位標題列 ScrollGridView Demo]
http://www.aspcity.idv.tw/demo.aspx

選擇左邊選單的ScrollGridView

2011年7月10日 星期日

Visual Studio 2010 T4 Text Templates 與 SqlExector 整合

在先前的分享中有提到以下兩個部份:
1. Visual Studio 2010 T4 Text Templates - 文字範本與程式碼產生
2. Visual Studio 2010 SqlExector - 快速執行.sql檔案

現在我將兩個工具進行了一些整合,並將整合後的結果更能應用在實際的程式開發上,以下就是這整個概念的說明

1. 在SQL Server上建立如下的資料庫與包含的資料表


2. 在Visual Studio 2010中,建立一個空白的Web Application(C#)專案,並建立如下圖的資料夾結構


3. 編輯專案中的Web.Config檔案,加入你需要連線的資料庫連結字串


4. 接下來會使用到的功能就是這次整合好的成果.

5. 滑鼠右鍵選取SQL這個資料夾並選擇新增項目,在視窗中可看到一個新的分類"Likol",選擇"Sql Text Template"項目,並修改檔案名稱為"ProductCategory.tt".


6. 完成後會出現資料表的選擇畫面,先選擇稍早鎖建立的資料庫連線設定,並選擇"ProductCategory"這個資料表


7. 重複5的步驟,但這次選擇的新增項目改為"Data Text Template",並一樣選擇"ProductCategory"這個資料表




8. 重複5,6,7步驟,但資料表的部份選擇"Product"

9.上述步驟完成後可看到如下圖的畫面


10. 接下來我們在SQL這個資料夾使用右鍵選擇,並選取SqlExector來執行由Text Template所產生的SQL Script






11. 執行完成後,我們可以在資料庫中看到,相關資料異動的Store Procedure都已經建立完成.


12. 現在,我們就可以使用由"Data Text Template"所產生的相關資料表操作,來進行程式的撰寫.我建立了如下的程式界面與程式

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <table>
            <tr>
                <td colspan="2"><b>Create</b></td>
            </tr>
            <tr>
                <td><asp:TextBox ID="txtName" runat="server" /></td>
                <td><asp:Button ID="btnCreate" Text="Create" runat="server" 
                        onclick="btnCreate_Click" /></td>
            </tr>
        </table>
        <br/>
        <br/>
        <table>
            <tr>
                <td colspan="2"><b>Select</b></td>
            </tr>
            <tr>
                <td><asp:TextBox ID="txtID" runat="server" /></td>
                <td><asp:Button ID="btnSelect" Text="Select" runat="server" 
                        onclick="btnSelect_Click" /></td>
            </tr>
            <tr>
                <td colspan="2">
                    Name: <asp:Label ID="lblName" Font-Bold="true" runat="server"></asp:Label>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

namespace WebApplication1
{
    public partial class ProductCategory : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void btnCreate_Click(object sender, EventArgs e)
        {
            Data.ProductCategory productCategory = new Data.ProductCategory();
            productCategory.ID = Guid.NewGuid();
            productCategory.Name = this.txtName.Text;

            Data.ProductCategory.Create(productCategory);
        }

        protected void btnSelect_Click(object sender, EventArgs e)
        {
            Data.ProductCategory productCategory = new Data.ProductCategory();
            productCategory.ID = new Guid(this.txtID.Text);

            productCategory = Data.ProductCategory.Select(productCategory);

            this.lblName.Text = productCategory.Name;
        }
    }
}

13. 輸入要新增的ProductCategroy名稱,並選擇Create.


14. 從資料表中找出剛剛新增的資料ID,並填入畫面,接著按下Select按鈕,就會將該Category的名稱顯示出來.


Data\SQL\ProductCategory.tt 產生的內容如下:
IF EXISTS(SELECT * FROM sys.objects WHERE type='P' AND name='sp_ProductCategory_Create')
 DROP PROCEDURE sp_ProductCategory_Create
GO

CREATE PROCEDURE sp_ProductCategory_Create
 @ID AS uniqueidentifier, 
 @Name AS nvarchar(50) 
AS
BEGIN

 INSERT INTO ProductCategory
 (
  ID, 
  Name 
 )
 VALUES
 (
  @ID, 
  @Name 
 )
END
GO

IF EXISTS(SELECT * FROM sys.objects WHERE type='P' AND name='sp_ProductCategory_Update')
 DROP PROCEDURE sp_ProductCategory_Update
GO

CREATE PROCEDURE sp_ProductCategory_Update
 @ID AS uniqueidentifier, 
 @Name AS nvarchar(50) 
AS
BEGIN

 UPDATE ProductCategory SET
  Name=@Name 
 WHERE
  ID=@ID 
END
GO

IF EXISTS(SELECT * FROM sys.objects WHERE type='P' AND name='sp_ProductCategory_Delete')
 DROP PROCEDURE sp_ProductCategory_Delete
GO

CREATE PROCEDURE sp_ProductCategory_Delete
  @ID AS uniqueidentifier 
AS
BEGIN

 DELETE ProductCategory WHERE
  ID=@ID 
END
GO

IF EXISTS(SELECT * FROM sys.objects WHERE type='P' AND name='sp_ProductCategory_Select')
 DROP PROCEDURE sp_ProductCategory_Select
GO

CREATE PROCEDURE sp_ProductCategory_Select
  @ID AS uniqueidentifier 
AS
BEGIN

 SELECT * FROM ProductCategory WHERE
  ID=@ID 
END
GO

Data\ProductCategory.tt 產生的內容如下:
//------------------------------------------------------------------------------
// 
// This code was generated by Likol.VisualStudio.Template Tool.
// Last generater time: 2011/7/10 上午 06:23:11
// 
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.SqlClient;
using Likol.Data;
using Likol.Web.Validation;

namespace WebApplication1.Data
{
 public partial class ProductCategory
 {
  private Guid _ID;
  private string _Name;

  public Guid ID
  {
   get { return this._ID; }
   set { this._ID = value; }
  }

  [Length(50)]
  public string Name
  {
   get { return this._Name; }
   set { this._Name = value; }
  }

  public static void Create(ProductCategory _ProductCategory)
  {
   SqlParameter[] parameters = new SqlParameter[]{
    new SqlParameter("ID", _ProductCategory.ID), 
    new SqlParameter("Name", _ProductCategory.Name) 
   };

   string commandText = "sp_ProductCategory_Create";

   DatabaseManager.ExecuteNonQuery(commandText, parameters);
  }

  public static void Update(ProductCategory _ProductCategory)
  {
   SqlParameter[] parameters = new SqlParameter[]{
    new SqlParameter("ID", _ProductCategory.ID), 
    new SqlParameter("Name", _ProductCategory.Name) 
   };

   string commandText = "sp_ProductCategory_Update";

   DatabaseManager.ExecuteNonQuery(commandText, parameters);
  }

  public static void Delete(ProductCategory _ProductCategory)
  {
   SqlParameter[] parameters = new SqlParameter[]{
    new SqlParameter("ID", _ProductCategory.ID) 
   };

   string commandText = "sp_ProductCategory_Delete";

   DatabaseManager.ExecuteNonQuery(commandText, parameters);
  }

  public static ProductCategory Select(ProductCategory _ProductCategory)
  {
   SqlParameter[] parameters = new SqlParameter[]{
    new SqlParameter("ID", _ProductCategory.ID) 
   };

   string commandText = "sp_ProductCategory_Select";

   SqlConnection sqlConnection = null;

   SqlDataReader sqlDataReader = DatabaseManager.ExecuteReader(commandText, parameters, ref sqlConnection);

   bool hasData = sqlDataReader.Read();

   if (!hasData) return null;

   ProductCategory __ProductCategory = new ProductCategory();

   __ProductCategory.ID = (Guid)sqlDataReader["ID"];
   __ProductCategory.Name = (string)sqlDataReader["Name"];

   sqlDataReader.Close();
   sqlConnection.Close();

   return __ProductCategory;
  }

  public static string GetLookupText(object propertyValue)
  {
   ProductCategory _ProductCategory = new ProductCategory();
   _ProductCategory.ID = (Guid)propertyValue;

   _ProductCategory = ProductCategory.Select(_ProductCategory);

   if (_ProductCategory != null) return _ProductCategory.Name;

   return "";
  }
 }
}


用T4 Text Templates的好處其實在於產生出來的格式雖然是固定的了,還是可以透過一些程式設計的方式進行異動,而且可以根據當時的需求進行修改,完全還是在程式設計的範疇之中.

2011年7月4日 星期一

Visual Studio 2010 SqlExector - 快速執行.sql檔案

這是一個Visual Studio 2010的自訂Package,主要的目的是希望可以在方案總管直接點選一個.sql的檔案或目錄,來快速執行SQL的語法.


1. 開啟包含.sql檔案的專案,並在.sql檔案上點選滑鼠右建,可以看到一個自訂的選單"SqlExector".



2. 選擇"Execute Sql Files"後,選擇要執行的.sql項目.



3. 完成選擇後,選擇要用來執行的ConnectionString,在這裡選擇的Connection的項目是直接由專案中Web.Config檔案中所設定的configuration\connectionStrings項目.



4. 確定完畢後,就會開始執行選擇的項目,可以在Visual Studio 2010的Output Window中看到執行的結果



預設如果你是點選一個目錄執行sql語法,尚未儲存的檔案將會自動存檔,如果僅選擇一個檔案,該檔案尚未存檔,將會跳出訊息框讓使用者確認.


感謝您把這篇文章看完了,也幫我按個讚吧!

2011年7月1日 星期五

Visual Studio 2010 T4 Text Templates - 文字範本與程式碼產生

T4 Text Templates在Visual Studio 2010中,算是一個滿不錯的功能,可以用範本的方式來快速產生相同格式的程式碼或是檔案內容.這裡我試著讀取資料庫中的Table Schema來產生相對應的Class.


1. 在專案中新增一個項目,Add New Item -> General 選擇 Text Template

2. 新增完成後可以看到剛剛新增的項目(.tt)與它底下包含的項目(.txt)

3. 修改output extension=".txt",就可以改變產生檔案的附檔名



4. 透過一些自行寫的程式就可以產生一些固定格式的內容如下:

Product.tt

<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="Likol.VisualStudio" #>
<#@ import namespace="Likol.VisualStudio.Template" #>
<#

string ConnectionName = "Template"; // ConnectionString Name in Web.Config
string TableName = "Product"; // Table Name

TableTemplate tableTemplate = new TableTemplate(this.Host, ConnectionName, TableName);
tableTemplate.Fill();
#>
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by Likol.VisualStudio.Template Tool.
// Last generater time: <#= DateTime.Now.ToString()#>
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Likol.Web.Validation;

namespace Likol.Web.TestWebSite.Data
{
 public class <#= tableTemplate.TableName #>
 {
<#
foreach(TableColumn tableColumn in tableTemplate.Columns)
{
#>
  private <#= tableColumn.DataType #> _<#= tableColumn.Name #>;
<#
}
#>

<#
foreach(TableColumn tableColumn in tableTemplate.Columns)
{
#>
<# if (!tableColumn.Nullable){ #>
  [Required]
<#}#>
<# if (tableColumn.Length != 0){ #>
  [Length(<#= tableColumn.Length.ToString() #>)]
<#}#>
  public <#= tableColumn.DataType #> <#= tableColumn.Name #>
  {
   get { return this._<#= tableColumn.Name #>; }
   set { this._<#= tableColumn.Name #> = value; }
  }

<#
}
#>
 }
}

Product.cs - 產生的結果

//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by Likol.VisualStudio.Template Tool.
// Last generater time: 2011/7/1 上午 09:54:25
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Likol.Web.Validation;

namespace Likol.Web.TestWebSite.Data
{
 public class Product
 {
  private int _ID;
  private Guid _CategotyID;
  private string _Name;

  [Required]
  public int ID
  {
   get { return this._ID; }
   set { this._ID = value; }
  }

  [Required]
  public Guid CategotyID
  {
   get { return this._CategotyID; }
   set { this._CategotyID = value; }
  }

  [Required]
  [Length(50)]
  public string Name
  {
   get { return this._Name; }
   set { this._Name = value; }
  }
 }
}


TableTemplate是一個用來與SQL Server溝通讀取Table Schema的Class,它會讀取Table中欄位相關的資訊,並做一些轉換.