星期二, 12月 30, 2014

[C#] 根據 TextBox 顯示 Combobox

論壇問題
combobox 如果用點選的話是沒問題的,但如果需要用輸入text就去抓相對應的value,我應該怎麼寫呢?假設 value 有: 1-水壺 2-鉛筆 3-電腦,我在輸入 1 的時候 combobox 會出現 "1-水壺" 並取得相關的 value,而不用打開下來選單來選擇該選項。
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            comboBox1.Items.Add("1-水壺");
            comboBox1.Items.Add("2-鉛筆");
            comboBox1.Items.Add("3-電腦");
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            string target = textBox1.Text;
            if (string.IsNullOrEmpty(target)) return;

            comboBox1.Text = string.Empty;
            string comboText = string.Empty;
            foreach (string item in comboBox1.Items)
            {
                comboText = item.ToString();
                if (comboText.Substring(0, target.Length) != target) continue;
                comboBox1.Text = comboText;
                break;
            }
        }
    }
}
[C#] 根據 TextBox 顯示 Combobox

星期一, 12月 29, 2014

[Azure] VM - 新增資料磁碟

在 Windows Azure VM 上掛載資料硬碟,模擬 VM 硬碟空間不足時,需要額外的硬碟空間存防資料,記錄參與 2014 Wndows Azure 開發訓練營和閱讀網路資料的筆記。

建立 VM 後,可以從下圖中看見 C 為 OS,D 為 Temporary Storage,只提供資料暫存,VM 關機或重新啟動,資料就可能會遺失,因此必須建立虛擬硬碟 (vhd),並掛載到 VM 上,才具備保存資料的功能,另 VM 掛載資料硬碟數量,會根據開 VM 的等級而有所限制,EX:A1 只能掛載 1 顆,限制請參考官方網站規格說明

[Azure] VM - 新增空白磁碟-0

星期二, 12月 23, 2014

[Azure] VM - 啟用 IIS

在已建立好的 VM 上安裝 IIS 並開啟 HTTP 80 Port 來連接 IIS,記錄參與 2014 Wndows Azure 開發訓練營的筆記。

在 VM 上安裝 IIS,Manage => Add Role and Features

[Azure] VM - 啟用 IIS-1
Step by Step 的過程中,在 Server Roles 勾選 Web Server(IIS)

星期一, 12月 22, 2014

[ADO.NET] 彙總函數練習

練習 ADO.NET 彙總函數的使用 ~~
namespace AggDeno
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        DataTable dtAgg = new DataTable();
        DataTable dtDataTable = new DataTable();
        private void Form1_Load(object sender, EventArgs e)
        {
            dtFill();
        }

        private void dtFill()
        {
            dtAgg.Columns.Add("Alias", typeof(string));
            dtAgg.Columns.Add("Data",typeof(decimal));
            dtAgg.Rows.Add("EG-2A",369);
            dtAgg.Rows.Add("EG-2A",344);
            dtAgg.Rows.Add("IA1-1X", 322.88);
            dtAgg.Rows.Add("IA1-1X", 0.335);
            dtAgg.Rows.Add("IQ1-4X", 0.225);
            dtAgg.Rows.Add("IQ1-4X", 3.6);
            dtAgg.Rows.Add("IQ1-4X", 222.5);
            dgvData.DataSource = dtAgg;

            // Clone() 複製原 DataTable Schema
            // Copy()  複製原 DataTable Schema 和 Data
            dtDataTable = dtAgg.Clone();
            dgvDataTable.DataSource = dtDataTable;
        }

        private void btnADO_Click(object sender, EventArgs e)
        {
            dtDataTable.Rows.Clear();

            // 利用 ToTable() 找出 Alias 唯一值
            DataTable dtLoop = dtAgg.DefaultView.ToTable(true, "Alias");

            string filter = string.Empty;
            string Alias = string.Empty;
            foreach (DataRow dr in dtLoop.Rows)
            {
                Alias = dr["Alias"].ToString();

                DataRow drNew = dtDataTable.NewRow();
                drNew["Alias"] = Alias;
                filter = string.Format("Alias = '{0}'", Alias);
                drNew["Data"] = dtAgg.Compute("AVG(Data)", filter);
                dtDataTable.Rows.Add(drNew);
            }
        }

        private void btnDataTableLINQ_Click(object sender, EventArgs e)
        {
            dtDataTable.Rows.Clear();

            IEnumerable<string> loop = dtAgg.AsEnumerable().Select(Row => Row.Field<string>("Alias")).Distinct();

            foreach (string Alias in loop)
            {
                decimal avg = dtAgg.AsEnumerable().Where(dr => dr.Field<string>("Alias") == Alias).Average(dr => dr.Field<decimal>("Data"));

                DataRow drNew = dtDataTable.NewRow();
                drNew["Alias"] = Alias;
                drNew["Data"] = avg;
                dtDataTable.Rows.Add(drNew);
            }
        }

        private void btnLINQ_Click(object sender, EventArgs e)
        {

            var result = dtAgg.AsEnumerable().GroupBy(datarow => datarow.Field<string>("Alias")).Select(g => new { Alias = g.Key , AVG = g.Average(a => a.Field<decimal>("Data"))}).ToList();

            dgvLINQ.DataSource = result;
        }
    }
}
[C#] 彙總函數練習

星期三, 12月 17, 2014

貼紙

研討會中按讚的贈品 - 小光貼紙

貼紙

星期二, 12月 16, 2014

[Azure] VM - 建立 Windows 虛擬機器

在 Windows Azure 上快速建立出一個 Windows VM 來使用,記錄參與 2014 Wndows Azure 開發訓練營和閱讀 MVA 上影片的筆記。

新增

[Azure] VM - 建立 Windows 虛擬機器-1

計算 => 虛擬機器 => 快速建立,設定相關資訊;假如是從 "組件庫" 來建立的話,可以設定進階選項。
  • DNS 名稱:VM 對外的 DNS 名稱,必須是 Global Only
  • 影像:欲建立的作業系統
  • 大小:老師建議最少要到開標準 A2 以上,標準 A2 以下進入 VM 會非常緩慢
  • 使用者名稱:無法輸入 user、guest、、admin 和 administrator 這類常見的名稱,此為利用遠端桌面(RDP)連進 VM 的帳號
  • 密碼:必須滿足複雜密碼原則(所定義的密碼長度必須超過八個字元,且包含有小寫英文、大寫英文、數字及符號其中三種。)
  • 區域:東亞,機房位於香港,
  • 訂閱用戶:付款依據
[Azure] VM - 建立 Windows 虛擬機器-2

星期一, 12月 15, 2014

[C#] WebBrowser

整理上課筆記

一直覺的 WebBrowser 控件好像沒有甚麼實際用途,上課時老師有提到,實務上可以把 Web 上的最新消息,透過 WebBrowser 來顯示,這樣就不用設計 WinForm 版本介面
namespace WebBrowserDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // Form 上每個控件的 Anchor 設定
            lblURL.Anchor = AnchorStyles.Left | AnchorStyles.Top;
            txtURL.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;
            btnGO.Anchor = AnchorStyles.Top | AnchorStyles.Right;
            webBrowser1.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;

            // 顯示該電腦 IE 首頁並顯示在 txtURL 內
            webBrowser1.GoHome();
        }

        private void btnGO_Click(object sender, EventArgs e)
        {
            runURL();
        }

        private void txtURL_KeyUp(object sender, KeyEventArgs e)
        {
            // 使用者輸入完後,直接按 Entry 執行
            if (e.KeyCode == Keys.Enter) runURL();
        }

        private void runURL()
        {
            webBrowser1.Navigate(txtURL.Text);
        }

        private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            // 使用者操作 WebBrowser 內連結時,必須把點擊的 URL 傳回 txtURL 內顯示
            string url = webBrowser1.Url.ToString();
            if (string.IsNullOrEmpty(url)) return;
            txtURL.Text = url;
        }
    }
}

