星期日, 8月 30, 2015

[VS] 起始專案

Solution 內有多個專案,都是在 Solution 選項內去進行變更

[VS] 起始專案-1

[VS] 起始專案-2

上課時看老師操作,才發現 Project 右鍵內,就可快捷功能可以直接設定

[VS] 起始專案-3

起始專案的名稱會有粗體的效果來提供辨識

[VS] 起始專案-4

星期五, 8月 28, 2015

[C#] DataGridView 匯出 Excel

論壇問題 - 把 DataGridView 內資料匯出 Excel


Employ Class
namespace DataGridView2Excel
{
    public class Employ
    {
        public string EmpNO { get; set; }
        public string EmpName { get; set; }
        public DateTime Birthday { get; set; }
        public decimal Salary { get; set; }
    }
}

WinForm C# Demo
using Excel = Microsoft.Office.Interop.Excel;

namespace DataGridView2Excel
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            dataGridView1.DataSource = GetSource();
        }

        private List<Employ> GetSource()
        {
            List<Employ> source = new List<Employ>();
            source.Add(new Employ() { EmpNO = "001", EmpName = "張三", Birthday = new DateTime(1970, 1, 1), Salary = 55000 });
            source.Add(new Employ() { EmpNO = "002", EmpName = "李四", Birthday = new DateTime(1981, 11, 11), Salary = 35000 });
            source.Add(new Employ() { EmpNO = "003", EmpName = "王五", Birthday = new DateTime(1985, 7, 7), Salary = 25000 });
            return source;
        }

        private void btnExcel_Click(object sender, EventArgs e)
        {
            SaveFileDialog save = new SaveFileDialog();
            save.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            save.FileName = "Excel Export demo";
            save.Filter = "*.xlsx|*.xlsx";
            if (save.ShowDialog() != DialogResult.OK) return;

            // Excel 物件
            Excel.Application xls = null;
            try
            {
                xls = new Excel.Application();
                // Excel WorkBook
                Excel.Workbook book = xls.Workbooks.Add();
                // Excel WorkBook,預設會產生一個 WorkSheet,索引從 1 開始,而非 0
                // 寫法1
                Excel.Worksheet Sheet = (Excel.Worksheet)book.Worksheets.Item[1];
                // 寫法2
                Excel.Worksheet Sheet = (Excel.Worksheet)book.Worksheets[1];
                // 寫法3
                Excel.Worksheet Sheet = xls.ActiveSheet;

                // 把 DataGridView 資料塞進 Excel 內
                DataGridView2Excel(Sheet);
                // 儲存檔案
                book.SaveAs(save.FileName);
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                xls.Quit();
            }
        }

        private void DataGridView2Excel(Excel.Worksheet Sheet)
        {
            // 下面方法二選一使用
            // 利用 DataGridView 
            for (int i = 0; i < dataGridView1.Rows.Count; i++)
            {
                for (int j = 0; j < dataGridView1.Columns.Count; j++)
                {
                    string value = dataGridView1[j, i].Value.ToString();
                    Sheet.Cells[i + 1, j + 1] = value;
                }
            }

            // 利用 List<Employ>
            List<Employ> empList = (List<Employ>)dataGridView1.DataSource;
            foreach (Employ emp in empList)
            {
                int
                    rowindex = empList.IndexOf(emp) + 1,
                    colindex = 1;

                Sheet.Cells[rowindex, colindex++] = emp.EmpNO;
                Sheet.Cells[rowindex, colindex++] = emp.EmpName;
                Sheet.Cells[rowindex, colindex++] = emp.Birthday;
                Sheet.Cells[rowindex, colindex++] = emp.Salary;
            }   
        }
    }
}



  • Type.Missing
閱讀 Automation 相關資料時,很討厭的是怎麼一堆參數是 Type.Missing,讓人看到眼花撩亂,@@
但在 dotNet 4.5 參數有預設值 Type.Missing,那表示就不用輸入啦,^^


