星期四, 7月 30, 2015

[C#] 使用者控制項 Part2

在 MSDN 發現這篇 2002 年文章 Creating a Windows Form User Control,動手實作並把文章內的 Code 整理起來

[C#] 使用者控制項 Part2-1

星期五, 7月 17, 2015

[C#] 自訂控制項內的事件

練習撰寫自訂控制項時發現沒有辦法在 Winform 上呼叫自訂控制項內控件的事件,找些資料才發現,必須自行撰寫事件來觸發

方案內容

[C#] 自訂控制項內的事件-1

星期四, 7月 16, 2015

[Win] 準備回收

同事 PC (Win7 32bit)上發現有 DWG 檔案竟然無法刪除,每次刪除就會產生 "準備回收" 的進行畫面,但就是不會進行刪除,嘗試在 cmd 內用 del 指令刪除、重新開機後刪除也都是一樣的結果,Orz

準備回收-1

準備回收-2

把刪除取消,通常都會出現下面畫面

準備回收-3

最後是參考這篇討論,嘗試用 LockHunter 這套軟體,才發現到,該檔案被檔案總管 Lock 住,完全無法釋放出來

準備回收-4

Unlock 後就可正常刪除,Lock 住的原因不明

星期一, 7月 13, 2015

[SQL] 衍伸資料表欄位別名

看 MVA 課程時發現的 T-SQL 寫法

以往寫 T-SQL 有用到 Derived Tables 時,都是用下面這個例子的寫法為主,Alias 會寫在 ColumnName 後面,比較直覺
SELECT 
    orderyear, 
    COUNT(DISTINCT custid) AS cust_count
FROM 
    ( 
        SELECT 
            YEAR(orderdate) AS orderyear, -- Alias 寫在 ColumnName 後面
            custid 
        FROM Sales.Orders
    ) AS derived_year
GROUP BY orderyear;
MVA 課程中介紹的寫法,寫在整個 Derived Tables ColumnName 中
SELECT 
    orderyear, 
    COUNT(DISTINCT custid) AS cust_count
FROM 
    ( 
        SELECT 
            YEAR(orderdate),  -- 不在欄位後面取 Alias
            custid
        FROM Sales.Orders
    ) AS derived_year(orderyear, custid) -- 寫在整個 Derived Tables ColumnName 中
GROUP BY orderyear;
原以為是 SQL Server 2012 的新語法 EXEC WITH Result Set 相關,但實際在 2005 上測試也是 OK 的

星期六, 7月 11, 2015

[C#] Form 傳值

論壇問題:要在 Form 之間傳值,拿來練習

Project 內容


frmMain layout


frmCustSearch layout


Customer Class
namespace WindowsFormsApplication1
{
    public class Customer
    {
        public int CustID { get; set; }
        public string CustName { get; set; }
        public string Address { get; set; }
    }
}
frmMain C# Code
namespace WindowsFormsApplication1
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        private void frmMain_Load(object sender, EventArgs e)
        {

        }

        private void btnCustSearch_Click(object sender, EventArgs e)
        {

            ClearControlValue();

            frmCustSearch CustSearch = new frmCustSearch();
            if (CustSearch.ShowDialog() != DialogResult.OK)
                return;

            var customer = CustSearch.RetValue;
            txtCustID.Text = customer.CustID.ToString();
            txtCustName.Text = customer.CustName;
            txtAddress.Text = customer.Address;
        }

        void ClearControlValue()
        {
            foreach (Control ctl in Controls.OfType<TextBox>())
            {
                if ((ctl is TextBox txt) == false)
                    continue;

                txt.Text = string.Empty;
            }
        }
    }
}
frmCustSearch C# Code
namespace WindowsFormsApplication1
{
    public partial class frmCustSearch : Form
    {
        public frmCustSearch()
        {
            InitializeComponent();
        }

        // 紀錄使用者點選的是哪一筆資料
        public Customer RetValue { get; set; }

        private void frmCustSearch_Load(object sender, EventArgs e)
        {
            dgvCustomer.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            btnOK.Click += btn_Click;
            btnCancel.Click += btn_Click;
            dgvCustomer.DataSource = DataGridViewSource();
            dgvCustomer.ClearSelection();
        }

        List<Customer> DataGridViewSource()
        {
            return
                new List<Customer>()
                    {
                        new Customer() { CustID = 1, CustName = "客戶1", Address = "台北" },
                        new Customer() { CustID = 2, CustName = "客戶2", Address = "台中" },
                        new Customer() { CustID = 3, CustName = "客戶3", Address = "高雄" }
                    };
        }

        void btn_Click(object sender, EventArgs e)
        {
            Button btn = sender as Button;
            if (btn == null) 
                return;

            DialogResult result = DialogResult.OK;

            if (RetValue == null || 
                btn.Name == btnCancel.Name)
                result = DialogResult.Cancel;

            DialogResult = result;

            Close();
        }

        private void dgvCustomer_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            RetValue = new Customer()
            {
                CustID = (int)dgvCustomer.CurrentRow.Cells[ColCustID.Name].Value,
                CustName = (string)dgvCustomer.CurrentRow.Cells[ColCustName.Name].Value,
                Address = (string)dgvCustomer.CurrentRow.Cells[ColAddress.Name].Value
            };
        }
    }
}
結果

星期三, 7月 08, 2015

[C#] 判斷 Image 圖片

論壇問題,需求是
當圖片是 A 就要顯示 B,圖面是 B 就顯示 A
把 Black 和 White 兩張圖片放進 Resources 內

[C#] 判斷 Image 圖片-2

圖片放進 PictureBox.Image 後就沒有辦法分辨是哪張圖片,所以在 PictureBox.Image.Tag 內駐記目前是哪張圖片
namespace ImageJudge
{
    public partial class Form1 : Form
    {
        private void Form1_Load(object sender, EventArgs e)
        {
            for (int i = 1; i <= 20; i++)
            {
                PictureBox pic = new PictureBox();
                pic.Name = string.Format("Pic{0}",i);

                // 預設是黑色背景
                pic.Image = Properties.Resources.Black ;
                // 把判斷條件放在 Tag Property 內
                pic.Image.Tag = "Black";
                pic.Click += pic_Click;

                // 每五張圖片就換行
                if (i % 5 == 0)
                    flowLayoutPanel.SetFlowBreak(pic, true);

                flowLayoutPanel.Controls.Add(pic);
            }
        }

        void pic_Click(object sender, EventArgs e)
        {
            PictureBox pic = sender as PictureBox;
            if (pic == null) return ;
            
            // 根據 Tag Property 來判斷目前圖片是哪張
            if (pic.Image != null && pic.Image.Tag.ToString() == "Black")
            {
                pic.Image = Properties.Resources.White;
                pic.Image.Tag = "White";
            }
            else
            {
                pic.Image = Properties.Resources.Black;
                pic.Image.Tag = "Black";
            }
        }
    }
}

[C#] 判斷 Image 圖片-1

星期一, 7月 06, 2015

[VFP] Microsoft Common Dialog

VFP 的 GetFile() 函數只能一次選擇一個檔案,因此改用 Microsoft Commom Dialog ActiveX 來達到可以多選檔案,在測試環境都 OK,直到放上正式環境才發現出線下面錯誤訊息:Class is not licensed for use


一看見這個錯誤訊息,直覺是想說這個 ActiveX 竟然還要有 License 驗證才可以用,有這麼神嗎,後來參考這篇文章 License error with ActiveX control added at run-time 把 Commom Dialog 包進自訂控件來使用,才避開這個問題


Commom Dialog ActiceX 使用方式
loCD = Createobject("IC_OCX.Comdlg32")
loCD.OleControl.Flags = 0x00080204 && 設定檔案多選
loCD.OleControl.Filter = "JPG|*.JPG"
loCD.OleControl.maxFileSize = 10000 && 該參數一定要存在,要不然會出現 Error
loCD.OleControl.InitDir = "C:\" 
loCD.OleControl.ShowOpen()
loCD.OleControl.FileName
特別要注意的是 Common Dialog 多選檔案後,FileName 內的值是用 CHR(0) 來分開每個檔案名稱,EX:在路徑 C:\ 內選擇 1.JPG 2.JPG 檔案,FileName 值會是 C:\ CHR(0) 1.JPG CHR(0) 2.JPG,單選檔案 FileName 值就是正常路徑,EX:C:\1.JPG

利用下面語法把多選檔案 FileName 值 show 出來觀察
MESSAGEBOX(CHRTRAN(loCD.OleControl.FileName, CHR(0), CHR(13)))