【问题标题】:WPF TabControl, change the background color of the TabItem with C# codesWPF TabControl,用C#代码改变TabItem的背景颜色
【发布时间】:2013-12-12 22:22:55
【问题描述】:

嗨,我认为这是一个初学者的问题。我已经搜索了所有相关的问题。但所有这些都由 .xaml 回答。但是,我需要的是后面的代码。 我有一个 TabControl。我需要设置其项目的背景颜色。 当项目被选中、未选中和悬停时,我需要为项目设置不同的颜色。 非常感谢你的帮助。 我想在这里发布我的代码。但是,目前,我只有一个 TabControl 实例和一个名为 ActiveTabIndex 的属性。

---------------------------------------编辑 1------ ------------------------------------------

我添加了一个事件 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;
            }
        }

但是,我实际上只能设置绿色。所选项目的背景颜色保持为默认颜色,而不是红色。对此有任何提示吗? 另外,我想知道如何为悬停添加事件。没有找到确切的事件。再次感谢。

-----------------------编辑 2---------- --------

经过长时间的长时间讨论。 我已经决定(实际上不是我的决定)使用 XAML。是的。我是 WPF 的新手。所以我对此仍有疑问(对此我感到非常抱歉,请多多包涵)。问题在这里: 当鼠标悬停在 TabItem 上时,我想将背景颜色更改为橙​​色。现在,当鼠标悬停在 ContentPanel 和 TabItem 上时,颜色为橙色。当鼠标仅在 TabItem 上方时,我需要它为橙色。 (我不确定我是否足够清楚。) 另一个问题是我会让用户设置颜色而不是直接设置为红色。我认为我需要一些绑定。对于这个问题,我稍后肯定会谷歌。只想说清楚。 非常感谢你们所有人。真的很有帮助。

<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>

------------- 编辑 3 ----

我认为我不够清楚。 现在是这样的: 如果鼠标在其他选项卡上,它工作正常:

但是当鼠标在圆圈区域上时,选中项的背景颜色应该是红色而不是橙色:

---------------编辑 4 -------

感谢大家的回复。 现在经过与我的用户和其他一些人的长时间讨论,我们想动态更改背景颜色。用户想自己设置颜色。基本上,我需要先做一些绑定(如果这是术语)。我试过以下。但是,选定的选项卡不是红色背景。我用Snoop查看,原来Background在本地设置为红色。我在这里有点困惑。我四处打听,有人给了我使用 TemplateBinding 的建议,因为它在 ControlTemplate 下。但是,我试图创建依赖属性和类似的东西。但是我不明白为什么要使用 TemplateBinding,因为我读过一些文章说它是用于编译时绑定。我完全糊涂了。我是 WPF 新手,如果问题是低级问题,我很抱歉。 再次感谢!

<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>

后面的代码是:

 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);
    }
}

【问题讨论】:

  • 显然您的问题的所有答案都由 XAML 回答,因为 这就是 XAML 的用途
  • HighCore 是对的——选中/取消选中/悬停由控件模板中的视觉状态定义设置。见这里:msdn.microsoft.com/en-us/library/ms754137(v=vs.110).aspx
  • 谢谢@HighCore!!我懂了。然而,这是我项目的设计。没有 XAML ......(我个人也不喜欢这个设计)。我正在努力。希望以后能有所收获。无论如何,XAML 应该被编译成代码。
  • @Payson 不是真的。 XAML 未编译为代码。 XAML 被编译为 BAML 并作为流读取。同样,对 UI 使用 XAML,对业务逻辑使用代码。不要对 UI 进行编码。 WPF不是winforms。学习一下。
  • 如果其他人继续以错误的方式推动项目,项目将会惨败,当它在地板上燃烧时我会盯着它笑。然后我会说,“我告诉过你 WPF 不像蹩脚的 winforms”

标签: c# wpf


【解决方案1】:

您发现自己的问题很难得到答案的原因是您完全错误地解决了这个问题;我能想到的情况很少,按照您的建议更改代码中的控件是合理的。 WPF 专门设计用于将视觉状态与代码分离,忽略这一点后果自负!

要实际回答您的问题,尽管以下内容可以解决问题...有点...

foreach (TabItem item in tabControl.Items)
    item.Background = new SolidColorBrush(Colors.Blue);

如果您这样做,您会注意到它会更改未选择选项卡的背景颜色,但不会更改当前选定选项卡的背景颜色。您还会注意到,用鼠标突出显示选项卡将再次显示另一种颜色。 TabItem 实际上有 7 种不同的视觉状态,添加代码来覆盖每种情况开始变得混乱,而且肯定比使用 XAML 复杂得多。

