2017/12/17

[C#] DateGridView 使用 DateTimePicker 輸入日期

使用DateGridView常常遇到需要輸入日期的情境,對使用者來說DateTimePicker是很直覺的輸入方式
但是原始的DateGridView並不支援DateTimePicker的使用,以往為了解決這個問題,我都是參考微軟
的這一篇 https://msdn.microsoft.com/zh-tw/library/7tas5c80.aspx 進行修改
最近看到這一篇 https://dotblogs.com.tw/danking/2014/11/13/147294 讓我興起改寫
DateGridView的想法。

對於改寫控制項還不是很了解要如何使用在專案的人,可以參考我的另一篇文https://nonfu.blogspot.tw/2017/11/c-checkbox.html

public partial class DataGridViewEx:System.Windows.Forms.DataGridView
{
  // 紀錄可編輯的欄位名稱
  private StringDictionary ColmmEdit;

  // 紀錄要使用日期資料的欄位名稱
  private StringDictionary ColmmDate;

  public DataGridViewEx() : base()
  {
    this.EditMode = DataGridViewEditMode.EditProgrammatically;
    if (!DesignMode)
    {
      ColmmEdit = new StringDictionary();
      ColmmDate = new StringDictionary();
      this.Disposed += DataGridViewEx_Disposed;
      this.CellClick += DataGridViewEx_CellClick;
      this.EditingControlShowing += DataGridViewEx_EditingControlShowing;          
     }
  }

  // 刪除資料清單
  private void DataGridViewEx_Disposed(object sender, EventArgs e)
  {
    if (!DesignMode)
    {
      ColmmEdit.Clear();
      ColmmDate.Clear();
    }
  }
       
  // 設定可編輯的欄位
  public void SetColmmEditName(string NameValue)
  {
    if(!ColmmEdit.ContainsKey(NameValue))
    {
      ColmmEdit.Add(NameValue, NameValue); 
    }
  }

  // 設定要使用DateTimePicker的欄位
  public void SetColmmDateName(string NameValue)
  {
    if (!ColmmDate.ContainsKey(NameValue))
    {
      ColmmDate.Add(NameValue, NameValue);
    }
  }

  // 檢查欄位是否可以編輯
  private void DataGridViewEx_CellClick(object sender, DataGridViewCellEventArgs e)
  {
    if ((e.RowIndex > -1) || (e.ColumnIndex > -1))
    {

      if (ColmmEdit.ContainsKey(this.Columns[e.ColumnIndex].Name))
      {
        this.BeginEdit(true);
      }
      else
      {
        this.EndEdit();
      }

    }
  }

  // DateTimePicker的日期資料回寫欄位
  private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
  {
    this .CurrentCell.Value = ((DateTimePicker)sender).Value.ToString("yyyy/MM/dd");
  }

  // 判斷是否適用DateTimePicker的欄位
  private void DataGridViewEx_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
  {
    if (this.CurrentCell.ColumnIndex > -1)
    {
      Control parentCTL = e.Control.Parent;

      if(ColmmDate.ContainsKey(this.Columns[this.CurrentCell.ColumnIndex].Name))
      {
        DateTimePicker dtPicker = new DateTimePicker();
        dtPicker.Name = "dateTimePicker1";
        dtPicker.Size = this .CurrentCell.Size;
        dtPicker.Format = DateTimePickerFormat.Custom;
        dtPicker.CustomFormat = "yyyy/MM/dd";

        dtPicker.Location = new Point(
                                      e.Control.Location.X - e.Control.Margin.Left < 0 ? 0 : e.Control.Location.X - e.Control.Margin.Left,
                                      e.Control.Location.Y - e.Control.Margin.Top < 0 ? 0 : e.Control.Location.Y - e.Control.Margin.Top);

        if (e.Control.Text != "")
        {
          dtPicker.Value = DateTime.ParseExact(e.Control.Text, dtPicker.CustomFormat, null);
        }
        else
        {
          dtPicker.Value = DateTime.Now;
          this.CurrentCell.Value = dtPicker.Value.ToString("yyyy/MM/dd");
        }

        e.Control.Visible = false;

        foreach (Control tmpCTL in parentCTL.Controls)
        {
          if (tmpCTL.Name == dtPicker.Name) parentCTL.Controls.Remove(tmpCTL);
        }

        parentCTL.Controls.Add(dtPicker);
        dtPicker.ValueChanged += new EventHandler(dateTimePicker1_ValueChanged);              
      }
      else
      {
        foreach (Control tmpCTL in parentCTL.Controls)
        {
          if (tmpCTL.Name == "dateTimePicker1")
          {
           parentCTL.Controls.Remove(tmpCTL);
          }
        }
      }
    }
  }
}

2017/11/29

[C#] 自訂CheckBox勾選區域

CheckBox自訂勾選範圍太小,一直都是常見的使用者抱怨問題
最常見的作法就是使用使用者控制項來模擬一個CheckBox工具
其實我知道還有一個方法就是直接改寫CheckBox的原始碼
奈何在下才疏學淺,一直都不知道重何下手,而網路上也一直找不到好的參考資料
最近偶然發現了一篇改寫CheckBox的方法,當然要趕緊記錄下來。

資料來源:http://inpega.blogspot.tw/2015/02/ccheckbox.html
主要程式碼都不是我所寫的,我只做了一點調整,為了怕以後找不到資料特複製於此,有任何侵權請通知我,我會立即刪除!

public partial class CheckBoxEx : System.Windows.Forms.CheckBox { public override string Text { get { return base.Text; } set { base.Text = value; Size size = TextRenderer.MeasureText(value, Font); if (Width < size.Width + ClientSize.Height) Width = size.Width + ClientSize.Height; } } public override Font Font { get { return base.Font; } set { base.Font = value; Size size = TextRenderer.MeasureText(Text, value); if (Width < size.Width + ClientSize.Height) Width = size.Width + ClientSize.Height; } } protected override void OnPaint(PaintEventArgs e) { int h = ClientSize.Height; Rectangle rc = new Rectangle(new Point(0, 0), new Size(h, h)); e.Graphics.Clear(Parent.BackColor); ControlPaint.DrawCheckBox( e.Graphics, rc, this.Checked ? ButtonState.Checked : ButtonState.Normal ); SizeF size = e.Graphics.MeasureString(Text, Font); e.Graphics.DrawString( Text, this.Font, new SolidBrush(Color.Black), new PointF(h, size.Height < h ? (h - size.Height) / 2 : 0) ); h = 0; e.Dispose(); } }

補充:

改寫Form控制項,不建議在UserControl、CustomControl 這兩個類型上撰寫,這兩個類型容易發生編譯上的錯誤
建議直接在空的Class類別上開發,開發後其他專案就可以直接在空具箱裡使用。

把改寫的控制項放入工具箱步驟:
1.

2.

直接選擇已編譯完成的新控制項物件即可。


2017/11/13

SD 記憶卡規格說明

SD Card 又或者叫SD記憶卡,是需多3C設備用來儲存資料的媒介。
購買SD Card時,往往會被複雜的規格弄得不知所措,特地整理一下規格資料方便以後查詢。

以下資料與圖片來源:SD 協會 https://www.sdcard.org



1.容量標準:規範記憶卡的容量上限與檔案系統
SD標準–容量上限為2GB,使用FAT 12與FAT 16檔案系統。
SDHC標準–容量介於2GB至32GB間,使用 FAT32檔案系統。
SDXC標準–容量介於32GB至2TB間,使用exFAT檔案系統。
2.記憶卡尺寸:規範記憶卡的尺寸大小與可使用的容量標準
SD
V
V
V
miniSD
V
V
microSD
V
V
V

3.速度標準:購買記憶卡最關鍵的規格,規範記憶卡需要達到的傳輸標準。

速度標誌位置


速度標誌分類

三種速度分類之間沒有相對應的關係。

傳輸速率表


影像解析度與建議使用的速度標誌

2017/10/24

.Net Standard 學習心得與想法

.Net Standard 發展的勢頭越來越旺,身為一個跟資訊沾點邊的人當然要好好地來了解一下。
以下是我的一些想法,如果有錯誤的地方歡迎來指正。

網路上已經有了很多.Net Standard 的相關文章,不論是官方的說明、還是網友的分享都寫得非常的精采,但是這些都還是無法解我的疑惑?
大部分的介紹文都會放這張圖


     資料來源:https://blogs.msdn.microsoft.com/dotnet/2016/09/26/introducing-net-standard/

這張圖讓我了解了.Net Standard 的架構,但是然後呢?
我應該怎麼使用.Net Standard 在我現有的專案上?
難道要我把現有的專案都用.Net Standard 的標準改寫嗎?
這些疑惑讓我對.Net Standard 這項技術有無從下手的感覺。
好在天無絕人之路,看了一篇文章
https://dotblogs.com.tw/aspnetshare/2017/02/26/20170225-netstandardagain
其中有一段
".Net Standard 並不算是一個實做任何東西的 platform,其實它是一系列的規範來要求每個 platform 在不同的版本下需要實做出那些 API"
我瞬間懂了,這其實說的就是物件裡的介面嘛!
簡單的說就是微軟定義了好幾組要大家遵守的介面API,並在編譯時幫忙將 .Net Standard API 對應到.Net Framework、Net Core、XAMARIN等實際可用的同名方法。

實際上應該要怎麼使用呢?
我的想法是:
在開發一個符合.Net Standard架構的系統,這個新的.Net Standard系統主要是要把已開發的.Net Framework系統供外部呼叫使用
有點類似MVC 的controller 的功用
假設我有一個已開發完成的 .Net Framework DLL 專案,那麼我先依據以下這張表決定要用哪一版的.Net Standard來開發

舉個例子:
我有一個.Net Framework開發的系統 ABC.DLL
我先依據ABC.DLL使用的.Net Framework版本參考以下這張表決定要用哪一版的.Net Standard來開發


    資料來源:https://github.com/dotnet/standard/blob/master/docs/versions.md

在來另開一個新的.Net Standard專案STD.DLL,當然STD.DLL必須能呼叫使用ABC.DLL
然後外部系統不論是用.Net Framework、Net Core還是XAMARIN來開發,只要支援STD.DLL 的.Net Standard版本
都可以透由STD.DLL 來使用 ABC.DLL。

2017/10/19

樹型資料庫結構設計

最近正在研究樹型資料庫結構設計,從網路上找了不少資料甚有啟發
特別記錄下網路上的資料

大家如果有好的觀點,或者好的文章連結,歡迎聯絡我!

2017/10/14

[VB.net] 如何避免程式重複執行

一般要避免開發的應用程式在系統上被使用者重複執行時有以下方法:


方法一.
直接在專案設定裡勾選 "建立單一執行個體應用程式"。


採用這個方法無論在執行程式前程式名稱是否不同,都無法重複執行。

方法二.
直接在 form load 事件裡新增檢查系統上是否有重複名稱的程式在執行

Dim _ThisProcess As Process = Process.GetCurrentProcess
Dim _ProcessArr() As Process = Process.GetProcessesByName(_ThisProcess.ProcessName)
If _ProcessArr.Length > 1 Then
'有重複名稱的程式開啟,關閉自己停止執行

   Erase _ProcessArr
   End

Else

   Erase _ProcessArr

End If

這個方法需要特別注意的是,在執行程式前只要程式名稱不同,雖然是相同的程式也是會重複執行。