views:

50

answers:

3

I'm trying to make only the header of the TabItem send an event.

So far I have my xaml...

    <TabControl>
        <TabItem Header="tab 1">
                 Any text
        </TabItem>
        <TabItem Header="tab 2">
            <TextBox>blah</TextBox>
        </TabItem>
        <TabControl.Resources>
            <Style TargetType="TabItem">
                <EventSetter Event="MouseDoubleClick" Handler="TabItemMouseDoubleClick"/>
            </Style>
        </TabControl.Resources>
    </TabControl>

...and my event handler...

void TabItemMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
}

Now, when double clicking the tab item header the event fires, when clicking the tab item content area it doesn't fire (which is what I want), but when I put a text box in the TabItem, the event fires upon double clicking the textbox. I'm trying to get only the header of the TabItem to fire the event - any ideas?

Thanks in advance.

A: 

What you're seeing is the effect of WPF's bubbling event model whereby events that happen in the children usually bubble up to the parent.

What you'll probably need to do is check the Source, or possibly the OriginalSource properties of the MouseButtonEventArgs, and only respond to events that are coming from TabItem types.

Another thing to try is checking the IsMouseDirectlyOver property which should return false if the mouse is inside the bounds of the parent, but is actually over a child element.

You might try setting IsHitTestVisible on, say, the TextBox in the tab item, but you would probably find that has undesirable side-effects, like not changing the selected tab when you click on the text.

Samuel Jack
The source always appears as the TabItem, regardless of the region clicked. The original source for a valid click varies, it can be the System.Windows.Documents.Run or System.Windows.Controls.Border etc. depending on the region of the header clicked. I could check for all these types, but I'd like to use a cleaner solution if possible.Should I be placing a template into the header?
+1  A: 

You can get the behaviour you want by using a HeaderTemplate as follows (this is very basic so you will need to fix it up to sort out the heights of the label...etc). Just replace your current eventsetter with this setter:

<Setter Property="HeaderTemplate">
    <Setter.Value>
        <DataTemplate>
            <Label Content={Binding}>
                <Label.Style>
                    <Style TargetType="Label">
                        <EventSetter Event="MouseDoubleClick" Handler="TabItemMouseDoubleClick"/>
                    </Style>
                </Label.Style>
            </Label>
        </DataTemplate>
    </Setter.Value>
</Setter>
Leom Burke
Thanks Leom, works perfectly.
A: 

For others, the final xaml to get the tabItems header only sending the event is...

    <TabControl>
        <TabItem Header="tab 1">
                 Any text
        </TabItem>
        <TabItem Header="tab 2">
            <TextBox>blah</TextBox>
        </TabItem>
        <TabControl.Resources>
            <Style TargetType="TabItem">

                <Setter Property="HeaderTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <Label Content="{Binding}">
                                <Label.Style>
                                    <Style TargetType="Label">
                                        <EventSetter Event="MouseDoubleClick" Handler="TabItemMouseDoubleClick"/>
                                    </Style>
                                </Label.Style>
                            </Label>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </TabControl.Resources>
    </TabControl>