通过代码控制背景颜色的“正确”方法是使用 XAML 和数据绑定。首先转到Microsoft MSDN page for WPF TabControl Styles and Templates,您可以在其中找到 TabItem 的完整模板。将其粘贴到您的 Window.Resources 部分,现在您可以开始使用它的外观(不要忘记添加命名空间和资源)。如果您使用各种资源,您会注意到 TabItems 使用线性渐变,ControlLightColor 用于所有选项卡的顶部,ControlMediumColor 用于未选定选项卡的底部,而 ControlDarkColor 用于当前选定选项卡的底部.要在运行时控制这一点,您需要找到分散在样式中的这些资源的所有实例并将它们绑定到代码中的属性,然后编写一个 ValueConverter 将您的属性(我猜是布尔值)转换为刷子。另一种(更好的)方法,并且根本不需要编写任何额外代码的方法是使用 DataTrigger 来更改 TabItem 的视觉外观以响应您的属性更改值,但这有点过了“初学者”阶段,您需要提供有关您的具体案例的更多信息。

更新:这似乎对我有用:

void TabSet_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
    {
        foreach (TabItem item in tabControl.Items)
            item.Background = new SolidColorBrush(item.IsSelected ? Colors.Green : Colors.Red);
    }

我仍然说这是非常错误的。如果您绝对坚持在代码中执行此操作,那么您不应该使用 WPF。这完全是错误的技术,我不能强调这一点!

更新 #2:您快到了,您只需要在承载选项卡控件的窗口中执行此操作:

<Window x:Class="MyWpfApplication.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300" WindowState="Maximized">

    <Window.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="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>

    </Window.Resources>

    <TabControl>
        <TabItem Header="Foo" />
        <TabItem Header="Bar" />
        <TabItem Header="Baz" />
    </TabControl>

</Window>

【讨论】:

  • 非常感谢@Mark Feldman。我现在正在努力。我现在所做的如下:
  • 我添加了一个事件 SelectionChanged;我在那里设置了背景颜色。请查看我的编辑,因为这里没有足够的空间。
  • 再次更新...不知道为什么要尝试子类 TabItem,但在 WPF 中确实没有必要。
  • @MarkFeldman 您提供给 MSDN 资源的链接已失效
  • @SteffenWinkler 感谢您的提醒,就在前几天,我对一位同事感叹我对 MSDN 链接不断下降感到非常恼火。我已经相应地更新了答案中的链接。
【解决方案2】:

WPF 允许您基于现有控件创建新的自定义控件类型,然后您可以使用 Microsoft 网站上的模板/样式声明来填写它并更改位以适合您。创建一个名为 MyTabControl 的新用户控件,并将后面的代码替换为:

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();
    }
}

现在用这个替换 xaml(您需要将命名空间更改为您的项目):

<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>

现在在您的 MainWindow 或任何像常规 TabControl 一样使用它的地方,SelectedBgClr 将设置选定的选项卡标题和主面板背景(如果您查看上面的 XAML,您会看到两者的绑定):

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

请注意,后台代码很少,大部分工作仍然是 XAML,而 MyTabControl 仅用作依赖属性的包装器。在实际应用程序中,您将使用一种称为附加属性的东西,这样您就不需要派生一个全新的 TabControl 类。

【讨论】:

  • 谢谢!标记!嗯,我已经按照你的建议改了。但是,我的情况在这里有点不同。我不会在任何 XAML 文件中设置 SelectedBgClr="Red"。相反,用户将使用 C# 代码(或其他方式)设置它们。我只需要为我的用户打开一个 DependencyProperty 来处理选项卡的背景颜色。
  • 没关系,您可以在代码中设置依赖属性,方法是执行“myTab.SetValue(MyTabControl.SelectedBgClrProperty, Brushes.Red)”之类的操作。也可以在 块中声明画笔并在运行时更改其属性,在这种情况下,您将其称为 DynamicResource 而不是 StaticResource。
【解决方案3】:

将其放入您的 TabControlChanged 事件中:

foreach (TabItem AllTabItems in MyTabControl.Items) // Change MyTabControl with your TabControl name
{
    if (!AllTabItems.IsSelected)
    {
        // do something for all unselected tabitems
    }
    else if (AllTabItems.IsSelected)
    {
       // do something for the selected tabitem
    }
    else if (AllTabItems.IsMouseOver)
    {
       // do something for mouseover tabitem
    }
}

【讨论】:

    猜你喜欢
    • 2021-03-30
    • 2022-01-21
    • 2011-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-25
    相关资源
    最近更新 更多