気楽なソフト工房

プログラミングについていろいろな記事を書いています。



mykonos2008

Author:mykonos2008
システムエンジニアとして働いている30代の会社員です。
仕事や趣味でプログラムを書いている方の役に立つ記事を書いていきたいと思っています。
ご意見、ご感想はこちらまで
If you are an english speaker,Please visit my english blog.

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
「TabControlのTabを閉じられるようにする」は前回で完了と思っていたのですが、開発を進める
うちに問題が有ることに気づきました。

 private void closeButton_Click(object sender, RoutedEventArgs e)
 {
     //ClosePageEventを発生させる
     RaiseEvent(new RoutedEventArgs(ClosePageEvent, this));

     //TabControlを取得し、自身を削除する
     TabControl tabControl = Parent as TabControl;
     tabControl.Items.Remove(this);

     e.Handled = true;
 }

これは前回、紹介したルーティングイベントを発生させて、TabControlからページを削除する部分です。
ここでは、自身を削除する前に、ルーティングイベントを発生させているので、イベントを処理する側にイベントが
届いた時点では、まだTabControlにはページが有る状態なのです。

イベントを処理する側では、既に削除されていることを前提に処理したいので、これは問題でした。。
かといって、単純にルーティングイベントを発生させる前に、自身を削除してしまうとイベントが上位のツリー要素に
届かなくなってしまいます。

そこで、今度はTabControlを拡張して、ページの閉じるボタンが押された際のイベントを処理し、TabControlが該当ページを
自身から削除する方式に変えました。

まずは、TabPageの方を以下のように変更。クラス名も「ExtendedTabItem」としました。

 public static readonly RoutedEvent CloseButtonClickEvent = 
             EventManager.RegisterRoutedEvent("CloseButtonClick", RoutingStrategy.Bubble,
                             typeof(RoutedEventHandler), typeof(ExtendedTabItem));

 public event RoutedEventHandler CloseButtonClick
 {
     add { AddHandler(CloseButtonClickEvent, value); }
     remove { RemoveHandler(CloseButtonClickEvent, value); }
 }

 public override void OnApplyTemplate()
 {
     base.OnApplyTemplate();

     Button closeButton = base.GetTemplateChild("CloseButton") as Button;
     closeButton.Click += new RoutedEventHandler(closeButton_Click);
 }

 private void closeButton_Click(object sender, RoutedEventArgs e)
 {
     //CloseButtonClickEventを発生させる
     RaiseEvent(new RoutedEventArgs(CloseButtonClickEvent, this));

     //処理済にする
     e.Handled = true;
 }

「閉じる」ボタンがクリックされた時に、自身を削除する処理は行わず、閉じるボタンが押されたことを伝えるためのルーティングイベントを発生させるだけにしました。

そして、「TabControl」を拡張し、「ExtendedTabControl」というクラスを作成しました。
このクラスは、外観は「TabControl」のものをそのまま引継ぎ、挙動のみを拡張しました。

 static ExtendedTabControl()
 {
     //外観はカスタマイズしないので、TabControlのスタイルを適用する
     DefaultStyleKeyProperty.OverrideMetadata(typeof(ExtendedTabControl), 
      new FrameworkPropertyMetadata(typeof(TabControl)));
 }
カスタムコントロールを作成すると自動的に挿入されている上記の部分なのですが、今回はここを少しいじって、TabControlの外観を利用するようにしました。
これをやらないと、XAMLの方でスタイルを定義しないといけなくなります。上記は簡単に言うと、ExtendedTabControlのスタイルにTabControlのスタイルを
適用してという意味です。

 public ExtendedTabControl()
 {
     AddHandler(ExtendedTabItem.CloseButtonClickEvent, new RoutedEventHandler(PageCloseButtonClick));
 }

先ほどExtendedTabItemで閉じるボタンが押された場合にルーティングイベントを発生させるようにしましたが、
ExtendedTabControlのコンストラクタで、そのイベントのハンドラを登録しています。

 public static readonly RoutedEvent PageCloseEvent = 
                         EventManager.RegisterRoutedEvent("PageClose", RoutingStrategy.Bubble,
                                       typeof(PageCloseEventHandler), typeof(TabControl));

 private void PageCloseButtonClick(Object sender, RoutedEventArgs e)
 {
     ExtendedTabItem page = e.OriginalSource as ExtendedTabItem;

     //自身からページを削除する
     Items.Remove(page);

     //ルーティングイベントを発生させる
     RaiseEvent(new PageCloseEventArgs(PageCloseEvent, this, page));
 }

ハンドラでは閉じるボタンがクリックされたページを自身から削除して、新たにページが閉じられた事を伝えるPageCloseEventを発生させています。
また、イベントの発生ソースに加えて、閉じられたページの情報をイベントの処理メソッドに伝えたかったのでRoutedEventArgsを拡張した
PageCloseEventArgsを作成しました。そしてそれを処理するためのデリゲートを新たに定義しました。

 public delegate void PageCloseEventHandler(Object sender,PageCloseEventArgs e);

 public class PageCloseEventArgs : RoutedEventArgs
 {
     private ExtendedTabItem _closedItem = null;

     public PageCloseEventArgs(RoutedEvent routedEvent, Object originalSource,
                                           ExtendedTabItem closedItem)
         : base(routedEvent,originalSource)
     {
         _closedItem = closedItem;
     }

     public ExtendedTabItem ClosedItem
     {
         get { return _closedItem; }
         set { _closedItem = value; }
     }

 }

これで本当にTabControlを閉じる部分は完了したと思います。

本日のソース





コメント

コメントの投稿

管理者にだけ表示を許可する

トラックバック

http://csfun.blog49.fc2.com/tb.php/26-63f30337

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。