執行程式會顯示 IE 首頁

[C#] WebBrowser-1

利用 Google 搜尋 Blog,可以看見 txtURL 會顯示現在的網址

[C#] WebBrowser-2
[C#] WebBrowser-3

星期五, 12月 12, 2014

[SQL] Merge 應用

此範例同 [SQL] OUTPUT 語法,差別在於 OUPUT 與法是假如 StockQty 內產品一定存在,而 Merge 則是不一定存在,且庫存量為 0 時,必須把產品刪除,藉此練習 OUTPUT 和 Merge 語法

下列在 AdventureWorks 中利用產品(Production)、庫存量(StockQty)和入領料(Stock、StockDetail)來說明 Merge 語法
  • 建立基礎 Table 並插入 Sample Data
IF OBJECT_ID('StockQty') IS NOT NULL
  DROP TABLE StockQty
 
IF OBJECT_ID('Stock') IS NOT NULL
  DROP TABLE Stock

IF OBJECT_ID('StockDetail') IS NOT NULL
  DROP TABLE StockDetail
 
IF OBJECT_ID('Production') IS NOT NULL
  DROP TABLE Production

CREATE TABLE Production (ProdID int Primary key, ProdName nchar(50))
INSERT INTO Production VALUES(1,N'SQL Server 2014')
INSERT INTO Production VALUES(2,N'SQL Server 2012')
INSERT INTO Production VALUES(3,N'SQL Server 2008 R2')
INSERT INTO Production VALUES(4,N'SQL Server 2008')
INSERT INTO Production VALUES(5,N'SQL Server 2005')

-- StockQty 沒有任何資料,當 StockDetail 有資料時,
-- 會透過 Merge 語法來 insert、update 和 delete StockQty Table 內資料
CREATE TABLE StockQty (ProdID int Primary key, Qty int)

CREATE TABLE Stock (SID int Primary key, [Date] date)
CREATE TABLE StockDetail (SID int Primary key(SID,ProdID), ProdID int , Qty int)
GO

星期二, 12月 09, 2014

[ADO.NET] 計算 DataTable 資料筆數

論壇問題
從 Database 中把 DataTable 後,把重覆值去除掉後當成 comboBox 資料來源,希望點選 comboxBox 時,可以顯示該選項在 DataTable 內的資料筆數
想法是利用 T-SQL DISTINCT 語法找出唯一値當成 comboxBox 資料來源,再根據使用者點選資料,進入 Database 計算資料筆數,論壇討論則是把資料通通抓到 C# 中來處理,剛好拿來練習 ADO.NET
namespace ComboBoxSearch
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // dtCombo 為全域變數
        DataTable dtCombo = new DataTable("Demo");

        private void Form1_Load(object sender, EventArgs e)
        {
            // 資料來源建立
            sourceFill();

            // 設定 ComboBox 的 DropDownStyle 
            cboList.DropDownStyle = ComboBoxStyle.DropDownList;
            cboDataTable.DropDownStyle = ComboBoxStyle.DropDownList;
            // 設定 ComboBox 一開始不顯示任何選項
            cboList.SelectedIndex = -1;
            cboDataTable.SelectedIndex = -1;
            // 不允許 DataGridView 可以新增資料
            gvData.AllowUserToAddRows = false;
        }

        private void sourceFill()
        {
            // dtCombo Schema 和 Data 建立
            dtCombo.Columns.Add("ColName",typeof(string));
            dtCombo.Rows.Add("A");
            dtCombo.Rows.Add("A");
            dtCombo.Rows.Add("A");
            dtCombo.Rows.Add("B");
            dtCombo.Rows.Add("B");
            dtCombo.Rows.Add("C");
            dtCombo.Rows.Add("C");
            dtCombo.Rows.Add("C");
            dtCombo.Rows.Add("C");
            dtCombo.Rows.Add("D");
            dtCombo.Rows.Add("D");
            dtCombo.Rows.Add("D");
            dtCombo.Rows.Add("D");
            dtCombo.Rows.Add("D");

            // 資料來源為 List
            List<string> uniqueLINQ = dtCombo.AsEnumerable().Select(row => row.Field<string>("ColName")).Distinct().ToList();
            cboList.DataSource = uniqueLINQ;

            // 資料來源為 DataTable
            DataTable uniqueDataTable = dtCombo.DefaultView.ToTable(true, "ColName");
            cboDataTable.DataSource = uniqueDataTable;
            cboDataTable.ValueMember = "ColName";
            cboDataTable.DisplayMember = "ColName";

            // 把 dtCombo 資料顯示出來,方便比對資料
            gvData.DataSource = dtCombo;
        }

        private void gvData_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (!gvData.Columns[e.ColumnIndex].Name.Equals("ColName")) return;

            string item =
                cboList.SelectedIndex == -1
                ? string.Empty
                : cboList.SelectedItem.ToString();
   
            string value = 
                cboDataTable.SelectedIndex == -1
                ? string.Empty
                : cboDataTable.SelectedValue.ToString();

            e.CellStyle.BackColor = SystemColors.Control;
            if (e.Value.ToString() == item || e.Value.ToString() == value) 
              e.CellStyle.BackColor = Color.LightGray;
        }

        private void cboList_SelectionChangeCommitted(object sender, EventArgs e)
        {
            // LINQ 作法
            if (cboList.SelectedIndex == -1) return;
            string item = cboList.SelectedItem.ToString();

            string result = dtCombo.AsEnumerable().Where(row => row.Field<string>("ColName") == item).Count().ToString();

            txtList.Text = result;
            gvData.Refresh();
        }

        private void cboDataTable_SelectionChangeCommitted(object sender, EventArgs e)
        {
            // ADO.NET 作法
            if (cboDataTable.SelectedIndex == -1) return;
            string value = cboDataTable.SelectedValue.ToString();

            string filter = string.Format("ColName = '{0}'", value);
            string result = dtCombo.Compute("COUNT(ColName)", filter).ToString();

            txtDataTable.Text = result;
            gvData.Refresh();
        }
    }
}

