Talen Kylon
Talen Kylon

Reputation: 1958

TabItem Header looks different as a Label

I have a TabItem and was previously setting the Header within the object like so,

<TabItem x:Name="Checked_Out_Items" Header="Clients In Use" Height="40" LostFocus="Checked_Out_Items_LostFocus" GotFocus="Checked_Out_Items_GotFocus" BorderThickness="0" >

However, I've run into the problem where there is not a Click event for this Tab. I found a solution where we can insert a label as the header specified here, how to handle TabItem single click event in WPF?

But, the Label looks nothing like what I need. Here is the Tab Header defined inside the object. enter image description here

Here's what it looks like with the label

        <TabItem x:Name="Checked_Out_Items" Height="40" LostFocus="Checked_Out_Items_LostFocus" GotFocus="Checked_Out_Items_GotFocus" BorderThickness="0" >
            <TabItem.Header>
                <Label Content="Clients In Use" Height="40" MouseLeftButtonDown="Checked_Out_Items_Clicked" Width="171" />
            </TabItem.Header>

enter image description here

Upvotes: 0

Views: 390

Answers (1)

grek40
grek40

Reputation: 13438

Lets separate the concerns a bit.

In order to handle a mouse click event, a control needs to be prepared for receiving this event, it needs to implement a handler and the handler must actually receive the event. In case of TabItem the mouse click event is consumed by the control, without releasing the event to user defined listeners.

On the level of TabItem, the best option would be to handle the PreviewMouseLeftButtonDown event, but this is not an option if event handling shouldn't occur when child controls have their own handling functionality.

So the other option is to handle the MouseLeftButtonDown event before it reaches the TabItem, which means to handle it in a child control of the tab item.

As said, in order to receive the event, the control needs to be ready to receive the event. This means, it needs a Background not null (can be Transparent) and IsHitTestEnabled="True" (which is default in most cases) and it must actually handle the event.

For the showcase, I use a Red instead of Transparent background color. The red area is the place where mouse clicks are captured and handled.

<TabItem Padding="0">
    <TabItem.Header>
        <Border Height="30" Width="50"
                Background="Red" MouseLeftButtonDown="Item_MouseLeftButtonDown">
            <ContentPresenter
                VerticalAlignment="Center" HorizontalAlignment="Center"
                Content="T2"/>
        </Border>
    </TabItem.Header>
    Test Content 2
</TabItem>

Or, in order to have a better separation between header content and click handling, a HeaderTemplate can be used:

<TabItem Header="T3" Padding="0">
    <TabItem.HeaderTemplate>
        <DataTemplate>
            <Border MinHeight="30" MinWidth="50"
                    Background="Red" MouseLeftButtonDown="Item_MouseLeftButtonDown">
                <ContentPresenter
                    VerticalAlignment="Center" HorizontalAlignment="Center"
                    Content="{Binding}"/>
            </Border>
        </DataTemplate>
    </TabItem.HeaderTemplate>
    Test Content 3
</TabItem>

The issue with any approach that relies on child controls is, that there is still a border of the TabItem and if the user clicks that border, the click will be outside of the child control and the tab will be selected without executing the click handler.

So a different way to handle tab changes (not clicks!) would be to handle the TabControl.SelectionChanged event and filter for events that actually originate from the TabControl and not from some inner content elements.

private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.Source == sender)
    {
        // this selection change is actually issued because of a tab change
    }
}

Another thing I just realized: The same condition could be used in TabItem.PreviewMouseLeftButtonDown in order to filter clicks to the tabitem header vs click events originating from the content area.

Edit:

The reason why Label is looking different is, that a font style is active for TabItem and Label is using some of its internal styles, ignoring the TabItem style.

Upvotes: 2

Related Questions