気楽なソフト工房

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



mykonos2008

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

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
全体のレイアウト方針が決まったところで、作業開始。
初期状態ではWindowには「Grid」が貼り付けられているのでこれを「DockPanel」に貼り変えます。

些細なことですが、デザイナの上では貼り付けた「DockPanel」がWindowに対して、Fillされた状態に
ならないので、どうしたらいいのかな?といろいろ調べてみました。

結局、DockPanelの「Width」と「Height」が指定されている(Autoになっていないと)とFillされた状態にならないことに気づきました。
そりゃ、そうですよね。Windowsフォームに慣れているといろいろ戸惑いますね。。。

メインのウィンドウの構成は、「メニュー」と「ツールバー」そして、各画面を表示するエリアのコンテナになる「DockPanel」
を縦に並べました。前回、お話しましたように、各画面はユーザの操作により並べて表示したりしたいので
「TabControl」自体の貼り付けはC#の方から行いたいと思います。

・今日の時点での画面イメージ


予定としては各画面を同時に並べて表示する場合、2つのTabControlをDockPabelの左右に貼り付け、
各画面をそれぞれのTabControlに貼り付けます。通常の場合は、1つのTabControlに各画面をページとして並べます。

XAMLはこんな感じになります。

<Window x:Class="Paella.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Paella" Height="445" Width="499" Focusable="False">
    <DockPanel Name="_rootPanel">
        <Menu Height="22" Name="_menu" DockPanel.Dock="Top"/>
        <ToolBar Height="26" Name="_toolBar" DockPanel.Dock="Top">
            <Button Name="_inputBtn" Click="_inputBtn_Click" FontSize="12">振替伝票入力</Button>
            <Button Name="_refBtn">振替伝票の参照</Button>
        </ToolBar>
        <DockPanel Name="_tabPanel"/>
    </DockPanel>
</Window>

分かりやすいですよね。下手にデザイナで編集するより、XAMLを直接いじる方が効率が良い気がします。
このように直感的にレイアウトがどうなっているかを把握できるのはWPFの良さの1つですね。

次にDockPanelにTabControlを貼り付けるコードです。

_tabPanel.LastChildFill = true;
_leftTab = new TabControl();
_tabPanel.Children.Add(_leftTab);

DockPanelの「LastChildFill」をtrueに設定すると、最後に追加された
コントロールがFillの状態になるので、1つのコントロールしか配置しない場合は
これでOKです。

さて、いよいよ本日の本題の「TabControl」に動的にControlを追加する方法をです。
ツールバーにボタンを追加して、そのボタンがクリックされたら、振替伝票入力画面が
開くようにします。

private void _inputBtn_Click(object sender, RoutedEventArgs e)
{
    try
    {
        //振替伝票入力のユーザコントロール
        JournalEntry entry = new JournalEntry();
        AddTagPage(entry, "振替伝票入力");
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "エラー", MessageBoxButton.OK, MessageBoxImage.Warning);
    }
}

private void AddTagPage(UserControl control,String header)
{
     TabItem item = new TabItem();
     item.Header = header;
     item.Content = control;

     _leftTab.Items.Add(item);

     //追加されたページが最初のページの場合、
     //何故か、そのコンテンツが表示されない現象が
     //発生する。それを回避するため、2つ目のページを追加し
     //即座に削除している
     if (_leftTab.Items.Count == 1)
     {
         item = new TabItem();
         item.Header = "ダミー";
         item.Content = "ダミー";
         _leftTab.Items.Add(item);

         _leftTab.Items.Remove(item);
     }
}

「JournalEntry」は振替伝票画面を実装するユーザコントロールです。
まず、TabItemのインスタンスを生成します。そして、その「Header」プロパティに
Tabページのタイトルを、Contentに、「JournalEntry」のインスタンスを設定します。
先ほどと同じくユーザコントロールのWidthとHeightに具体的な数値が指定されていると
Fillされた状態にならないので、気をつけてください。

そして、最後に、TabControlのItemsにTabItemを追加して完了です。

通常はこれでOKなのですが、タブページが全く追加されていない状態で
イベントハンドラからこの処理を行った場合、ヘッダは表示されるのですが、
コンテントが表示されない現象が発生します。しかし、2つ目のTabページを追加すると、
1ページのコンテントも表示されます。コンストラクタから同じ処理を行った場合は、
1ページ目から問題なく表示されています。???原因が分かりません。う~ん、TabControlのバグかな?

とりあえず、対処として、1ページ目を追加した直後にダミーの2ページ目を追加して
すぐに削除するという処理を行うようにして回避しました。

本日のソース




コメント

TabControl.Items が空の状態でのTabItemの追加の問題、私のプロジェクトでも発生いたしました。私のところでは TabControl.SelectedIndex に 0を代入することで表示の更新が行われました。

Re: タイトルなし

Nさん、こんにちは。
なるほど、こちらの方が良いですね。参考になりました。

僕の場合
_leftTab.Items.Add(item);
のあとで、
_leftTab.SelectedItem = item;
にしました。
ボタンを押したときに、追加されたタブが前面に来るのが自然な気がします。

調べました

使っていたのがVBなので、少し違うかもしれません。
自分は、

TabItem item = new TabItem();
item.Header = header;
item.Content = control;
に、
   item.IsSelected = true;
を追加することで、
"そのコンテンツが表示されない現象"
を解決しました。

コメントの投稿

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

トラックバック

http://csfun.blog49.fc2.com/tb.php/23-57476838

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