練習時發現,當 Form 一執行時都會觸發 ComboBox SelectedIndexChanged 事件,在 MSDN ComboBox.SelectionChangeCommitted 事件,看見這段說明
只有當使用者變更下拉式方塊選擇時,才會引發 SelectionChangeCommitted。 請勿使用 SelectedIndexChanged 或 SelectedValueChanged 來擷取使用者變更,因為當以程式方式變更選擇時,也會引發這些事件。
ComboBox 預設點擊事件為 SelectedIndexChanged,所以也就很直覺地把 Code 寫在裡面,Orz ~~

星期一, 12月 08, 2014

[Word] 目錄

從 2003 開始就有的功能,到了 2013 終於實際操作 ~~ ^^'' ~~

Step1:設定標題

在 word 內輸入第一章,可以看見 Word 樣式是顯示 "內文"

目錄-1

全選 "第一章"字樣後,改設定為 "標題 1" 後,可以在第一章字樣前看見下圖綠色框框符號

目錄-2

在其他頁面上輸入第二章和第三章;第三章第一節、第三章第二節設定為 "標題 2 ",可以再導覽內看見設定的標題

目錄-3

設定標題時,理論上導覽功能寄會自動出現,沒有出現的話,請至檢視 => 勾選功能窗格,就可以叫出導覽功能

