日付をいろんな書式で表示したい。(参)

◇コンストラクタで、イベントへメソッドを登録する。
#region コンストラクタ

/// <summary>
/// コンストラクタ
/// </summary>
public DatePickerEx() {
this.Loaded += new RoutedEventHandler(DatePickerEx_Loaded);
this.Unloaded += new RoutedEventHandler(DatePickerEx_Unloaded);
this.SelectedDateChanged +=
new EventHandler<SelectionChangedEventArgs>(DatePickerEx_SelectedDateChanged);
this.LostFocus += new RoutedEventHandler(DatePickerEx_LostFocus);
return;
}

#endregion
当然終了時には、登録したメソッドを削除しておかないと、メモリリークのリストを背負い込む事になる。

◇Loadedイベント用メソッド+α
#region 内部データ

/// <summary>カスタムな書式で表示するかどうか</summary>
private bool customizeFormat_;

/// <summary>オーナーウィンドウ</summary>
private Window ownerWindow_;

#endregion

/// <summary>
/// Loadedイベント用メソッド
/// </summary>
/// <param name="sender">イベントソース</param>
/// <param name="e">イベントデータ</param>
private void DatePickerEx_Loaded(object sender, RoutedEventArgs e) {

var datePicker = sender as DatePickerEx;
this.ownerWindow_ = Window.GetWindow(datePicker);

if (this.ownerWindow_ != null) {
//ウィンドウ終了イベントへメソッドを登録する。
this.ownerWindow_.Closed += new EventHandler(Window_Closed);
}

this.customizeFormat_ = !string.IsNullOrEmpty(this.CustomDateFormat);

if (this.customizeFormat_) {
//DatePicker内で持っているTextBoxは、
//DatePickerTextBoxというちょっと特殊なクラス
//PART_TextBoxはTemplate内のコントロール名。固定
var textBox = Template.FindName("PART_TextBox", this) as DatePickerTextBox;

if (textBox != null && datePicker.SelectedDate != null) {

if (!textBox.IsFocused || textBox.IsReadOnly) {
//フォーカスがあたっていない、又は読み取り専用の時は
//カスタム書式で表示します。
textBox.Text = datePicker.SelectedDate.Value.
ToString(datePicker.CustomDateFormat);

} else if (!textBox.IsReadOnly) {
//フォーカスが合っていて、編集可能なときは、編集用の書式にする。
textBox.Text = this.ToEditingDateFormat(
datePicker.SelectedDate.Value);
}
}
}

return;
}

/// <summary>
/// 編集用の書式を使って、文字列に変換します。
/// </summary>
/// <param name="date">日付</param>
/// <returns>変換後の文字列</returns>
private string ToEditingDateFormat(DateTime date) {

if (this.SelectedDateFormat == DatePickerFormat.Short) {
//変換用メソッドもここで決まります。
return date.ToShortDateString();

} else {
//変換用メソッドもここで決まります。
return date.ToLongDateString();
}
}
Loadedイベント発生時に、オーナーウィンドウの終了イベントにメソッドを登録しておく。このメソッド内で、登録したイベントからメソッドを削除する処理を記述する。

○LostFocusイベント用メソッド
/// <summary>
/// フォーカスアウト イベント用メソッド
/// </summary>
/// <param name="sender">イベントソース</param>
/// <param name="e">イベントデータ</param>
private void DatePickerEx_LostFocus(object sender, RoutedEventArgs e) {
var datePicker = sender as DatePickerEx;

if (datePicker.Template == null || !datePicker.customizeFormat_) {
return;
}

var textBox = this.Template.FindName("PART_TextBox", this) as DatePickerTextBox;

if (textBox != null && datePicker.SelectedDate != null) {
//フォーカス喪失時の書式設定に変換する。
textBox.Text = datePicker.SelectedDate.Value.ToString(datePicker.CustomDateFormat);
}

return;
}

