none
ControlPresenter内のTextBlockの色をTriggerで変えたい RRS feed

  • 質問

  • お世話になっています。

    質問の内容はこちらと全くいっしょです。

    http://stackoverflow.com/questions/11068249/contentpresenter-triggers-not-working

    TabItemのヘッダー内の文字列を加工(複数行表示等)したいため、HeaderにTextBlockを挿入しています。

    <TabItem.Header>
         <TextBlock LineHeight="20" LineStackingStrategy="BlockLineHeight" Name="header1" MinWidth="100" TextAlignment="Center">
              リスト1 <LineBreak/>
              (10)
        </TextBlock>
    </TabItem.Header>

    タブヘッダーを選択したときに、このTextBlockの文字色を変えたいので、リンク先と同じようにトリガーを引っ掛けて見たのですが変わりません。Headerに直接文字列を挿入した場合は変わりますが、TextBlockなどの他のオブジェクトには反映されないようです。

    何か良い手段はないでしょうか?


    2013年2月5日 9:30

回答

  • TabItem.HeaderTemplateを使えば良いかと。

    <Window x:Class="WpfApplication20.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <Style TargetType="TabItem">
                <Setter Property="HeaderTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <TextBlock Name="headerTextBlock"  Text="{Binding}" LineHeight="20" LineStackingStrategy="BlockLineHeight" MinWidth="100" TextAlignment="Center"/>
                            
                            <DataTemplate.Triggers>
                                <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}},Path=IsSelected}" Value="True">
                                    <Setter TargetName="headerTextBlock" Property="Foreground" Value="Red"/>
                                </DataTrigger>
                            </DataTemplate.Triggers>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Window.Resources>
        
        <Grid>
            <TabControl>
                <TabItem Header="リスト1&#xd;&#xa;(10)"/>
                <TabItem Header="リスト2&#xd;&#xa;(20)"/>
            </TabControl>
        </Grid>
    </Window>
    

    TabItem.HeaderTemplateでスタイルとトリガを設定し、個々のTabItemはヘッダ文字列だけ指定してやります。
    ちなみに改行を挟みたい時はLineBreak以外にも『&#xd;&#xa;』でもOKです。

    以上、参考まで。

    • 回答としてマーク NZ-000 2013年2月6日 2:52
    2013年2月5日 10:31
  • できなくは無いですよ。というかやり方は色々あるので・・・
    例えばこんな感じで。

    <Window x:Class="WpfApplication21.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        
        <Window.Resources>
            <Style x:Key="headerTextStyle" TargetType="TextBlock">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}},Path=IsSelected}" Value="True">
                        <Setter Property="Foreground" Value="Red"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Window.Resources>
        
        <Grid>
            <TabControl>
                <TabItem>
                    <TabItem.Header>
                        <TextBlock Style="{StaticResource headerTextStyle}" LineHeight="20" LineStackingStrategy="BlockLineHeight" Name="header1" MinWidth="100" TextAlignment="Center">
                            リスト1 <LineBreak/>
                            (10)
                        </TextBlock>
                    </TabItem.Header>
                </TabItem>
                
                <TabItem>
                    <TabItem.Header>
                        <TextBlock Style="{StaticResource headerTextStyle}" LineHeight="20" LineStackingStrategy="BlockLineHeight" Name="header2" MinWidth="100" TextAlignment="Center">
                            リスト2 <LineBreak/>
                            (20)
                        </TextBlock>
                    </TabItem.Header>
                </TabItem>
            </TabControl>
        </Grid>
    </Window>
    

    こちらはTextBlockのStyleを定義してやって、それを個々のHeader内のTextBlockに紐付けてやる方法です。もちろんTextBlock.StyleはHeader毎にベタ書きしてもOKです(煩雑になりますけどね・・・)。
    私がTemplateを利用する方法を最初に挙げたのは、まぁ好みの問題でもあるんですが(笑)、TabControlはItemsControl派生なので、ItemsSourceへのBindingと組み合わせてTabPageが動的に生成される事を念頭に置いているからです。静的に利用するのであればこの方法に拘る必要はありません。
    ただViewModelをちゃんと作った場合、親元のViewModel内にTabPage毎のViewModelを配列で持って、TabControl.ItemsSourceにBindingする形になるかなーと思うので、自然とTemplateを使う形に考えが向いてしまうので・・・(苦笑)
    あとは外観定義はResourceにまとめてしまった方がすっきりするかな、という書き方の好みもありますね。
    • 回答としてマーク NZ-000 2013年2月8日 5:11
    2013年2月7日 9:19