目錄-4

星期三, 12月 03, 2014

[C#] 使用者控制項

了解如何改寫使用者控制項時,在 MSDN 發現這篇文章 逐步解說:使用 Visual C# 撰寫使用者控制項,動手實作並把文章內的 Code 整理起來

實作這篇文章時最大的收穫是,原來要 override 時,VS 有快取的方式可以使用,之前看到範例,都會覺得怎麼這麼利害,Method 內的 Object Sender 和 EventArgs e 這兩個參數要怎麼知道,尤其是 EventArgs,不會都必須查詢 MSDN,然後再複制貼上到 VS 內吧,Orz ~~

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

[C#] 使用者控制項-2

星期二, 12月 02, 2014

[Win] iSCSI 目標伺服器 - MPIO

完成 iSCSI 目標伺服器和 iSCSI 啟動伺服器設定後,就可以進行檔案傳輸,從下圖的效能監視器內可以發現,雖然有設定都有設定兩張網路卡,但實際傳輸檔案時,還是只透過一張網路卡進行傳輸,要透過多張網路卡傳輸,還必須在 iSCSI 啟動伺服器上,設定 MPIO 功能
[Win] iSCSI 目標伺服器 -MPIO-1

星期三, 11月 26, 2014

星期二, 11月 25, 2014

[Win] iSCSI 目標伺服器 - Initiator

以下為利用 iSCSI 啟動器連接 iSCSI 目標筆記,該伺服器名稱為 iSCSIInitiator

Step 1:iSCSI  啟動器在 Windows Vista 和 Windows Server 2012 之後版本變成內鍵功能

[Win] iSCSI 目標伺服器 -Initiator-1

Step 2:執行 iSCSI 啟動器且該服務未啟動時,會有下列訊息出現

[Win] iSCSI 目標伺服器 -Initiator-2

Step 3:建立目標 192.168.3.1 並按 "快速連線" 按鈕

[Win] iSCSI 目標伺服器 -Initiator-3

Step 4:會顯示 iSCSI 目標的 IQN 並顯示登入成功,假如快速連線沒有找到 iSCSI 目標,請檢查 iSCSI 目標內的存取伺服器,是否有把嘗試存取 iSCSI 目標的伺服器加入存取清單內

[Win] iSCSI 目標伺服器 -Initiator-4

Step 5:重覆執行新增目標,把 192.168.3.2 也加入目標中,然後就可以在 探索 Tag 中看見,下圖目標入口資訊

[Win] iSCSI 目標伺服器 -Initiator-5

Step 6:到 iSCSI 啟動器內的 "磁碟區和裝置" tag,按下"自動設定",這樣就可以把 iSCSI Target 內的虛擬硬碟抓進來,因為只在 Target 內建立一顆虛擬硬碟,所以磁碟清單內只有一筆資料

[Win] iSCSI 目標伺服器 -Initiator-7

Step 7:到電腦管理中就可以看見該伺服器內多一顆硬碟,把它掛載,就可以正常使用該 iSCSI 目標

[Win] iSCSI 目標伺服器 -Initiator-6

星期一, 11月 24, 2014

[C#] 改變 GroupBox 內 Label 的背景顏色

技術論壇問題
groupBox 裡 放幾個label 想改變 label 的背景顏色
以往尋找物件都是利用 Controls.Find() 和 foreach 搭配 ofType<控件類型> 來找出控件並進行處理,在這個討論中發現,把欲尋找控件加入 List<控件類型> 中,再掃 List <控件類型>,也是一種處理方式,檢單筆記一下
namespace GroupLabel
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            cboSelect.DropDownStyle = ComboBoxStyle.DropDownList;
            for (int i = 1; i <= 10; i++)
            {
                string item = string.Format("Label{0}", i);
                cboSelect.Items.Add(item);
            }

            btnOdd.Click += btnClick;
            btnEven.Click += btnClick;
        }

        private void cboSelect_SelectedIndexChanged(object sender, EventArgs e)
        {
            // 利用 Control.Find 來尋找 Label 控件
            string target = cboSelect.SelectedItem.ToString();
            if (string.IsNullOrEmpty(target)) return;

            Control[] labels = gbLabel.Controls.Find(target, false);
            if (labels.Length == 0) return;
            if (!(labels[0] is Label)) return;

            Label lbl = labels[0] as Label;
            if (lbl == null) return;

            colorReset();
            lbl.ForeColor = Color.White;
            lbl.BackColor = Color.Red;
        }

        private void colorReset()
        {
            // 掃 gpLabel 內的 Label 控件
            foreach (Label lbl in gbLabel.Controls.OfType<Label>())
            {
                lbl.BackColor = SystemColors.Control;
                lbl.ForeColor = Color.Black;
            }
        }

        private void btnClick(object sender, EventArgs e)
        {
            // 把欲變色的 Label 控件,加入 List<Label> 中,掃 List<Label> 來進行變色
            string btnName = ((Button)sender).Name;

            List<Label> lstLabels = new List<Label>();
            if (btnName == "btnOdd")
            {
                lstLabels.Add(label1);
                lstLabels.Add(label3);
                lstLabels.Add(label5);
                lstLabels.Add(label7);
                lstLabels.Add(label9);
            }
            else
            {
                // btnName == "btnEven"

                lstLabels.Add(label2);
                lstLabels.Add(label4);
                lstLabels.Add(label6);
                lstLabels.Add(label8);
                lstLabels.Add(label10);
            }

            colorReset();
            foreach (Label lbl in lstLabels)
            {
                lbl.ForeColor = Color.White ;
                lbl.BackColor = Color.Red;
            }
        }
    }
}
[C#] 改變 GroupBox 內 Label 的背景顏色

星期五, 11月 21, 2014

[SQL] Sequence

MSDN Sequence 說明
建立順序物件,並指定其屬性。 順序是使用者定義之結構描述繫結的物件,該物件會根據建立順序所使用的規格產生數值序列。 數值序列會在定義的間隔依照遞增或遞減順序來產生,而且在用完時可設定為重新啟動 (循環)。 順序不會與特定資料表產生關聯,與識別欄位不同。 應用程式會參考順序物件,以擷取它的下一個值。 順序與資料表之間的關聯性是由應用程式所控制。 使用者應用程式可以參考順序物件,並協調跨越多個資料列和資料表的值。
  • 建立 Sequence 語法
[SQL] Sequence - 6
  • 預設值 Sequence
IF EXISTS(SELECT 1 FROM sys.sequences WHERE name = 'DefaultSeq')
    DROP SEQUENCE dbo.DefaultSeq

CREATE SEQUENCE dbo.DefaultSeq
[SQL] Sequence - 1
  • Sequence 物件設定值查詢語法
SELECT 
    S.Name AS N'順序物件',
    S.start_value AS N'起始值',
    S.increment AS N'遞增值',
    S.current_value AS N'目前值',
    T.name AS N'資料類型',
    S.minimum_value AS N'最小值',
    S.maximum_value AS N'最大值',
    S.is_cycling AS N'循環',
    S.is_cached AS N'快取',
    S.cache_size AS N'快取大小',
    S.create_date AS N'建立日期',
    S.modify_date AS N'修改日期',
    S.cache_size AS N'快取值'
FROM sys.sequences AS S 
    JOIN sys.types AS T ON S.system_type_id = T.system_type_id
[SQL] Sequence - 8

星期二, 11月 18, 2014

[Win] iSCSI 目標伺服器 - Target

以下為建立 iSCSI 目標筆記,該伺服器名稱為 iSCSITarget

Step 1:建立 "iSCSI 目標伺服器" 伺服器角色

[Win] iSCSI 目標伺服器 -Target-1

Step2:伺服器管理員 => 檔案和存放服務 => iSCSI => 工作 => 新增 iSCSI 虛擬磁碟

[Win] iSCSI 目標伺服器 -Target-2


星期一, 11月 17, 2014

[C#] 檔案系統監視

論壇問題上看見這個 FileSystemWatcher 這個功能,趕快找資料來了解並筆記

官方文件 - FileSystemWatcher 類別 備註說明
Windows 作業系統會在所建立的緩衝區中通知您檔案變更的元件 FileSystemWatcher 。 如果短時間內有許多變更,緩衝區可能會溢位。 這會導致元件無法追蹤目錄中的變更,而且只會提供總通知。 使用屬性來增加緩衝區的大小 InternalBufferSize 會很昂貴,因為它來自無法交換至磁片的非分頁式記憶體,因此請將緩衝區保持在夠大的小,而不會遺漏任何檔案變更事件。 若要避免緩衝區溢位,請使用 NotifyFilter 和 IncludeSubdirectories 屬性,讓您可以篩選掉不必要的變更通知。
Code 
using System;
using System.IO;
using System.Windows.Forms;

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

        private void Form1_Load(object sender, EventArgs e)
        {
            txtLog.Multiline = true;
            txtLog.Dock = DockStyle.Bottom;

            // 預設監視資料夾
            txtPath.Text = @"D:\WatchDemo";

            // 檔案篩選選項
            cboExtension.Items.Add("");
            cboExtension.Items.Add("*.txt");
            cboExtension.Items.Add("*.jpg");
            cboExtension.Items.Add("*.docx");
            cboExtension.Items.Add("*.xlsx");

            // 預設篩選的副檔名
            cboExtension.Text = "*.txt";
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fbd = new FolderBrowserDialog();

            // 預設開啟位置為使用者桌面
            fbd.RootFolder = Environment.SpecialFolder.Desktop;
            if (fbd.ShowDialog() != DialogResult.OK || string.IsNullOrEmpty(fbd.SelectedPath))
                return;

            txtPath.Text = fbd.SelectedPath;
        }

        private void btnRun_Click(object sender, EventArgs e)
        {
            string path = txtPath.Text;
            if (string.IsNullOrEmpty(path))
                return;

            FileSystemWatcher fsw = new FileSystemWatcher();

            //設定監視資料夾
            fsw.Path = path;

            // 是否包含子目錄,預設為 true
            fsw.IncludeSubdirectories = true;

            // 設定篩選條件
            string extension = cboExtension.Text;
            if (!string.IsNullOrEmpty(extension))
                fsw.Filter = extension;

            // 設定監視檔案變化類型
            fsw.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite;

            // FileSystemWatcher 偵測事件是否啟動,預設為 true
            fsw.EnableRaisingEvents = true;

            // 事件觸發時,藉由 delegate 引用 WatchMessage 方法
            fsw.Deleted += WatchMessage;
            fsw.Changed += WatchMessage;
            fsw.Created += WatchMessage;
            fsw.Renamed += WatchMessage;
        }

        private void WatchMessage(object sender, FileSystemEventArgs e)
        {
            string message = $"檔案 {e.FullPath} 被 {e.ChangeType}";
            txtLog.Text += message + Environment.NewLine;
        }

    }
}