○フォーカス時イベント用メソッド
DatePickerへのフォーカスではなく、内部のTextBoxに対するフォーカスイベントへメソッドを登録する。
/// <summary>
/// テンプレート適用時の処理です。<br/>
/// テンプレートが適用される度に発生します。<br/>
/// </summary>
public override void OnApplyTemplate() {
base.OnApplyTemplate();

if (this.Template == null) {
return;
}

var textBox = this.Template.FindName("PART_TextBox", this) as DatePickerTextBox;

if (textBox != null) {
//IME=OFF
InputMethod.SetPreferredImeState(textBox, InputMethodState.Off);

//登録しているいないにかかわらず、削除を実行してもエラーにはならない
//多重呼び出しを抑える為の保険的なコード
textBox.GotKeyboardFocus -=
new KeyboardFocusChangedEventHandler(TextBox_GotKeyboardFocus);
//フォーカスよりは、キーボードフォーカス(カレット出現)がいいかも?
textBox.GotKeyboardFocus +=
new KeyboardFocusChangedEventHandler(TextBox_GotKeyboardFocus);
}

return;
}

/// <summary>
/// キーボードフォーカス取得イベント用メソッド
/// </summary>
/// <param name="sender">イベントソース</param>
/// <param name="e">イベントデータ</param>
private void TextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
if (!this.customizeFormat_) {
return;
}

//所定の部分を選択状態にします。
var textBox = sender as DatePickerTextBox;
DateTime dateTime;

//日付に変換できるときだけ適用する
if (DateTime.TryParse(textBox.Text, out dateTime)) {
textBox.Text = this.ToEditingDateFormat(dateTime);
}

return;
}

○SelectedDateChangedイベント用メソッド
/// <summary>
/// 選択日付変更イベント用メソッド
/// </summary>
/// <param name="sender">イベントソース</param>
/// <param name="e">イベントデータ</param>
private void DatePickerEx_SelectedDateChanged(object sender, SelectionChangedEventArgs e) {

var datePicker = sender as DatePickerEx;

if (datePicker.SelectedDate == null || !datePicker.customizeFormat_) {
return;
}

if (datePicker.Template == null) {
//テンプレートがない?
return;
}

//テンプレート内のテキストボックスを検索します。
var dateTextBox = datePicker.Template.FindName("PART_TextBox", datePicker)
as DatePickerTextBox;

if (dateTextBox != null) {

if (string.IsNullOrWhiteSpace(dateTextBox.Text)) {
return;
}

//編集中の書式を強制できますよ?
if (datePicker.IsFocused || dateTextBox.IsFocused) {
dateTextBox.Text = this.ToEditingDateFormat(
datePicker.SelectedDate.Value);

} else {
dateTextBox.Text = datePicker.SelectedDate.Value.
ToString(this.CustomDateFormat);
}
}
}

○Unloaded用メソッド
/// <summary>
/// Unloadedイベント用メソッド
/// </summary>
/// <param name="sender">イベントソース</param>
/// <param name="e">イベントデータ</param>
private void DatePickerEx_Unloaded(object sender, RoutedEventArgs e) {

if (this.ownerWindow_ != null) {
this.ownerWindow_.Closed -= new EventHandler(Window_Closed);
this.ownerWindow_ = null;
}
}
Unloadedイベントで、Loadedイベントで登録したウィンドウ終了用のメソッドを削除している。Unloadedイベントの中では、Window.GetWindowメソッドが使えない(戻り値はnullになる)為、内部変数として確保している。削除しておかないと、Loadedの度に登録され、登録された回数分だけ発生する。

○画面終了イベント
/// <summary>
/// ウィンドウ終了イベント用メソッド
/// </summary>
/// <param name="sender">イベントソース</param>
/// <param name="e">イベントデータ</param>
private void Window_Closed(object sender, EventArgs e) {
var window = sender as Window;
window.Closed -= new EventHandler(Window_Closed);

this.Loaded -= new RoutedEventHandler(DatePickerEx_Loaded);
this.Unloaded -= new RoutedEventHandler(DatePickerEx_Unloaded);

if (this.Template != null) {
var textBox = this.Template.FindName("PART_TextBox", this) as DatePickerTextBox;

if (textBox != null) {
textBox.GotKeyboardFocus -=
new KeyboardFocusChangedEventHandler(TextBox_GotKeyboardFocus);
}
}

return;
}
ここで登録したイベントからメソッドを削除しておく。やっておかないときっちり(?)リークするし。
続く
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


サイドバー背後固定表示サンプル

当ブログに書かれたソースコードは流用自由です。

バグ、スペルミス等はありうる事です。

ご利用の際は自己責任でお願いしますm(_ _)m