すべての返信

  • TabItem.HeaderTemplateを使えば良いかと。

    <Window x:Class="WpfApplication20.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <Style TargetType="TabItem">
                <Setter Property="HeaderTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <TextBlock Name="headerTextBlock"  Text="{Binding}" LineHeight="20" LineStackingStrategy="BlockLineHeight" MinWidth="100" TextAlignment="Center"/>
                            
                            <DataTemplate.Triggers>
                                <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}},Path=IsSelected}" Value="True">
                                    <Setter TargetName="headerTextBlock" Property="Foreground" Value="Red"/>
                                </DataTrigger>
                            </DataTemplate.Triggers>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Window.Resources>
        
        <Grid>
            <TabControl>
                <TabItem Header="リスト1&#xd;&#xa;(10)"/>
                <TabItem Header="リスト2&#xd;&#xa;(20)"/>
            </TabControl>
        </Grid>
    </Window>
    

    TabItem.HeaderTemplateでスタイルとトリガを設定し、個々のTabItemはヘッダ文字列だけ指定してやります。
    ちなみに改行を挟みたい時はLineBreak以外にも『&#xd;&#xa;』でもOKです。

    以上、参考まで。

    • 回答としてマーク NZ-000 2013年2月6日 2:52
    2013年2月5日 10:31
  • みっとさんのやり方で実現できました。

    ありがとうございます。

    ただ気になったことが1つあります。

    結果が全てですが、今回のような要望(色を変える等)を実現する場合、Headerで直接構造を作るアプローチを取っていると、対応は難しいということでしょうか?

    2013年2月6日 3:00
  • できなくは無いですよ。というかやり方は色々あるので・・・
    例えばこんな感じで。

    <Window x:Class="WpfApplication21.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        
        <Window.Resources>
            <Style x:Key="headerTextStyle" TargetType="TextBlock">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}},Path=IsSelected}" Value="True">
                        <Setter Property="Foreground" Value="Red"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Window.Resources>
        
        <Grid>
            <TabControl>
                <TabItem>
                    <TabItem.Header>
                        <TextBlock Style="{StaticResource headerTextStyle}" LineHeight="20" LineStackingStrategy="BlockLineHeight" Name="header1" MinWidth="100" TextAlignment="Center">
                            リスト1 <LineBreak/>
                            (10)
                        </TextBlock>
                    </TabItem.Header>
                </TabItem>
                
                <TabItem>
                    <TabItem.Header>
                        <TextBlock Style="{StaticResource headerTextStyle}" LineHeight="20" LineStackingStrategy="BlockLineHeight" Name="header2" MinWidth="100" TextAlignment="Center">
                            リスト2 <LineBreak/>
                            (20)
                        </TextBlock>
                    </TabItem.Header>
                </TabItem>
            </TabControl>
        </Grid>
    </Window>
    

    こちらはTextBlockのStyleを定義してやって、それを個々のHeader内のTextBlockに紐付けてやる方法です。もちろんTextBlock.StyleはHeader毎にベタ書きしてもOKです(煩雑になりますけどね・・・)。
    私がTemplateを利用する方法を最初に挙げたのは、まぁ好みの問題でもあるんですが(笑)、TabControlはItemsControl派生なので、ItemsSourceへのBindingと組み合わせてTabPageが動的に生成される事を念頭に置いているからです。静的に利用するのであればこの方法に拘る必要はありません。
    ただViewModelをちゃんと作った場合、親元のViewModel内にTabPage毎のViewModelを配列で持って、TabControl.ItemsSourceにBindingする形になるかなーと思うので、自然とTemplateを使う形に考えが向いてしまうので・・・(苦笑)
    あとは外観定義はResourceにまとめてしまった方がすっきりするかな、という書き方の好みもありますね。
    • 回答としてマーク NZ-000 2013年2月8日 5:11
    2013年2月7日 9:19
  • 非常に参考になります。

    特にResourceのDataTrigger辺りのところ。
    このようにで別の要素であるTabItemのイベントに関連付けする方法があればいいのに、と予てより思っていました。

    本当にありがとうございます。

    2013年2月8日 5:19