Skip to content

Instantly share code, notes, and snippets.

@takiru
Last active May 26, 2018 08:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save takiru/a98d2517bb8e501dee2290ca3ff74d59 to your computer and use it in GitHub Desktop.
Save takiru/a98d2517bb8e501dee2290ca3ff74d59 to your computer and use it in GitHub Desktop.
Nullable, ReadOnly, Changeable ForeColor, Changeable BackColor DateTimePicker
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Metroit.Windows.Forms
{
/// <summary>
/// ユーザーが日時を選択し、書式を指定して日時を表示できる Windows コントロールを表します。
/// </summary>
public class MetDateTimePicker : DateTimePicker, ISupportInitialize
{
/// <summary>
/// MetDateTimePicker の新しいインスタンスを初期化します。
/// </summary>
public MetDateTimePicker()
: base()
{
// デザイン時は制御しない
if (MetDateTimePicker.DesignMode)
{
return;
}
this.KeyDown += MetDateTimePicker_KeyDown;
this.Enter += MetDateTimePicker_Enter;
this.Leave += MetDateTimePicker_Leave;
}
#region イベント
private bool isNull = false;
/// <summary>
/// Backspace, Deleteキー押下でnull表示にする。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MetDateTimePicker_KeyDown(object sender, KeyEventArgs e)
{
//Backspace, Deleteキーが押されたらnull表示
if (this.AcceptNull && (e.KeyData == Keys.Delete || e.KeyData == Keys.Back) && !this.isNull)
{
this.Value = null;
return;
}
// 数字キー、数字テンキー、十字キーが押された時だけnullから値を復帰する
if (!(e.Alt || e.Control || e.Shift) &&
((e.KeyValue >= 48 && e.KeyValue <= 57) ||
(e.KeyValue >= 96 && e.KeyValue <= 105) ||
(e.KeyValue >= 37 && e.KeyValue <= 40)))
{
if (!this.isNull)
{
return;
}
// UIから操作した時、ミリ秒は取り除かれるのが通常仕様
var recoverDate = new DateTime(base.Value.Year, base.Value.Month, base.Value.Day, base.Value.Hour, base.Value.Minute, base.Value.Second, 0);
if (base.Value == recoverDate)
{
this.Value = recoverDate;
this.OnValueChanged(EventArgs.Empty);
}
else
{
this.Value = recoverDate;
}
}
}
/// <summary>
/// フォーカスを得た時、色の変更とテキストの反転を行う。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MetDateTimePicker_Enter(object sender, EventArgs e)
{
// フォーカス取得時の色に変更
this.changeFocusColor();
}
/// <summary>
/// フォーカスを失った時、色の変更を行う。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MetDateTimePicker_Leave(object sender, EventArgs e)
{
this.changeBaseColor();
}
private bool formatSwitching = false;
private bool formatSwitchingByDataBinding = false;
/// <summary>
/// 状態に応じてフォーマットの変更を行う。
/// </summary>
/// <param name="isNull">null値かどうか。</param>
private void switchFormat(bool isNull)
{
this.formatSwitching = true;
if (isNull)
{
// Valueプロパティがバインドされている場合はValue制御用にフラグを立てる
var valueBinding = this.DataBindings["Value"];
if (valueBinding != null)
{
this.formatSwitchingByDataBinding = true;
base.Format = DateTimePickerFormat.Custom;
base.CustomFormat = " ";
this.isNull = true;
this.formatSwitchingByDataBinding = false;
}
else
{
base.Format = DateTimePickerFormat.Custom;
base.CustomFormat = " ";
this.isNull = true;
}
}
else
{
base.Format = this.innerFormat;
base.CustomFormat = this.innerCustomFormat;
this.isNull = false;
}
this.formatSwitching = false;
}
#endregion
#region プロパティ
private bool isValueChanged = false;
private DateTimePickerFormat innerFormat = DateTimePickerFormat.Long;
private string innerCustomFormat = "";
private bool visible = true;
/// <summary>
/// コントロールに代入された日付/時刻値を取得または設定します。
/// </summary>
[Browsable(true)]
[Bindable(true)]
[Category("Behavior")]
[Description("コントロールに代入された日付/時刻値を取得または設定します。")]
public new DateTime? Value
{
get
{
if (this.isNull)
{
return null;
}
return base.Value;
}
set
{
// Valueがデータバインドしていて、null入力が行われた時にFormat変更によって二度走行するため
if (this.formatSwitchingByDataBinding)
{
return;
}
// Visible=false の時に、nullにしてからTextプロパティで値を変更し、Visible=true にすると、
// 内部で保持しているであろうnullにする前の日付に変更されて走行してしまうため
if (this.visibleSwitching)
{
return;
}
if (!this.AcceptNull && value == null)
{
throw new ArgumentNullException();
}
this.isValueChanged = true;
// 既にnullが設定されている場合は何もしない
if (value == null && this.isNull)
{
return;
}
// nullの設定時
if (value == null)
{
this.switchFormat(true);
if (MetDateTimePicker.DesignMode)
{
return;
}
switchControl();
this.OnValueChanged(EventArgs.Empty);
return;
}
// nullからの復帰時
if (this.Value == null && value != null)
{
this.switchFormat(false);
if (MetDateTimePicker.DesignMode)
{
return;
}
switchControl();
if (base.Value == value.Value)
{
this.OnValueChanged(EventArgs.Empty);
}
else
{
base.Value = value.Value;
}
return;
}
base.Value = value.Value;
if (MetDateTimePicker.DesignMode)
{
return;
}
switchControl();
}
}
/// <summary>
/// Value が既定値から変更されたかどうかを返却する。
/// </summary>
/// <returns>true:変更された, false:変更されていない</returns>
internal bool ShouldSerializeValue() => this.isValueChanged;
/// <summary>
/// Value のリセット操作を行う。
/// </summary>
internal void ResetValue()
{
this.Value = DateTime.Now;
this.Checked = false;
this.isValueChanged = false;
}
/// <summary>
/// このコントロールに関連付けられているテキストを取得または設定します。
/// </summary>
public override string Text
{
get
{
if (this.isNull)
{
return "";
}
return base.Text;
}
set
{
if (MetDateTimePicker.DesignMode)
{
base.Text = value;
}
else
{
switchFormat(false);
base.Text = value;
switchControl();
}
}
}
/// <summary>
/// コントロールに表示される日時の書式を取得または設定します。
/// </summary>
[DefaultValue(DateTimePickerFormat.Long)]
public new DateTimePickerFormat Format
{
get => base.Format;
set
{
this.innerFormat = value;
base.Format = value;
// nullの時は値を復元する
if (this.isNull)
{
this.switchFormat(false);
OnValueChanged(EventArgs.Empty);
}
if (!this.controlCreated)
{
return;
}
switchControl();
}
}
/// <summary>
/// 日付/時刻のカスタム書式指定文字列を取得または設定します。
/// </summary>
[DefaultValue("")]
public new string CustomFormat
{
get => base.CustomFormat;
set
{
this.innerCustomFormat = value;
base.CustomFormat = value;
// nullの時は値を復元する
if (this.isNull && this.Format == DateTimePickerFormat.Custom && base.CustomFormat != " ")
{
this.switchFormat(false);
OnValueChanged(EventArgs.Empty);
}
if (!this.controlCreated)
{
return;
}
switchControl(true);
}
}
/// <summary>
/// コントロールとそのすべての子コントロールが表示されているかどうかを示す値を取得または設定します。
/// </summary>
[Browsable(true)]
[DefaultValue(true)]
public new bool Visible
{
get => this.visible;
set
{
this.visible = value;
if (MetDateTimePicker.DesignMode)
{
return;
}
if (!this.ReadOnly && !this.ReadOnlyLabel)
{
base.Visible = value;
return;
}
if (!this.controlCreated)
{
return;
}
switchControl();
}
}
/// <summary>
/// DateTimePicker コントロールの背景色を示す値を取得または設定します。
/// </summary>
[Browsable(false)]
public override Color BackColor { get => base.BackColor; set => base.BackColor = value; }
/// <summary>
/// DateTimePicker コントロールの文字色を示す値を取得または設定します。
/// </summary>
[Browsable(false)]
public override Color ForeColor { get => base.ForeColor; set => base.ForeColor = value; }
#endregion
#region 追加プロパティ
private bool acceptNull = false;
private TextBox textBox = null;
private bool readOnlyText = false;
private Label label = null;
private bool readOnlyLabel = false;
private Color defaultBaseBackColor => this.ReadOnly ? SystemColors.Control : SystemColors.Window; // BaseBackColor の既定値
private Color? baseBackColor = null;
private Color defaultFocusBackColor => this.ReadOnly ? SystemColors.Control : SystemColors.Window; // FocusBackColor の既定値
private Color? focusBackColor = null;
private Color defaultBaseForeColor => SystemColors.WindowText; // BaseForeColor の既定値
private Color? baseForeColor = null;
private Color defaultFocusForeColor => SystemColors.WindowText; // FocusForeColor の既定値
private Color? focusForeColor = null;
/// <summary>
/// NULLの入力を受け入れるかどうかを取得または設定します。
/// </summary>
[Browsable(true)]
[Category("Metroit拡張 動作")]
[DefaultValue(false)]
[Description("NULLの入力を受け入れるかどうかを取得または設定します。")]
public bool AcceptNull
{
get => this.acceptNull;
set
{
// nullを許可しない場合は、Value実装が動作するため、値を現在日にしてから。
if (!value && !this.Value.HasValue)
{
this.Value = DateTime.Now;
this.acceptNull = value;
return;
}
this.acceptNull = value;
}
}
/// <summary>
/// TextBox による代替表示を行っているかどうかを取得します。
/// </summary>
[Browsable(true)]
[Category("Metroit拡張 動作")]
[DefaultValue(false)]
[Description("コントロールをテキストボックスで置き換えます。")]
public bool ReadOnly
{
get
{
return this.readOnlyText;
}
set
{
// ラベルの代替をやめる
if (value && this.ReadOnlyLabel)
{
this.ReadOnlyLabel = false;
}
this.readOnlyText = value;
if (MetDateTimePicker.DesignMode)
{
// 背景色・文字色の変更
this.ChangeDisplayColor();
return;
}
if (!this.controlCreated)
{
return;
}
this.switchTextBox();
}
}
private bool visibleSwitching = false;
/// <summary>
/// 表示状態に応じて、Visible、テキスト代替を切り替える。
/// </summary>
private void switchTextBox()
{
// 非表示
if (!this.Visible)
{
// テキスト代替なしの場合は通常のVisible
if (!this.ReadOnly)
{
this.ChangeDisplayColor();
base.Visible = this.Visible;
return;
}
// テキストを一旦削除する
if (this.textBox != null)
{
this.textBox.Parent.Controls.Remove(this.textBox);
this.textBox.Dispose();
this.textBox = null;
}
this.ChangeDisplayColor();
base.Visible = this.Visible;
return;
}
// 表示でテキスト代替なしの場合はテキストを消す
if (!this.ReadOnly)
{
if (this.textBox != null)
{
this.textBox.Parent.Controls.Remove(this.textBox);
this.textBox.Dispose();
this.textBox = null;
}
this.ChangeDisplayColor();
if (this.isNull)
{
base.Visible = this.Visible;
switchFormat(true);
}
else
{
this.visibleSwitching = true;
base.Visible = this.Visible;
this.visibleSwitching = false;
}
return;
}
// ReadOnly=trueで既にテキストが存在する場合、一旦テキストを削除する
if (this.textBox != null)
{
this.textBox.Parent.Controls.Remove(this.textBox);
this.textBox.Dispose();
this.textBox = null;
}
// 表示でテキスト代替あり
this.textBox = new TextBox();
this.textBox.ReadOnly = true;
this.textBox.Text = this.Text;
this.textBox.Size = this.Size;
this.textBox.Location = this.Location;
this.textBox.Margin = this.Margin;
this.textBox.MaximumSize = this.MaximumSize;
this.textBox.MinimumSize = this.MinimumSize;
this.textBox.Padding = this.DefaultPadding;
this.textBox.Visible = this.Visible;
this.textBox.Enabled = this.Enabled;
this.textBox.Dock = this.Dock;
this.textBox.Font = this.Font;
this.textBox.Anchor = this.Anchor;
this.textBox.RightToLeft = this.RightToLeft;
this.textBox.BorderStyle = BorderStyle.Fixed3D;
this.textBox.Cursor = this.Cursor;
this.textBox.TextAlign = HorizontalAlignment.Left;
this.textBox.TabIndex = this.TabIndex;
this.textBox.TabStop = this.TabStop;
this.ChangeDisplayColor();
this.textBox.Enter += MetDateTimePicker_Enter;
this.textBox.Leave += MetDateTimePicker_Leave;
base.Visible = false;
if (this.Parent.GetType() == typeof(TableLayoutPanel))
{
var tlp = (TableLayoutPanel)this.Parent;
var position = tlp.GetPositionFromControl(this);
tlp.Controls.Add(this.textBox, position.Column, position.Row);
}
else if (this.Parent.GetType() == typeof(FlowLayoutPanel))
{
var flp = (FlowLayoutPanel)this.Parent;
flp.Controls.Add(this.textBox);
flp.Controls.SetChildIndex(this.textBox, flp.Controls.IndexOf(this));
}
else
{
this.Parent.Controls.Add(this.textBox);
}
}
/// <summary>
/// Label による代替表示を行っているかどうかを取得します。
/// </summary>
[Browsable(true)]
[Category("Metroit拡張 動作")]
[DefaultValue(false)]
[Description("コントロールをラベルで置き換えます。")]
public bool ReadOnlyLabel
{
get
{
return this.readOnlyLabel;
}
set
{
// テキストの代替をやめる
if (value && this.ReadOnly)
{
this.ReadOnly = false;
}
this.readOnlyLabel = value;
if (MetDateTimePicker.DesignMode)
{
// 背景色・文字色の変更
this.ChangeDisplayColor();
return;
}
if (!this.controlCreated)
{
return;
}
this.switchLabel();
}
}
/// <summary>
/// 表示状態に応じて、Visible、ラベル代替を切り替える。
/// </summary>
private void switchLabel()
{
// 非表示
if (!this.Visible)
{
// ラベル代替なしの場合は通常のVisible
if (!this.ReadOnlyLabel)
{
this.ChangeDisplayColor();
base.Visible = this.Visible;
return;
}
// ラベルを一旦削除する
if (this.label != null)
{
this.label.Parent.Controls.Remove(this.label);
this.label.Dispose();
this.label = null;
}
this.ChangeDisplayColor();
base.Visible = this.Visible;
return;
}
// 表示でラベル代替なしの場合はラベルを消す
if (!this.ReadOnlyLabel)
{
if (this.label != null)
{
this.label.Parent.Controls.Remove(this.label);
this.label.Dispose();
this.label = null;
}
this.ChangeDisplayColor();
if (this.isNull)
{
base.Visible = this.Visible;
switchFormat(true);
}
else
{
this.visibleSwitching = true;
base.Visible = this.Visible;
this.visibleSwitching = false;
}
return;
}
// ReadOnlyLabel=trueで既にラベルが存在する場合、一旦ラベルを削除する
if (this.label != null)
{
this.label.Parent.Controls.Remove(this.label);
this.label.Dispose();
this.label = null;
}
// 表示でラベル代替あり
this.label = new Label();
this.label.Text = this.Text;
this.label.Size = this.Size;
this.label.Location = this.Location;
this.label.Margin = this.Margin;
this.label.MaximumSize = this.MaximumSize;
this.label.MinimumSize = this.MinimumSize;
this.label.Padding = this.DefaultPadding;
this.label.Visible = this.Visible;
this.label.Enabled = this.Enabled;
this.label.Dock = this.Dock;
this.label.Font = this.Font;
this.label.Anchor = this.Anchor;
this.label.RightToLeft = this.RightToLeft;
this.label.BorderStyle = BorderStyle.Fixed3D;
this.label.Cursor = this.Cursor;
this.label.TextAlign = ContentAlignment.MiddleLeft;
this.ChangeDisplayColor();
base.Visible = false;
if (this.Parent.GetType() == typeof(TableLayoutPanel))
{
var tlp = (TableLayoutPanel)this.Parent;
var position = tlp.GetPositionFromControl(this);
tlp.Controls.Add(this.label, position.Column, position.Row);
}
else if (this.Parent.GetType() == typeof(FlowLayoutPanel))
{
var flp = (FlowLayoutPanel)this.Parent;
flp.Controls.Add(this.label);
flp.Controls.SetChildIndex(this.label, flp.Controls.IndexOf(this));
}
else
{
this.Parent.Controls.Add(this.label);
}
}
/// <summary>
/// TextBoxまたはLabelへ切り替える。
/// </summary>
/// <param name="isCustomFormatChange">CustomFormat プロパティを変更したかどうか。</param>
private void switchControl(bool isCustomFormatChange = false)
{
if (isCustomFormatChange)
{
if (this.Format == DateTimePickerFormat.Custom && this.ReadOnly)
{
this.switchTextBox();
}
if (this.Format == DateTimePickerFormat.Custom && this.ReadOnlyLabel)
{
this.switchLabel();
}
}
else
{
if (this.ReadOnly)
{
this.switchTextBox();
}
if (this.ReadOnlyLabel)
{
this.switchLabel();
}
}
}
/// <summary>
/// コントロールの背景色を取得または設定します。
/// </summary>
[Browsable(true)]
[Category("Metroit拡張 表示")]
[Description("コントロールの背景色を取得または設定します。")]
public Color BaseBackColor
{
get
{
this.Refresh();
return this.baseBackColor ?? this.defaultBaseBackColor;
}
set
{
this.baseBackColor = value;
// 背景色・文字色の変更
this.ChangeDisplayColor();
}
}
/// <summary>
/// BaseBackColor が既定値から変更されたかどうかを返却します。
/// </summary>
/// <returns>true:変更された, false:変更されていない</returns>
internal bool ShouldSerializeBaseBackColor() => this.baseBackColor != null && this.baseBackColor != this.defaultBaseBackColor;
/// <summary>
/// BaseBackColor のリセット操作を行う。
/// </summary>
internal void ResetBaseBackColor()
{
this.baseBackColor = null;
// 背景色・文字色の変更
this.ChangeDisplayColor();
}
/// <summary>
/// フォーカス時のコントロールの背景色を取得または設定します。
/// </summary>
[Browsable(true)]
[Category("Metroit拡張 表示")]
[Description("フォーカス時のコントロールの背景色を取得または設定します。")]
public Color FocusBackColor
{
get
{
this.Refresh();
return this.focusBackColor ?? this.defaultFocusBackColor;
}
set
{
this.focusBackColor = value;
// 背景色・文字色の変更
this.ChangeDisplayColor();
}
}
/// <summary>
/// FocusBackColor が既定値から変更されたかどうかを返却します。
/// </summary>
/// <returns>true:変更された, false:変更されていない</returns>
internal bool ShouldSerializeFocusBackColor() => this.focusBackColor != null && this.focusBackColor != this.defaultFocusBackColor;
/// <summary>
/// FocusBackColor のリセット操作を行う。
/// </summary>
internal void ResetFocusBackColor()
{
this.focusBackColor = null;
// 背景色・文字色の変更
this.ChangeDisplayColor();
}
/// <summary>
/// コントロールの文字色を取得または設定します。
/// </summary>
[Browsable(true)]
[Category("Metroit拡張 表示")]
[Description("コントロールの文字色を取得または設定します。")]
public Color BaseForeColor
{
get
{
this.Refresh();
return this.baseForeColor ?? this.defaultBaseForeColor;
}
set
{
this.baseForeColor = value;
// 背景色・文字色の変更
this.ChangeDisplayColor();
}
}
/// <summary>
/// BaseBackColor が既定値から変更されたかどうかを返却する。
/// </summary>
/// <returns>true:変更された, false:変更されていない</returns>
internal bool ShouldSerializeBaseForeColor() => this.baseForeColor != null && this.baseForeColor != this.defaultBaseForeColor;
/// <summary>
/// BaseBackColor のリセット操作を行う。
/// </summary>
internal void ResetBaseForeColor()
{
this.baseForeColor = null;
// 背景色・文字色の変更
this.ChangeDisplayColor();
}
/// <summary>
/// フォーカス時のコントロールの文字色を取得または設定します。
/// </summary>
[Browsable(true)]
[Category("Metroit拡張 表示")]
[Description("フォーカス時のコントロールの文字色を取得または設定します。")]
public Color FocusForeColor
{
get
{
this.Refresh();
return this.focusForeColor ?? this.defaultFocusForeColor;
}
set
{
this.focusForeColor = value;
// 背景色・文字色の変更
this.ChangeDisplayColor();
}
}
/// <summary>
/// FocusBackColor が既定値から変更されたかどうかを返却する。
/// </summary>
/// <returns>true:変更された, false:変更されていない</returns>
internal bool ShouldSerializeFocusForeColor() => this.focusForeColor != null && this.focusForeColor != this.defaultFocusForeColor;
/// <summary>
/// FocusBackColor のリセット操作を行う。
/// </summary>
internal void ResetFocusForeColor()
{
this.focusForeColor = null;
// 背景色・文字色の変更
this.ChangeDisplayColor();
}
/// <summary>
/// コントロールのアクティブ状態に応じた表示色に変更します。
/// </summary>
protected virtual void ChangeDisplayColor()
{
// アクティブの時にアクティブ色に変更
var form = this.FindForm();
if (form != null && form.ActiveControl == this)
{
this.changeFocusColor();
}
else
{
this.changeBaseColor();
}
}
/// <summary>
/// 表示色をフォーカス色に変更する。
/// </summary>
private void changeFocusColor()
{
if (this.focusBackColor == null)
{
base.BackColor = this.defaultFocusBackColor;
}
else
{
base.BackColor = this.FocusBackColor;
}
if (this.focusForeColor == null)
{
base.ForeColor = this.defaultFocusForeColor;
}
else
{
base.ForeColor = this.FocusForeColor;
}
// テキストの代替表示を行っている場合はテキストの表示色も変更
if (this.controlCreated && this.ReadOnly && this.Visible)
{
this.textBox.BackColor = this.FocusBackColor;
this.textBox.ForeColor = this.FocusForeColor;
}
}
/// <summary>
/// 表示色を非フォーカス色に変更する。
/// </summary>
private void changeBaseColor()
{
if (this.baseBackColor == null)
{
base.BackColor = this.defaultBaseBackColor;
}
else
{
base.BackColor = this.BaseBackColor;
}
if (this.baseForeColor == null)
{
base.ForeColor = this.defaultFocusForeColor;
}
else
{
base.ForeColor = this.BaseForeColor;
}
// テキスト・ラベルの代替表示を行っている場合はテキスト・ラベルの表示色も変更
if (this.controlCreated && this.ReadOnly && this.Visible)
{
this.textBox.BackColor = this.BaseBackColor;
this.textBox.ForeColor = this.BaseForeColor;
}
if (this.controlCreated && this.ReadOnlyLabel && this.Visible)
{
this.label.BackColor = this.BaseBackColor;
this.label.ForeColor = this.BaseForeColor;
}
}
#endregion
#region メソッド
private bool controlCreated = false;
/// <summary>
/// InitializeComponent()でコントロールの生成が完了していないことを通知します。
/// </summary>
public void BeginInit()
{
this.controlCreated = false;
}
/// <summary>
/// 実装はありません。
/// </summary>
public void EndInit() { }
/// <summary>
/// コントロールの生成が完了したことを通知し、ReadOnly, ReadOnlyLabelの制御を行います。
/// </summary>
protected override void OnCreateControl()
{
// Formatプロパティを変更するとOnCreateControlが走行する。
// 内部的にFormatプロパティが変更された時は何も処理させない。
if (this.formatSwitching)
{
return;
}
base.OnCreateControl();
if (MetDateTimePicker.DesignMode)
{
return;
}
this.controlCreated = true;
switchControl();
}
/// <summary>
/// カレンダーを表示した時、日付を復帰します。
/// </summary>
/// <param name="eventargs">EventArgs オブジェクト。</param>
protected override void OnDropDown(EventArgs eventargs)
{
if (!this.isNull)
{
base.OnDropDown(eventargs);
return;
}
// nullの時、カレンダーを表示後、日付の選択や月の移動ボタンを押すとFormatプロパティ変更直後に
// 日付が確定してカレンダーが消えてしまうため、直前に指定されていた日付を復帰し、Alt+F4によって
// カレンダーを表示させ、通常ルートに戻す
// UIから操作した時、ミリ秒は取り除かれるのが通常仕様
var recoverDate = new DateTime(base.Value.Year, base.Value.Month, base.Value.Day, base.Value.Hour, base.Value.Minute, base.Value.Second, 0);
this.Value = recoverDate;
SendKeys.Send("%{DOWN}");
}
/// <summary>
/// コントロールの配置元が変更時、ラベル・テキスト代替表示をしていたらラベル・テキストの配置元も変更します。
/// </summary>
/// <param name="e"></param>
protected override void OnParentChanged(EventArgs e)
{
if (this.controlCreated && this.ReadOnlyLabel)
{
this.label.Parent = this.Parent;
}
if (this.controlCreated && this.ReadOnly)
{
this.textBox.Parent = this.Parent;
}
base.OnParentChanged(e);
}
/// <summary>
/// コントロールの表示位置が変更時、ラベル・テキスト代替表示をしていたらラベル・テキストの表示位置も変更します。
/// </summary>
/// <param name="e"></param>
protected override void OnLocationChanged(EventArgs e)
{
if (this.controlCreated && this.ReadOnlyLabel)
{
this.label.Location = this.Location;
}
if (this.controlCreated && this.ReadOnly)
{
this.textBox.Location = this.Location;
}
base.OnLocationChanged(e);
}
/// <summary>
/// コントロールのサイズが変更時、ラベル・テキスト代替表示をしていたらラベル・テキストのサイズも変更します。
/// </summary>
/// <param name="e"></param>
protected override void OnSizeChanged(EventArgs e)
{
if (this.controlCreated && this.ReadOnlyLabel)
{
this.label.Size = this.Size;
}
if (this.controlCreated && this.ReadOnly)
{
this.textBox.Size = this.Size;
}
base.OnSizeChanged(e);
}
/// <summary>
/// コントロールのサイズが変更時、ラベル・テキスト代替表示をしていたらラベル・テキストのサイズも変更します。
/// </summary>
/// <param name="e"></param>
protected override void OnResize(EventArgs e)
{
if (this.controlCreated && this.ReadOnlyLabel)
{
this.label.Size = this.Size;
}
if (this.controlCreated && this.ReadOnly)
{
this.textBox.Size = this.Size;
}
base.OnResize(e);
}
/// <summary>
/// コントロールのドッキングが変更時、ラベル・テキスト代替表示をしていたらラベル・テキストのドッキングも変更します。
/// </summary>
/// <param name="e"></param>
protected override void OnDockChanged(EventArgs e)
{
if (this.controlCreated && this.ReadOnlyLabel)
{
this.label.Dock = this.Dock;
}
if (this.controlCreated && this.ReadOnly)
{
this.textBox.Dock = this.Dock;
}
base.OnDockChanged(e);
}
/// <summary>
/// コントロールの文字入力方向が変更時、ラベル・テキスト代替表示をしていたらラベル・テキストの文字入力方向も変更します。
/// </summary>
/// <param name="e"></param>
protected override void OnRightToLeftChanged(EventArgs e)
{
if (this.controlCreated && this.ReadOnlyLabel)
{
this.label.RightToLeft = this.RightToLeft;
}
if (this.controlCreated && this.ReadOnly)
{
this.textBox.RightToLeft = this.RightToLeft;
}
base.OnRightToLeftChanged(e);
}
/// <summary>
/// コントロールのフォントが変更時、ラベル・テキスト代替表示をしていたらラベル・テキストのフォントも変更します。
/// </summary>
/// <param name="e"></param>
protected override void OnFontChanged(EventArgs e)
{
if (this.controlCreated && this.ReadOnlyLabel)
{
this.label.Font = this.Font;
}
if (this.controlCreated && this.ReadOnly)
{
this.textBox.Font = this.Font;
}
base.OnFontChanged(e);
}
/// <summary>
/// コントロールのマージンが変更時、ラベル・テキスト代替表示をしていたらラベル・テキストのマージンも変更します。
/// </summary>
/// <param name="e"></param>
protected override void OnMarginChanged(EventArgs e)
{
if (this.controlCreated && this.ReadOnlyLabel)
{
this.label.Margin = this.Margin;
}
if (this.controlCreated && this.ReadOnly)
{
this.textBox.Margin = this.Margin;
}
base.OnMarginChanged(e);
}
/// <summary>
/// コントロールのカーソルが変更時、ラベル・テキスト代替表示をしていたらラベル・テキストのカーソルも変更します。
/// </summary>
/// <param name="e"></param>
protected override void OnCursorChanged(EventArgs e)
{
if (this.controlCreated && this.ReadOnlyLabel)
{
this.label.Cursor = this.Cursor;
}
if (this.controlCreated && this.ReadOnly)
{
this.textBox.Cursor = this.Cursor;
}
base.OnCursorChanged(e);
}
/// <summary>
/// コントロールの活性状態が変更時、テキスト代替表示をしていたらテキストの活性状態も変更します。
/// </summary>
/// <param name="e"></param>
protected override void OnEnabledChanged(EventArgs e)
{
if (this.controlCreated && this.ReadOnly)
{
this.textBox.Enabled = this.Enabled;
}
base.OnEnabledChanged(e);
}
/// <summary>
/// 背景色の変更を行います。
/// </summary>
/// <param name="m"></param>
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
// 背景色・文字色を描画する
this.redrawColor(ref m);
}
/// <summary>
/// 背景色・文字色の描画し直します。
/// </summary>
private void redrawColor(ref Message m)
{
// 描画が行われた際のメッセージ
int WM_PAINT = 0x000F;
if (m.Msg == WM_PAINT)
{
// Bitmapを自分の上に描画して背景色を設定する
var bsz = SystemInformation.Border3DSize;
using (var g = this.CreateGraphics())
using (var bmp = this.getControlImage())
{
g.DrawImage(bmp, -bsz.Width + 2, -bsz.Height + 2);
}
}
}
/// <summary>
/// 背景色・文字色描画用のBitmapオブジェクトを取得する。
/// </summary>
/// <returns></returns>
private Bitmap getControlImage()
{
// 自分自身の画像をBitmapにコピー
var bmp = new Bitmap(this.Width, this.Height);
this.DrawToBitmap(bmp, new Rectangle(0, 0, this.Width, this.Height));
// Bitmapの背景色をMe.BackColorに変更する
using (var g = Graphics.FromImage(bmp))
{
System.Drawing.Imaging.ColorMap[] cm = { new System.Drawing.Imaging.ColorMap(), new System.Drawing.Imaging.ColorMap() };
// 背景色のマッピング
cm[0].OldColor = SystemColors.Window;
cm[0].NewColor = this.BackColor;
// 文字色のマッピング
cm[1].OldColor = SystemColors.WindowText;
cm[1].NewColor = this.ForeColor;
var ia = new System.Drawing.Imaging.ImageAttributes();
ia.SetRemapTable(cm);
var r = new Rectangle(0, 0, bmp.Width, bmp.Height);
g.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height),
0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, ia);
}
return bmp;
}
#endregion
/// <summary>
/// <para>Component が現在デザイン モードかどうかを示す値を取得します。</para>
/// <para>System.Windows.Forms.Control.DesignMode プロパティで制御されない継承コンポーネントの状態まで把握します。</para>
/// </summary>
/// <returns>true:デザインモード、false:実行中</returns>
private new static bool DesignMode
{
get
{
if (System.ComponentModel.LicenseManager.UsageMode
== System.ComponentModel.LicenseUsageMode.Designtime)
{
return true;
}
var processName = Process.GetCurrentProcess().ProcessName.ToUpper();
if (processName == "DEVENV" || processName == "VCSEXPRESS")
{
return true;
}
if (AppDomain.CurrentDomain.FriendlyName == "DefaultDomain")
{
return true;
}
return false;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment