且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

WPF的TabControl,改变TabItem的背景颜色与C#代码

更新时间:2022-10-23 12:09:04

WPF使您可以创建基于现有的控制新的自定义控制类型,则可以与Microsoft网站上的模板/样式声明填好并更改位适合你。创建一个名为MyTabControl一个新的用户控件以及与此替换的背后代码:

 公共部分类MyTabControl:TabControl的
{
公共静态只读的DependencyProperty SelectedBgClrProperty = DependencyProperty.Register(SelectedBgClr,
的typeof(刷)的typeof(MyTabControl),新UIPropertyMetadata(NULL));

[类别(外观)]
公共刷SelectedBgClr
{
得到
{
返回(刷)的GetValue(SelectedBgClrProperty) ;
}

{
的SetValue(SelectedBgClrProperty,值);
}
}

公共MyTabControl()
{
的InitializeComponent();
}
}

现在替换这个XAML(你需要更改命名空间无论你的项目):

 < TabControl的X:类=TabDemo.MyTabControl
的xmlns =http://schemas.microsoft.com/winfx/2006/xaml/presentation
的xmlns:X =http://schemas.microsoft.com/winfx/2006/xaml
的xmlns:MC =http://schemas.openxmlformats.org/markup-compatibility/2006
的xmlns:D =http://schemas.microsoft.com/expression/blend/2008
MC:可忽略=D
NAME =TabControl的
D:DesignHeight =300D:DesignWidth =300>

< TabControl.Resources>

<风格的TargetType ={X:类型TabItem的}>
< setter属性=模板>
< Setter.Value>
<的ControlTemplate的TargetType ={X:类型TabItem的}>
<网格和GT;
< BORDER NAME =边框保证金=0,0,-4,0了borderThickness =1,1,1,1CornerRadius =2,12,0,0>
< ContentPresenter X:NAME =ContentSiteVerticalAlignment =中心的Horizo​​ntalAlignment =中心ContentSource =头保证金=12,2,12,2RecognizesAccessKey =真/>
< /边框>
< /网格和GT;
< ControlTemplate.Triggers>
<触发属性=IsSelectedVALUE =真>
< setter属性=Panel.ZIndexVALUE =100/>
<二传手的TargetName =边框属性=背景VALUE ={绑定的ElementName = TabControl的,路径= SelectedBgClr}/>
< setter属性=前景VALUE =黄色/>
<二传手的TargetName =边框属性=了borderThicknessVALUE =1,1,1,0/>
< /触发>
<触发属性=IsSelectedVALUE =FALSE>
<二传手的TargetName =边框属性=背景值=绿色/>
< setter属性=前景VALUE =艾莉斯蓝/>
< /触发>
<触发属性=IsMouseOverVALUE =真>
<二传手的TargetName =边框属性=背景值=橙色/>
< setter属性=前景VALUE =黑/>
< /触发>
< /ControlTemplate.Triggers>
< /控件模板>
< /Setter.Value>
< /二传手>
< /样式和GT;
< /TabControl.Resources>

< TabControl.Style>
<风格的TargetType ={X:类型的TabControl}>
< setter属性=OverridesDefaultStyle
值=真/>
< setter属性=SnapsToDevicePixels
值=真/>
< setter属性=模板>
< Setter.Value>
<的ControlTemplate的TargetType ={X:类型的TabControl}>
<电网KeyboardNavigation.TabNavigation =本地>
< Grid.RowDefinitions>
< RowDefinition高度=自动/>
< RowDefinition高度=*/>
< /Grid.RowDefinitions>
< VisualStateManager.VisualStateGroups>
< VisualStateGroup X:NAME =CommonStates>
<的VisualState X:名称=已禁用>
<情节提要>
< ColorAnimationUsingKeyFrames Storyboard.TargetName =边框
Storyboard.TargetProperty =。(Border.BorderBrush)
(SolidColorBrush.Color)>
将; EasingColorKeyFrame KeyTime =0
值=#FFAAAAAA/>
< / ColorAnimationUsingKeyFrames>
< /故事板>
< /&的VisualState GT;
< / VisualStateGroup>
< /VisualStateManager.VisualStateGroups>
将;的TabPanel X:名称=HeaderPanel
Grid.Row =0
Panel.ZIndex =1
保证金=0,0,4, - 1
IsItemsHost =真
KeyboardNavigation.TabIndex =1/>
< BORDER X:名称=边框
Grid.Row =1
了borderThickness =1
CornerRadius =2
KeyboardNavigation.TabNavigation =本地
KeyboardNavigation.DirectionalNavigation =含有
KeyboardNavigation.TabIndex =2背景={绑定的ElementName = TabControl的,路径= SelectedBgClr}>
< ContentPresenter X:NAME =PART_SelectedContentHost
保证金=4
ContentSource =SelectedContent/>
< /边框>
< /网格和GT;
< /控件模板>
< /Setter.Value>
< /二传手>
< /样式和GT;
< /TabControl.Style>





在你的主窗口或任何现在只是用它,你会经常的TabControl,在SelectedBgClr同时设置选定的选项卡头和主面板背景(如果你在XAML看你上面已经看到两者绑定):

 <局部:MyTabControl SelectedBgClr =红&GT; 
&LT; TabItem的标题=富/&GT;
&LT; TabItem的标题=酒吧/&GT;
&LT; TabItem的标题=巴兹/&GT;
&LT; /地方:MyTabControl&GT;



注意,后面的代码是最小的,它仍然是XAML是在做大量的工作和MyTabControl的只是用作依赖项属性的包装。在实际的应用中,你将使用一种叫做附加属性,这样你就不需要推导出一个全新的TabControl类。


Hi I think this is a beginners questions. I've searched all the related questions. But all of them are answered by .xaml. However, what I need is the back code. I have a TabControl. I need to set the background color of its items. I need to set different colors for the items when it is selected, unselected and hover. Thank you so much for your help. I want to post my codes here. However, currently, all I have is an instance of the TabControl and one property called ActiveTabIndex.

---------------------------------------Edit 1-----------------------------------------------

I have added an event SelectionChanged

(this.myTabControl as System.Windows.Controls.TabControl).SelectionChanged += TabSet_SelectionChanged;

void TabSet_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
            foreach (System.Windows.Controls.TabItem item in (this.myTabControl as System.Windows.Controls.TabControl).Items)
            {
                if (item == (this.myTabControl as System.Windows.Controls.TabControl).SelectedItem)
                {
                    item.Background = System.Windows.Media.Brushes.Red;
                }
                else
                    item.Background = System.Windows.Media.Brushes.Green;
            }
        }

However, I can only set the Green actually. The background color of the selected item keeps as the default color instead of red. Any hints about this? Also, I would like to know how to add event for the hover. Haven't find the exact event. Thanks again.

-----------------------Edit 2------------------------------

After a long long long discussion. I've decided (actually not my decision) to use the XAML. Yeah. I am new to WPF. So I still have questions about this (I am so sorry for this, Please bear me). The questions are here: I would like to change the background color to Orange when the mouse is over the TabItem. Now the color is Orange when the mouse is over the ContentPanel and TabItem. I need it to be orange when the mouse is over the TabItem only. (I am not sure I am clear enough.) Another question is that I would let users to set the color instead of setting is to red directly. I need some bindings I think. For this question, I will google later for sure. Just want to be clear. Thank you so much for all of you. Really helpful.

<TabItem x:Class="MyControls.Tab"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <TabItem.Style>
        <Style TargetType="{x:Type TabItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabItem}">
                        <Grid>
                            <Border  Name="Border" Margin="0,0,-4,0" BorderThickness="1,1,1,1" CornerRadius="2,12,0,0" >
                                <ContentPresenter x:Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="12,2,12,2" RecognizesAccessKey="True"/>
                            </Border>
                        </Grid>
                        <ControlTemplate.Triggers>

                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="Panel.ZIndex" Value="100" />
                                <Setter TargetName="Border" Property="Background" Value="Red" />
                                <Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
                            </Trigger>

                            <Trigger Property="IsSelected" Value="False">
                                <Setter TargetName="Border" Property="Background" Value="Green" />                                
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="Border" Property="Background" Value="Orange" />
                            </Trigger>

                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </TabItem.Style>
</TabItem>

------------- Edit 3 ----------------

I am not clear enough I think. Here is what it is now: It's working fine if the mouse is over other tabs:

But When the mouse is over the circled area, the background color of the selected item should be red instead of orange:

---------------Edit 4 -------------------

Thanks for all of you for your reply. Now after a long discussion with my users and some others, we would like to change the background color dynamically. The user wants to set the color by themselves. Basically, I need first do some binding (if this is the term). I've tried the following. However, the selected tab is not with red background. I used the Snoop to check out, it turns out that the Background is set as red locally. I am a little confusing here. I've asked around, and someone gave me the suggestion to use TemplateBinding since it is under ControlTemplate. But, I've tried to create dependency property and something like that. But just I don't understand why should I use TemplateBinding since I read some article said that it is for compile time binding. I am totally confused. I am new to WPF, I am sorry if the question is low level question. Thanks again!

<TabItem x:Class="MyControl.Tab"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <TabItem.Style>
        <Style TargetType="{x:Type TabItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TabItem}">
                        <Grid>
                            <Border  Name="Border" Margin="0,0,-4,0" BorderThickness="1,1,1,1" CornerRadius="2,12,0,0" >
                                <ContentPresenter x:Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="12,2,12,2" RecognizesAccessKey="True"/>
                            </Border>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="Panel.ZIndex" Value="100" />
                                <Setter TargetName="Border" Property="Background" Value="{Binding SelectedBgClr}" />
                                <Setter Property="Foreground" Value="Yellow" />
                                <Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
                            </Trigger>                            
                            <Trigger Property="IsSelected" Value="False">
                                <Setter TargetName="Border" Property="Background" Value="Green" /> 
                                <Setter Property="Foreground" Value="AliceBlue"/>
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="Border" Property="Background" Value="Orange" />
                                <Setter Property="Foreground" Value="Black"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </TabItem.Style>
