Reputation: 1334
Probably I have not really understood the event system in WPF.
I have a TabItem that has a header consisting of a TextBox and a Button. The TextBox is readonly. (In the real application it allows editing on double clicking, but that's irrelevant here.)
It was difficult to select a tab because the TextBox grabs the MouseLeftButtonDown event. I therefore added an event handler to the TabItem that brings it into foreground. However with that event handler the button no longer receives the event. Why does the button not get the event before the TabItem gets the event? I thought it bubbles from the leaves to the root of the logical tree.
Here's the XAML:
<Window x:Class="tt_WPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:tt_WPF"
Title="MainWindow" SizeToContent="WidthAndHeight">
<TabControl x:Name="TC"></TabControl>
</Window>
Here's the code behind:
public class myItem : TabItem
{
public myItem(string name)
{
// Create horizontal StackPanel
StackPanel sp = new StackPanel();
sp.Orientation = Orientation.Horizontal;
// Create a readonly TextBox
TextBox tb = new TextBox();
tb.Text = name;
tb.IsReadOnly = true;
// Create a Button with a simple command
Button b = new Button();
b.Content = "X";
b.Click += Button_Click;
// Add Button and TextBlock to StackPanel and StackPanel to this TabIten
sp.Children.Add(tb);
sp.Children.Add(b);
this.Header = sp;
this.Content = "This is " + name;
// --> Here's the trouble: Install an event handler that brings the TabItem into foreground when clicked
this.AddHandler(MouseLeftButtonDownEvent, new RoutedEventHandler(TabItem_MouseLeftButtonDownEvent), true);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Button X");
}
private void TabItem_MouseLeftButtonDownEvent(object sender, RoutedEventArgs e)
{
this.IsSelected = true;
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TC.Items.Add(new myItem("Tab 1"));
TC.Items.Add(new myItem("Tab 2"));
}
}
Upvotes: 1
Views: 1911
Reputation: 6260
The thing you have faced is called event routing in WPF. To prevent event from being routed to the next level you have to set Handled = true
. Also you can check for sender type which raised this event to filter out unnecessary calls.
private void TabItem_MouseLeftButtonDownEvent(object sender, RoutedEventArgs e)
{
this.IsSelected = true;
e.Handled = true;
}
There is a very nice diagram displaying events routing when it comes to user input (from MSDN):
So to get desired bottom->up routing path you need to change behavior to Bubble
instead of Tunnel
by using PreviewLeftMouseButtonDown
.
Upvotes: 3