星期四, 8月 27, 2015

[C#] Microsoft.Office.Interop.Excel - dll 引用

想學習一下,如何在 C# 中使用 Excel Automation,沒想到光是要把它加入參考,就花掉不少時間,最後是在下圖的位置,找到 Excel.dll,Orz

自己筆電

在公司電腦是在參考管理員 => 組件 => 擴充功能下就找到啦
using Excel = Microsoft.Office.Interop.Excel;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Excel.Application demo = new Excel.Application();
        }
    }
}

星期三, 8月 26, 2015

[C#] ComboBox 多欄位 - DrawItem

利用 ComboBox DrawItem Event 來作到多欄位顯示功能

DateSelect Class
namespace ComboBoxMultiCols
{
    public class DateSelect
    {
        public int Year { get; set; }
        public int TWYear { get; set; }

        public static List<DateSelect> DataFill()
        {
            List<DateSelect> result = new List<DateSelect>();

            DateTime 
                Today = DateTime.Today ,
                LoopDate = DateTime.Today ;
            int 
                Year = 0 ,
                TWYear = 0;
   
            System.Globalization.TaiwanCalendar tc = new System.Globalization.TaiwanCalendar();

            for (int i = 0; i < 10; i++)
            {
    
                LoopDate = Today.AddYears(i * -1);
                Year = LoopDate.Year;
                TWYear = tc.GetYear(LoopDate);

                DateSelect ds = new DateSelect()
                {
                    Year = Year ,
                    TWYear = TWYear
                };

                result.Add(ds);
            }

            return result;
        }
    }
}
WinForm Demo
namespace ComboBoxMultiCols
{
    public partial class MultiCols_DrawItem : Form
    {
        public MultiCols_DrawItem()
        {
            InitializeComponent();
        }

        private void MultiCols_DrawItem_Load(object sender, EventArgs e)
        {
            comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
            comboBox1.DataSource = DateSelect.DataFill();
            comboBox1.DisplayMember = "Year";
            comboBox1.ValueMember = "TWYear";

            comboBox1.DrawMode = DrawMode.OwnerDrawFixed;
            comboBox1.DrawItem += comboBox1_DrawItem;
        }

        void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
        {
            // 繪製預設背景
            e.DrawBackground();

            // DataSource 是 List<DateSelect>,所以這裡必須轉型為 DateSelect
            // 假如 DataSource 是 DataTable,就必須轉型為 DataRowView
            DateSelect ds = (DateSelect)this.comboBox1.Items[e.Index];

            // ComboBox 內文字
            string DropDownInfo = string.Format("{0} (民國 {1:000} 年)", ds.Year, ds.TWYear);

            // 取得 ComboBox 界限
            Rectangle rec = e.Bounds;
   
            // 把文字繪進去
            using (SolidBrush sb = new SolidBrush(e.ForeColor))
            {
                e.Graphics.DrawString(DropDownInfo, e.Font, sb, rec);
            }
        }
    }
}

[C#] ComboBox 多欄位 - DrawItem-1

星期二, 8月 25, 2015

[C#] PictureBox - 區段顏色

論壇問題,簡化成在動態產生 PicutrBox 並根據資料在 Paint Event 內畫出各區段顏色

專案內容
[C#] PictureBox - 區段顏色-2

WinForm Layout:只放一個 FlowLayoutPanel 容器

[C#] PictureBox - 區段顏色-1

星期一, 8月 24, 2015

[C#] ComboBox 多欄位 - TSQL

在 T-SQL 中先行把 ComboxBox DisplayMember 的資料整理好,藉此來作到多欄位顯示功能

利用該 Store Procedure 來產生日期資料
CREATE PROCEDURE dbo.GetComboBoxData
AS
    BEGIN
       WITH CTE AS 
       (
           SELECT 
               YEAR(GetDate()) AS [Year] , 0 AS DelCount
           UNION ALL
           SELECT 
               [Year] - 1 , DelCount + 1
           FROM CTE
           WHERE DelCount + 1 <= 10
       )
       SELECT
           CAST([Year] AS varchar(4)) + 
           '( 民國 ' + RIGHT(REPLICATE('0',3)  + CAST([Year] - 1911 AS varchar(3)),3) + ' 年)' AS Display ,
           [Year] AS value
       FROM CTE
    END
C# Winform 中的測試 Code
using System.Data.SqlClient;

namespace ComboBoxMultiCols
{
    public partial class MultiCols_TSQL : Form
    {
        public MultiCols_TSQL()
        {
            InitializeComponent();
        }

        private void MultiCols_TSQL_Load(object sender, EventArgs e)
        {
            comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
            SetComboDaataSource();
        }

        private void SetComboDaataSource()
        {

            string ConnString = @"Data Source=InstanceName;Initial Catalog=DBName;Integrated Security=True";
            using(SqlConnection conn = new SqlConnection(ConnString))
            {
                try
                {
                    SqlCommand cmd = new SqlCommand();
                    cmd.Connection = conn;
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.CommandText = "GetComboBoxData";

                    if (conn.State == ConnectionState.Closed) conn.Open();

                    DataTable dt = new DataTable();
                    SqlDataAdapter da = new SqlDataAdapter();
                    da.SelectCommand = cmd;
                    da.Fill(dt);

                    comboBox1.DataSource = dt;
                    comboBox1.DisplayMember = dt.Columns[0].ToString();
                    comboBox1.ValueMember = dt.Columns[1].ToString();
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }
    }
}
[C#] ComboBox 多欄位 - TSQL

星期五, 8月 21, 2015

[C#] ComboBox 多欄位 - Format

利用 ComboBox Format Event 來作到多欄位顯示功能

DateSelect Class
namespace ComboBoxMultiCols
{
    public class DateSelect
    {
        public int Year { get; set; }
        public int TWYear { get; set; }

        public static List<DateSelect> DataFill()
        {
            List<DateSelect> result = new List<DateSelect>();

            DateTime 
                Today = DateTime.Today ,
                LoopDate = DateTime.Today ;
            int 
                Year = 0 ,
                TWYear = 0;
   
            System.Globalization.TaiwanCalendar tc = new System.Globalization.TaiwanCalendar();

            for (int i = 0; i < 10; i++)
            {
    
                LoopDate = Today.AddYears(i * -1);
                Year = LoopDate.Year;
                TWYear = tc.GetYear(LoopDate);

                DateSelect ds = new DateSelect()
                {
                    Year = Year ,
                    TWYear = TWYear
                };

                result.Add(ds);
            }

            return result;
        }
    }
}

WinForm Demo
namespace ComboBoxMultiCols
{
    public partial class MultiCols_Format : Form
    {
        public MultiCols_Format()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
            comboBox1.DataSource = DateSelect.DataFill();
            comboBox1.DisplayMember = "TWYear";
            comboBox1.ValueMember = "Year";
        }

        private void comboBox1_Format(object sender, ListControlConvertEventArgs e)
        {
            DateSelect ds = e.ListItem as DateSelect;
            if (ds == null) return;
            e.Value = string.Format("{0} (民國{1})",ds.Year,ds.TWYear.ToString("000"));
        }
    }
}

[C#] ComboBox 多欄位 - Format

星期四, 8月 20, 2015

[C#] Reflection - Property

看見這篇文章標題 How to Get Name of the Member (Property Name, etc.) of a .NET Class Without Using Hard-coded/ Magic Strings,原以為是介紹 Reflection,看完內容才知道還可以用 System.Linq.Expressions 來達到相同效果

紀錄 Reflection 的作法

City Class
namespace ReflectionProperty
{
    public class City
    {
        public int CityId { get; set; }
        public string CityName { get; set; }
    }
}
Program.cs Code
using System.Reflection;

namespace ReflectionProperty
{
    class Program
    {
        static void Main(string[] args)
        {
            // 抓 Type 的 3 種方法
            // 方法1:System.Object.GetType()
            City c = new City();
            Type t = c.GetType();

            // 方法2:Type.GetType()
            Type t = Type.GetType("ReflectionProperty.City");

            // 方法3: Typeof()
            Type t = typeof(City);

            if (t == null)
            {
                Console.WriteLine("找不到 Type");
                return;
            }
            Console.WriteLine(string.Format("Type FullName:{0}",t.FullName));
            
            // 利用 Type.GetProperties() 來抓 Property
            PropertyInfo[] pis = t.GetProperties();
            foreach (PropertyInfo pi in pis)
            {
                Console.WriteLine(string.Format("Property Name:{0}", pi.Name));
            }

        }
    }
}
[C#] Reflection - Property

星期二, 8月 18, 2015

[ZWCAD] 啟動問題

幫新電腦安裝 ZWCAD 時,註冊時發現,怎麼序號驗證後,竟然載入莫名其妙的公司資訊,直覺有問題,馬上 PrintScreen 存檔留下證據,Google 該公司行號,還真的存在,

ZWCAD 啟動問題

老大致電客服,客服也沒有給出很明確的解決方案,不知道使用一段時間後會發生甚麼事情,哈

星期日, 8月 16, 2015

[C#] 重複字元

閱讀該教學影片時 小山的 C# 教學-第13課-NumericUpDown,看見作者用雙迴圈產生星號時,原想說用 T-SQL Replicate() 函數就可以用單迴圈,沒想到 C# 沒有對應 Replicate() 的函數,Orz

Project 檔案
[C#] 重複字元-3

Winform 畫面
[C#] 重複字元-1

把 Relpicate() 函數寫成擴充事件來使用
namespace NumericUpDown
{
    public static class ExtChar
    {
        public static string Replicate(this char value , int count)
        {
            // 輸入負值或 0,就把 char 回傳
            count = Math.Max(count,1);
            return new string(value,count);
        }
    }
}
C# Code
namespace NumericUpDown
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnRun_Click(object sender, EventArgs e)
        {
            // numericUpDonw.Value property 回傳值是 decimal
            int count = (int)numericUpDown1.Value;
            // 輸入 0 或負值,就跑一次就好
            count = Math.Max(count, 1);

            char sign = '*' ;
            lblResult.Text = string.Empty;

            for (int i = 1; i <= count; i++)
            {
                lblResult.Text += string.Concat(sign.Replicate(i), Environment.NewLine);
            }
        }
    }
}
執行結果
[C#] 重複字元-2

一個突發奇想,讓自己的函式庫內又多一個擴充事件,^^

星期五, 8月 14, 2015

[C#] MaskedTextBox

實作這篇 MSDN 文章 逐步解說:使用 MaskedTextBox 控制項

[C#] MaskedTextBox-1

namespace maskedTextBoxMSDN
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // 設定西元簡單日期
            maskedTextBox1.Mask = "0000/00/00";
            // 發出系統警示音
            maskedTextBox1.BeepOnError = true;
            // 欲驗證資料型態
            maskedTextBox1.ValidatingType = typeof(DateTime);
            // 註冊事件
            maskedTextBox1.MaskInputRejected += maskedTextBox1_MaskInputRejected;
            maskedTextBox1.TypeValidationCompleted += maskedTextBox1_TypeValidationCompleted;
        }

        void maskedTextBox1_TypeValidationCompleted(object sender, TypeValidationEventArgs e)
        {
            if (e.IsValidInput) return;

            toolTip1.ToolTipTitle = "TypeValidationCompleted Event";
            toolTip1.Show(e.Message, maskedTextBox1, 5000);
            // 取消該事件,並把 focus 鎖定在 maskedTextbox
            e.Cancel = true;
        }

        void maskedTextBox1_MaskInputRejected(object sender, MaskInputRejectedEventArgs e)
        {
            toolTip1.ToolTipTitle = "MaskInputRejected Event";
            toolTip1.Show(e.RejectionHint.ToString(), maskedTextBox1, 5000);
        }
    }
}

測試 1:空值
[C#] MaskedTextBox-2

測試 2:嘗試輸入中文
[C#] MaskedTextBox-3

測試 3:輸入無效日期
[C#] MaskedTextBox-4

星期日, 8月 09, 2015

[C#] MonthCalendar

了解 WinForm 內鍵的 MonthCalendar 時,發現該控件使用彈性不高。
  • MSDN Windows XP 視覺化樣式 說明
視覺化樣式是指控制項外觀的規格。 例如,視覺化樣式可定義控制項的色彩、大小和字型。 視覺化樣式可以讓您設定視覺化介面,與應用程式介面協調。 此外,它們還會提供一項機制,讓所有 Windows 架構應用程式都能套用視覺化樣式。
根據預設,Windows XP 會提供一種新的視覺化樣式。 當 Windows Form 在 Windows XP 中執行時,表單上的捲軸和標題列都會自動使用新的視覺化樣式。 如果應用程式呼叫 EnableVisualStyles 方法,而且應用程式是在 Windows XP 中執行,則大部分的 Windows Form 控制項都會自動使用這個視覺化樣式。
  • 開啟/關閉 Windows XP 視覺化樣式
[C#] MonthCalendar-0
  • 問題點 1:關閉 XP 視覺化,顏色相關設定才會出現,左圖關閉、右圖開啟
[C#] MonthCalendar-1
  • 問題點 2:開啟 XP 視覺化,MinDate 和 MaxDate 設定值,才會被凸顯,左圖關閉、右圖開啟
[C#] MonthCalendar-2
問題點 1、2 剛好相斥,哈

星期五, 8月 07, 2015

[SQL] 錯誤訊息 8623

一大早開 mail 就被嚇到,這是甚麼錯誤訊息,Orz

錯誤訊息 8623-1
錯誤訊息
The query processor ran out of internal resources and could not produce a query plan. This is a rare event and only expected for extremely complex queries or queries that reference a very large number of tables or partitions. Please simplify the query. If you believe you have received this message in error, contact Customer Support Services for more information.
根據這篇官方文章  FIX: Error message when you run a complex query after you install Cumulative Update 3 or Cumulative Update 4 for SQL Server 2005 Service Pack 2: "The query processor ran out of internal resources and could not produce a query plan" ,是說明 SP2 的 CU3 或 CU4 就已經修正,我們是 SP4 了,Orz

錯誤訊息 8623-2

2009 年的 Connect 回報,The query processor ran out of internal resources and could not produce a query plan with WHERE in and several thousand values,根據官方回答,看來是要無解啦

後來詢問同事(就兩個人寫 ERP,很容易找出兇手,哈),同事有提到是用 UNION ALL 去串接資料產生這個錯誤訊息,發現後就馬上改掉 T-SQL 語法,雖然跟查到資料的方向都不太一樣,但看來這個 Error 應該是不會在出現才對

星期四, 8月 06, 2015

[Win] 檔案關聯

同事跑來說 PC 中毒啦,要我趕快去看,當下聽到中毒,是一整個囧,聽完案發事件的前因後果,鬆了一口氣,^^ ~~

同事間利用 Skype 傳送檔案,但沒有傳實際檔案,而是傳檔案捷徑過來,接收者打開該捷徑後,發現無法開啟且全部程式,竟然都無法執行,其實是全部的捷徑,通通都用 Adobe Reader 來開啟,可能該捷徑是 PDF 的關係吧,請教 Google 大神就發現到,這還不是單一事件,網路上也有相同案例,解決方式是要解除捷徑的檔案關聯
利用 A Utility to Unassociate File Types in Windows 7 and Vista 這套小軟體來解除關聯,在搜尋視窗內輸入 lnk 後,再按 "Remove File association (User)" 按鈕就行

不用重開機就回復正常