星期三, 11月 12, 2014

[HyperV] VM 上新增虛擬硬碟

準備練習 iSCSI 目標伺服器時,想在 Target Server 上再多掛上一顆硬碟來使用,下面為筆記紀錄

在 Hyper-V 管理員內,選擇要新增虛擬硬碟的 VM(iSCSCTarget)=> IDE 控制器 0 => 硬碟 => 新增

[HyperV] VM 上新增虛擬硬碟-0

在該 VM IDE 控制器 0 清單內可以看見多出一顆硬碟 => 新增虛擬硬碟

[HyperV] VM 上新增虛擬硬碟-1


星期二, 11月 11, 2014

[Win] iSCSI 目標伺服器

Windows Server 2012 R2 伺服器資料安全管理 學習時,老師有 Demo iSCSI 目標伺服器這個主題,自己找些資料來了解並時作練習一下
理解這些內容,就可以完成 iSCSI Target + MPOI + 容錯功能,以下為自己練習環境的簡易說明
伺服器名稱網路卡 IP 位置
iSCSITarget192.168.3.1、192.168.3.2
iSCSIInitiator192.168.3.3、192.168.3.4

星期一, 11月 10, 2014

[C#] 拖放應用 - ListBox

在論壇上看見這篇文章 如何提供視覺 C# 應用程式中的檔案拖放功能,才想到之前練習時,並沒有真的了解 DragEnter 內的 Code,代表甚麼意義,趁這個機會了解一下,並延伸這篇文章,拖曳物件假如是資料夾,必須把資料夾內的檔案也列出
using System.IO;

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

        private void DragDropList_Load(object sender, EventArgs e)
        {
            listBox.AllowDrop = true;
            listBox.Dock = DockStyle.Fill;
        }

        private void listBox_DragEnter(object sender, DragEventArgs e)
        {
            // 判斷物件是否可以拖曳進入控件,EX:垃圾桶無法拖曳進入控件,
            // 拖曳過程中可以在控件上透過圖示來顯示該物件是否可以進行拖曳
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                // 控件上會出現 + 圖示,DragDrop 才會被觸發
                e.Effect = DragDropEffects.All;
            else
                // 控件上會出現禁止圖示,DragDrop 不會被觸發
                e.Effect = DragDropEffects.None;
        }

        private void listBox_DragDrop(object sender, DragEventArgs e)
        {
            // 避免重覆操作,無法正確顯示結果
            listBox.Items.Clear();
            // GetData() 回傳 string[],內容為物件路徑,允許使用者一次拖曳多個物件
            string[] entriesPath = (string[])e.Data.GetData(DataFormats.FileDrop,false) ;
            foreach (string entryPath in entriesPath)
            {
                listBox.Items.Add(entryPath);
                dirFiles(entryPath);
            }   
        }

        private void dirFiles(string _entryPath)
        {
            DirectoryInfo dirInfo = new DirectoryInfo(_entryPath);
            if (dirInfo.Exists == false) return;

            // DirectoryInfo.GetFileSystemInfos() 會回傳 Directory 和 File 兩種類型檔案,
            // 相當於執行 DirectoryInfo.GetFiles 和 DirectoryInfo.GetDirectories
            foreach (FileSystemInfo info in dirInfo.GetFileSystemInfos())
            {
                listBox.Items.Add(info.FullName);
                dirFiles(info.FullName);
            }
        }
    }
}
[C#] 拖放應用 - ListBox

星期五, 11月 07, 2014

[SQL] 利用 sqlcmd 來執行 T-SQL script

利用 sqlcmd 來執行 TSQL script,這個方法最廣泛的應用,莫過於在 SQL Express 排程備份資料庫
  • 遠端連線
要利用 sqlcmd 連接 SQL Server instance,必須先開啟 Express 版本的遠端連線(預設關閉)
  • T-SQL Script
在 Script 內下 T-SQL 語法來進行資料庫備份、交易紀錄備份,並設定好備份檔案名稱
DECLARE @date char(8) = CONVERT(char(8),getdate(),112)
DECLARE @bakpath varchar(100) = CONCAT('D:\AdventureWorks2012-',@date,'.bak')
BACKUP DATABASE [AdventureWorks2012] TO DISK = @bakpath
  • sqlcmd
參數說明:
  1. -S:指定要連接的 SQL Server 執行個體
  2. -i:識別包含 SQL 陳述式或預存程序的批次之檔案
在命令提示字元中測試,輸入
sqlcmd -S win7-jengting\sql2012 -i C:\TSQL.sql
執行畫面如下

[SQL] 利用 sqlcmd 來執行 T-SQL script-1
  • Windows 排程
新增 txt 檔案,內容為上述 sqlcmd 執行 TSQL 語法,輸入後把副檔名的 txt 改為 bat 檔案,並在 Windows 上設定排程來執行該 bat 檔案,重要步驟如下(下圖為 Win7 排程設定畫面)

Windows 7 工作排程 => 新增工作 => 一般 tag => 輸入排程名稱

[SQL] 利用 sqlcmd 來執行 T-SQL script-2

觸發程序 tag => 新增 button (觸發程序就是排程時間設定)

[SQL] 利用 sqlcmd 來執行 T-SQL script-3

動作 tag => 新增 button => 程式或指令碼,請選擇之前建立的 TSQLbat 檔案

[SQL] 利用 sqlcmd 來執行 T-SQL script-4

手動執行就可以看見備份出來的 bat 檔案

[SQL] 利用 sqlcmd 來執行 T-SQL script-5

星期三, 11月 05, 2014

[Win] 重覆資料刪除

Windows Server 2012 R2 伺服器資料安全管理 學習時,老師有 Demo 重覆資料刪除這個主題,自己找些資料來了解並時作練習一下

Step 1 :新增 "重覆檔案刪除" 伺服器角色

[Win] 重覆刪除資料-1

Step 2:磁碟區 => 磁碟 => 選擇磁碟區 => 滑鼠右鍵 => 設定重覆資料刪除

[Win] 重覆刪除資料-2

Step 3:
  • 重覆資料刪
    1. 一般用途的檔案伺服器:就ㄧ般用途,^_^''
    2. Virtual DeskTop Infrastructure(VDI)伺服器:HyperV 用,重覆刪除資料比率會比一般用途更高
  • 可以設定排除刪除的副檔名
  • 排除設定重覆刪除磁碟內的資料夾
  • 設定排程:重覆資料刪除並不是檔案一放進磁碟內就會判斷是否重覆,必須透過排程定期定時去檢查並刪除資料
[Win] 重覆刪除資料-3

此為排程設定畫面

[Win] 重覆刪除資料-4

 Step 4:設定完成後,可以在工作排程中看見重覆資料刪除排程

[Win] 重覆刪除資料-5

Step 5:檢查該磁碟區可以看見重覆刪除相關資訊

[Win] 重覆刪除資料-6

星期一, 11月 03, 2014

[C#] FlowLayoutPanel

之前練習動態物件加入 container 時,最令人討厭的,莫過於要計算控件位置,現在才發現 Winform 有 FlowLayoutPanel 控件可以解決計算位置這個問題,這篇就利用 FlowLayoutPanel 來作每 5 個控件一欄的練習,並把 CheckedChanged 事件進行註冊,當點選 CheckBox 時,必須顯示現在勾選哪一個 CheckBox

FlowLayoutPanel MSDN 說明
FlowLayoutPanel 控制項會以水平或垂直流向來排列它的內容。 其內容可以從某一資料列換行至下一個資料列,或從某一資料行換行至下一個資料行。 此外,也可裁剪該內容而不換行。
namespace FlowLayoutPanelDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // 使用者輸入預設值
            numInput.Value = 10;
            // FlowDirection 預設值為 LedtToRight 
            flowDemo.FlowDirection = FlowDirection.TopDown;
            // WrapContents 預設值為 true
            flowDemo.WrapContents = true;
            // 設定 FlowLayoutPanel 具有 Scroll 功能
            flowDemo.AutoScroll = true;
        }

        private void btnRun_Click(object sender, EventArgs e)
        {
            decimal count = numInput.Value;
            if (count <= 0) return;

            // 避免重覆操作,無法顯示正確結果
            flowDemo.Controls.Clear();

            for (int i = 1; i <= count; i++)
            {
                CheckBox cb = new CheckBox();
                cb.Name = "cb" + i;
                cb.Text = "cb" + i;
                cb.CheckedChanged += cb_CheckedChanged;

                // 預設是碰到 FlowLayoutPanel Border 時會自動折行
                // 在這改用每 5 個控件就進行折行
                if (i % 5 == 0)
                    flowDemo.SetFlowBreak(cb, true);

                flowDemo.Controls.Add(cb);
            }
        }

        void cb_CheckedChanged(object sender, EventArgs e)
        {
            lblMessage.Text = string.Format("{0} 正被勾選", ((CheckBox)sender).Name);
        }
    }
}
[C#] FlowLayoutPanel

星期三, 10月 29, 2014

[Win] 陰影複製

紀錄 Windows Server 2012 R2 的陰影複製設定

陰影複製說明:
  • 存取舊版本資料和救回刪除檔案
  • 可以排程定期追蹤磁碟上的檔案異動
  • 不能用來取代備份
圖一:陰影複製是針對磁碟進行設定,選定目標磁碟

圖二:按下啟用按鈕

圖三:陰影複製注意事項,不適合 I / O 負載較高的伺服器

圖四:啟用後會馬上進行陰影複製,也有 "立即建立" 按鈕,可以手動建立

圖五:圖二中的設定按鈕,可以指定陰影複製存放位置和最大容量

圖六:圖五中的排程按鈕,預設排程一天兩次,分別為 0700 am 和 1200 pm

圖七:啟動陰影複製前,已在 C 磁碟中建立 ShadowDemo 資料夾,資料夾中有檔案 1、檔案 2 兩檔案,為了測試陰影備份,對檔案 1 內容進行修改並刪除檔案 2

針對檔案 1 可以在內容的 "以前的版本" 看見可用備份

已刪除的檔案 2,因為沒有檔案存在,可以在資料夾中的 "以前的板本" 中,把檔案 2 救回來,還原會回復整個資料夾,複製可以把整個資料夾還原到指定位置

檔案 1 和 檔案 2 就救回來啦