rhasm.net/blog

興味の赴くままに色々紹介し、解説をするブログです。

*

NullableDateTimePickerコントロール

      2015/08/29

NullableDateTimePicker Nullを許容するDateTimePicker

DateTimePickerは便利なコントロールなのですが、ぶっちゃけデータベースを扱っているとDateTime型にNullを放り込んでいることも多く、Nullを許容するDateTimePickerがないかと探していたのです。


探した結果、見つけたのがこちら。
Nullを許容するDateTimePickerコントロール

そのまんまです。
名前はNullableDateTimePicker。大層便利に使わせてもらっていたのですが、ある日気がつきました。使っている環境は、VisualStudio2010、言語はC#です。
何に気がついたかというと、貼り付けたその日がデフォルト日付になってしまう、ということ。

何も設定してなければ、DropDownカレンダーを表示した時にデフォルト値が「今日」になってて欲しいわけですが、このコントロール、貼り付けたその日がデフォルト値になってしまうのです。なぜ。
調べた結果

// 
// nullableDateTimePicker1
// 
this.nullableDateTimePicker1.Location = new System.Drawing.Point(569, 248);
this.nullableDateTimePicker1.Name = "nullableDateTimePicker1";
this.nullableDateTimePicker1.Size = new System.Drawing.Size(200, 19);
this.nullableDateTimePicker1.TabIndex = 3;
this.nullableDateTimePicker1.Value = new System.DateTime(2012, 11, 13, 18, 36, 53, 199);

ん?おや?

this.nullableDateTimePicker1.Value = new System.DateTime(2012, 11, 13, 18, 36, 53, 199);

なんと。
コントロールをデザイン画面で貼り付けた時に、ものすごい勢いで固定値が指定されているのがわかりました。どういうことですか。見つけた時びっくりしたわ。これを消せば、動作としては問題なく動くようになるわけですが、消し忘れた時が悲惨だなと思います。

そこで、もう少し調べてみることにしました。
何か、こう、貼り付けた時のデフォルト値を指定したい。しかも、それは固定値ではなく「今日」。今日なのです。
彷徨ったところ、こんな記事を見つけました。

カスタムコントロールのプロパティに勝手に初期値が設定されてしまう。

おお、ShouldSerializeというのがあるらしい。これは良いことを知りました。
今度はShouldSerializeを調べると、

ShouldSerialize メソッドと Reset メソッドによる既定値の定義

なるほど。
んで、これを参照にしてコードを付け足してみました。

/// <summary>
/// デザイナに貼り付けた際にValueのデフォルト値が貼り付けた日付を固定値にしてしまうことを防ぐ。
/// これを書くと、Valueのデフォルト値が指定されなくなります。
/// </summary>
/// <returns></returns>
public bool ShouldSerializeValue()
{
    return (System.DateTime)this.Value == System.DateTime.Now;
}

これだけです。
これをValueのプロパティ定義の後ろにこそっと書き込んでいます。こんな風に。

/// <summary>
/// Gets or sets the date/time value assigned to the control.
/// </summary>
/// <value>The DateTime value assigned to the control
/// </value>
/// <remarks>
/// <p>If the <b>Value</b> property has not been changed in code or by the user, it is set
/// to the current date and time (<see cref="DateTime.Now"/>).</p>
/// <p>If <b>Value</b> is <b>null</b>, the DateTimePicker shows 
/// <see cref="NullValue"/>.</p>
/// </remarks>
public new Object Value
{
    get
    {
        if (_isNull)
        {
            return null;
        }
        else
        {
            return base.Value;
        }
    }
    set
    {
        if (value == null || value == DBNull.Value)
        {
            SetToNullValue();
        }
        else
        {
            SetToDateTimeValue();
            base.Value = (DateTime)value;
        }
    }
}

/// <summary>
/// デザイナに貼り付けた際にValueのデフォルト値が貼り付けた日付を固定値にしてしまうことを防ぐ。
/// これを書くと、Valueのデフォルト値が指定されなくなります。
/// </summary>
/// <returns></returns>
public bool ShouldSerializeValue()
{
    return (System.DateTime)this.Value == System.DateTime.Now;
}

/// <summary>
/// Gets or sets the format of the date and time displayed in the control.
/// </summary>
/// <value>One of the <see cref="DateTimePickerFormat"/> values. The default is 
/// <see cref="DateTimePickerFormat.Long"/>.</value>
[Browsable(true)]
[DefaultValue(DateTimePickerFormat.Long), TypeConverter(typeof(Enum))]
public new DateTimePickerFormat Format
{
    get { return _format; }
    set
    {
        _format = value;
        SetFormat();
        OnFormatChanged(EventArgs.Empty);
    }
}

1つ目と3つ目のプロパティ設定は、元々のソースそのままです。
まあ、付け足す場所もどこでもよいわけなので、位置指定にさしたる意味はありません。ともあれ、これを書いてからコントロールを貼り付けると、変な固定値が初期値として設定されなくなります。お試しあれ。

 - コンピュータ, プログラミング