KB).NET付属のDateTimePickerコントロールは、ルックアンドフィールは非常に優れていますが、null値を入力できません。データベース内では、nullを許容するDateTime値がよく使われます。この問題の回避策を紹介します。目次はじめにソリューション実装フォーマット値イベントコンストラクタ使い方CSLA.NETユーザーへの注意はじめに.NET付属のDateTimePickerコントロールは、ルックアンドフィールは非常に優れていますが、ある重要な機能が欠けています。DateTimePickerコントロールにはnull値を入力できないのです。そのため、DateTimePickerコントロールをデータセットにバインドすると問題が起こります。データベース内では、nullを許容するDateTime値がよく使われるからです。この問題を回避するためのソリューションがインターネットでいくつか見つかりましたが、いずれも少々問題がありました。Jonssonが作成したこのコントロールは、DateTimePickerのCheckBoxを使用してnull値を示します。私はこのソリューションに賛成しません。TextBoxなどと一貫した動作にするべきだと思うからです。TextBox内にnull値を表示するときには、それがnullであることをCheckBoxで示したりはしません。何も表示しないだけです。Triが作成したこのコントロールは、別の方法を採用し、null値のときは空のDateTimePickerを表示します。この方が良いとは思いますが、このコントロールにはいくつか問題があり、思いどおりの動作をしませんでした。このコントロールをTabPageに配置してデータ連結を行おうとしたところ、例外が発生してしまいました。このコントロールをnull値で初期化すると、必ず次の例外が発生しました。有効なDateTime値で初期化したときは、問題なく動作しました。Shirshovが作成したコントロールです。Triのコントロールによく似ていますが、こちらの方が問題は少ないと言えます。TabControl上で使用するとまったく同じ例外が発生しました。ルックアンドフィールは良くてもTabPage上で動作しないコントロールしかないということです。私はたいていのコントロールをTabPageに配置して使用するので、これらのコントロールをTabPage上で動作させる必要がありました。そこで、返された例外を詳しく調べるところから着手しました。調べるうちに、初期化時にDateTimePicker.FormatプロパティをCustomFormatに変更していることに関係があることがわかってきました。Zimmerannによる次のような説明を見つけました。「null日付から非null日付へ、またはその逆へと切り替えたときは、DateTimePicker.Formatが変更されている。Formatの値を変更すると、コンポーネントが通常は問題なしという通知を生成する。この場合はコントロールがまだ表示されていないので、Formatの通知が内部的に失敗してしまう。」そこで、これらのNullableDateTimePickerコントロールの動作に基づきつつ、問題が発生しないような独自のNullableDateTimePickerコントロールを作成することにしました。ソリューションこのNullableDateTimePickerコントロールはDateTimePickerコントロールを継承し、DateTimePickerの良いところをすべて受け継いでいます。基本となるDateTimePickerのFormatプロパティは常にDateTimePickerFormat.Customに設定し、変更しません(コントロールをTabPage上で使用したときの例外を避けるため)。オリジナルのDateTimPickerと同様にフォーマットを変更できるようにするために、このNullableDateTimePickerでは、DateTimePickerのFormatプロパティおよびCustomFormatプロパティにまつわるすべてのものをエミュレートする必要があります。このコントロールの具体的な実装を次に示します。実装まず、NullableDateTimePickerで使用されるさまざまな値を格納するためのプライベートフィールドをいくつか新しく定義します。_formatAsString;フォーマット前にも述べたとおり、DateTimePickerからはFormatプロパティとCustomFormatプロパティを使用できません。そのため、これらに代わる新しいプロパティを実装する必要があります。}}Formatプロパティのセッターを呼び出すと、新しいDateTimePickerFormatの値が_valueに格納されます。ここで、NullableDateTimePickerのフォーマットをこの新しいフォーマットに変更する必要があります。これはSetFormat()メソッド内で行います。親のDateTimePickerのFormatプロパティは常にDateTimePickerFormat.Customに設定されているので、独自クラスのFormat値を、このフォーマットを表す文字列にマッピングする必要があります。それにより、この文字列を基になるDateTimePickerコントロールのCustomFormatとして設定することができます。DateTimePickerFormatの値を対応する文字列表現にマッピングするにはどうすればいいでしょうか。そのためには、現在のCultureInfoを取得する必要があります。このCultureInfoから、各種のDateTimePickerFormatに対応する正しいフォーマット文字列を返すDateTimeFormatInfoを取得します。}}上記のメソッドでは、フォーマットの文字列表現をFormatAsStringプロパティに割り当てています。これは本稿で作成しているコントロールのプライベートプロパティです。}}FormatAsStringプロパティのセッターでは、フォーマット文字列をbase.CustomFormatに割り当てて、最終的に親DateTimePickerクラスのフォーマットを変更しています。値ここまでのコードでは、フォーマットの問題を同名の新規プロパティの陰に隠しました。したがって、このコントロールのユーザー側から見れば、これまでと何も変わっていません。次は、さらに一歩進んで、DateTime値だけでなくnull値も設定できるように新しいValueプロパティを実装します。Valueプロパティのゲッターは、基本コントロールのValueをそのまま返すか、コントロールがnull値を表示している場合はnullを返します。セッターは、値がnullまたはDBNull.Valueの場合は、SetToNullValue()を呼び出してコントロールをnullに設定します。値がDateTime値の場合は、基本コントロールのValueを設定します。DateTime値を正しく表示するためにSetToDateTimeFormat()を呼び出します。}}コントロールがそれまでnullを表示していて、次にDateTime値を表示しなければならなくなった場合、SetToDateTimeValue()メソッドは、SetFormat()を呼び出すことでフォーマットを現在使用中のDateTimePickerFormatに設定し、その後にOnValueChanged()を呼び出してValueChangedイベントを発生させます。}}SetToNullValue()メソッドは、コントロール内にDateTime値の代わりにNullValueを表示します。NullValueは、開発者が設定できる文字列プロパティです。please>」など)を自由に定めて表示することもできます。}}イベントDateTimePickerが現在null値を表示していて、ユーザーがこのコントロールのドロップダウンリストからDateTime値を選択したときは、Formatを適切なDateTimePickerFormatに戻す必要があります。(e);}ここまでのコードでは、ユーザーがDateTimePickerの値をnullに設定するという可能性を考慮していません。データ連結では正常に動作しますが、問題はユーザー操作のときです。今回のDateTimePickerでは、Deleteキーが押されたときにnullを受け付けるようにします。そのためには、OnKeyUpイベントをオーバーライドして、ValueをNullValueに設定します。base.OnKeyUp(e);}コンストラクタ最後にコンストラクタを実装します。コンストラクタでは、基本クラスのFormatプロパティをDateTimePickerFormat.Customに設定し、今回作成しているコントロールのFormatプロパティをDateTimePickerFormat.Longに設定します(LongはこのDateTimePickerコントロールの既定値です)。DateTimePickerFormat.Long;}使い方このコントロールの使い方は、.NETのDateTimePickerと同じです。唯一の違いは、Valueプロパティへのアクセス方法です。新しいコントロールでは、Valueプロパティのデータ型がDateTimeからObjectになっています。したがって、値をDateTime型にキャストする必要があります(ただし、その前にnullかどうかをテストしてください)。私は、マルチ階層アプリケーションを開発するときにはCSLA.NETというオープンソースフレームワークを使用しています。CSLA.NETには、SmartDateと呼ばれる独自のDateTime型があります。SmartDateは、DBNull.ValueをDateTime.MinValueまたはDateTime.MaxValueに変換します。そのため、CSLA.NETで作業しているときは、上記のNullableDateTimePickerは役に立ちません。SmartDateクラスを扱っているときは、SmartDateのDateTime値がDateTime.MinValueまたはDateTime.MaxValueの際に、DateTimePickerがNullValueを表示しなければならないからです。そこで、この状況に対処する別のNullableDateTimePickerを作成してみました。こちらの詳細は私の個人的ブログに書いてあります。CSLA.NET」をお読みください。連載通知を行うには会員登録(無料)が必要です。会員の方はログインを行ってください。1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。圧縮・解凍UNIX基本講座@CodeZine『CodeZine(コードジン)』の公式アカウントです。【NEW】デブスト2019デブサミ2019福岡・関西デブサミ2019夏デブスト関西デブサミ2019×ログインEメールパスワード※旧SEメンバーシップ会員の方は、同じ登録情報(Eメール&パスワード)でログインいただけます。イラストの無断転載を禁じます。記載されているロゴ、システム名、製品名は各社及び商標権者の登録商標あるいは商標です。