</TabItem>

The behind code is:

 public Tab()
        {
            SelectedBgClr = new SolidColorBrush(Colors.Red);
            //UnSelectedBgClr = new SolidColorBrush(Colors.Green);
            //HoverBgClr = new SolidColorBrush(Colors.Orange);
            InitializeComponent();

        }
public static readonly DependencyProperty SelectedBgClrProperty = DependencyProperty.Register("SelectedBgClr", typeof(Brush), typeof(Tab), new UIPropertyMetadata(null));
public Brush SelectedBgClr
{
    get
    {
        return (Brush)GetValue(SelectedBgClrProperty);
    }
    set
    {
        SetValue(SelectedBgClrProperty, value);
    }
}

WPF lets you create a new custom control type based on an existing control, you can then fill it out with the template/style declaration on the Microsoft site and change the bits to suit you. Create a new user control called MyTabControl and replace the behind code with this:

public partial class MyTabControl : TabControl
{
    public static readonly DependencyProperty SelectedBgClrProperty = DependencyProperty.Register("SelectedBgClr",
        typeof(Brush), typeof(MyTabControl), new UIPropertyMetadata(null));

    [Category("Appearance")]
    public Brush SelectedBgClr
    {
        get
        {
            return (Brush)GetValue(SelectedBgClrProperty);
        }
        set
        {
            SetValue(SelectedBgClrProperty, value);
        }
    }

    public MyTabControl()
    {
        InitializeComponent();
    }
}

Now replace the xaml with this (you'll need to change the namespace to whatever your project is):

<TabControl x:Class="TabDemo.MyTabControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         Name="tabControl"
         d:DesignHeight="300" d:DesignWidth="300">

<TabControl.Resources>

    <Style TargetType="{x:Type TabItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TabItem}">
                    <Grid>
                        <Border  Name="Border" Margin="0,0,-4,0" BorderThickness="1,1,1,1" CornerRadius="2,12,0,0" >
                            <ContentPresenter x:Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="12,2,12,2" RecognizesAccessKey="True"/>
                        </Border>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="Panel.ZIndex" Value="100" />
                            <Setter TargetName="Border" Property="Background" Value="{Binding ElementName=tabControl, Path=SelectedBgClr}" />
                            <Setter Property="Foreground" Value="Yellow" />
                            <Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
                        </Trigger>
                        <Trigger Property="IsSelected" Value="False">
                            <Setter TargetName="Border" Property="Background" Value="Green" />
                            <Setter Property="Foreground" Value="AliceBlue"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="Border" Property="Background" Value="Orange" />
                            <Setter Property="Foreground" Value="Black"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</TabControl.Resources>

<TabControl.Style>
    <Style  TargetType="{x:Type TabControl}">
        <Setter Property="OverridesDefaultStyle"
          Value="True" />
        <Setter Property="SnapsToDevicePixels"
          Value="True" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TabControl}">
                    <Grid KeyboardNavigation.TabNavigation="Local">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                Storyboard.TargetProperty="(Border.BorderBrush).
                    (SolidColorBrush.Color)">
                                            <EasingColorKeyFrame KeyTime="0"
                                         Value="#FFAAAAAA" />
                                        </ColorAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <TabPanel x:Name="HeaderPanel"
                    Grid.Row="0"
                    Panel.ZIndex="1"
                    Margin="0,0,4,-1"
                    IsItemsHost="True"
                    KeyboardNavigation.TabIndex="1" />
                        <Border x:Name="Border"
                  Grid.Row="1"
                  BorderThickness="1"
                  CornerRadius="2"
                  KeyboardNavigation.TabNavigation="Local"
                  KeyboardNavigation.DirectionalNavigation="Contained"
                  KeyboardNavigation.TabIndex="2" Background="{Binding ElementName=tabControl, Path=SelectedBgClr}">
                            <ContentPresenter x:Name="PART_SelectedContentHost"
                              Margin="4"
                              ContentSource="SelectedContent" />
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</TabControl.Style>

Now in your MainWindow or whatever just use it as you would a regular TabControl, the SelectedBgClr will set both the selected tab header and the main panel background (if you look in the XAML above you've see bindings for both):

<local:MyTabControl SelectedBgClr="Red">
        <TabItem Header="Foo"  />
        <TabItem Header="Bar" />
        <TabItem Header="Baz" />
    </local:MyTabControl>

Notice that the behind-code is minimal, it's still XAML that's doing the bulk of the work and MyTabControl is simply used as a wrapper for the dependency property. In a real application you would use something called an attached property so that you wouldn't need to derive a whole new TabControl class.