How to Attach to MouseDown Event on WPF ListBox
2013-05-03 15:40
351 查看
I wanted to create drag and drop functionality between two list boxes – user should be able to drag items from one
For test, I created
boxes side by side:
In codebehind, I added simple handler for the
Press F5 and test. Clicked in the middle of the left listbox –
listbox and nothing happened. Item was selected, but no
handled event and it stopped propagating.
is described in MSDN article: Routed Events OverView.
In WPF, events can be routed in three ways: bubbling, tunneling and direct routing. Direct routing is not interesting because event fires only in control where it originated. Bubbling and tunneling routing propagate event through the visual tree.
Bubbling routes event from control where event was invoked to successive parent elements until it reaches the root.
Tunneling routes event in opposite direction, starting with element tree root and propagates until it reaches control where it was invoked. These are called “Preview” events.
Bubbling and tunneling events are often implemented in pairs. Tunneling events are always invoked first, before corresponding bubbling event.
are other controls in between like border and scrollviewer, but they could be abstracted here because they by default handle
When I click inside
is routed like this:
Event originates in
to
reaches the
does not change
handler, it would be invoked.
When I click on
with the selected item inside
to
Fortunately, there are two ways to work around this situation:
Use the “Preview” event which happens before the bubbling event. This event can be added in
to true, because it will prevent bubbling events to be invoked.
Add handler by using the
More details on this can be found in last section of MSDN article Marking Routed Events as Handled, and Class Handling.
Finally, here is the code that uses both approaches – one
XAML:
CodeBehind:
Note that in this version text is displayed in the title of the window instead of
was interfering with event propagation and item in left list box was not selected after click – looked like click never happened. It probably has something to do with the fact that there were other mouse events happening when I was closing message box. So,
be careful with actions in preview event.
For drag/drop handling I will use second approach – adding handler that receives handled events. Drag and drop functionality needs information about selected item. I could get that myself in preview event, but why, when there is code in event handler of ListBoxItem.
Referenced from: http://www.wpfnewbie.com/2010/07/22/how-to-attach-to-mousedown-event-on-listbox/
ListBoxto another.
For test, I created
MouseDownevent handler for list boxes. Here is
XAMLfor window with two list
boxes side by side:
01 | < Window x:Class = "ListBoxMouseEvents.Window1" |
02 | xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
03 | xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" |
04 | Title = "Window1" Height = "316" Width = "655" > |
05 | < Grid > |
06 | < Grid.ColumnDefinitions > |
07 | < ColumnDefinition /> |
08 | < ColumnDefinition Width = "20" /> |
09 | < ColumnDefinition /> |
10 | </ Grid.ColumnDefinitions > |
11 | < ListBox x:Name = "listBox1" Mouse.MouseDown = "ListBox_MouseDown" > |
12 | < ListBoxItem >Lorem ipsum dolor sit amet,</ ListBoxItem > |
13 | </ ListBox > |
14 | < ListBox Grid.Column = "2" x:Name = "listBox2" Mouse.MouseDown = "ListBox_MouseDown" > |
15 | < ListBoxItem >Lorem ipsum dolor sit amet,</ ListBoxItem > |
16 | </ ListBox > |
17 | </ Grid > |
18 | </ Window > |
MouseDownevents on both listboxes. Handler should popup messagebox with name of the listbox that triggered the event.
01 | public partial class Window1 : Window |
02 | { |
03 | public Window1() |
04 | { |
05 | InitializeComponent(); |
06 | } |
07 |
08 | private void ListBox_MouseDown(Object sender, MouseButtonEventArgs e) |
09 | { |
10 | ListBox listBox = (ListBox)sender; |
11 | MessageBox.Show( "MouseDown event on " + listBox.Name); |
12 | } |
13 | } |
MesasgeBoxpops up with correct name. Same for right listbox. Then I accidentally clicked on that one item in the
listbox and nothing happened. Item was selected, but no
MessageBox. Obviously,
ListBoxItemclass
handled event and it stopped propagating.
How routed events work in WPF
MouseDownis, like all mouse events in WPF, implemented as
RoutedEvent. Mechanics of routed events
is described in MSDN article: Routed Events OverView.
In WPF, events can be routed in three ways: bubbling, tunneling and direct routing. Direct routing is not interesting because event fires only in control where it originated. Bubbling and tunneling routing propagate event through the visual tree.
Bubbling routes event from control where event was invoked to successive parent elements until it reaches the root.
Tunneling routes event in opposite direction, starting with element tree root and propagates until it reaches control where it was invoked. These are called “Preview” events.
Bubbling and tunneling events are often implemented in pairs. Tunneling events are always invoked first, before corresponding bubbling event.
MouseDownis routed event that is routed by bubbling and his corresponding tunneling or preview event is
PreviewMouseDown.
Routing MouseDown event in ListBox
ListBoxcontrol contains
ItemsPresenterwhich contains
ListBoxItems(there
are other controls in between like border and scrollviewer, but they could be abstracted here because they by default handle
MouseDownevent same way as
ItemsPresenter).
When I click inside
ListBox, but not on
ListBoxItem,
MouseDownevent
is routed like this:
Event originates in
ItemsPresenterwhich is first control to receive event. Default handler does not set
Handledproperty
to
trueand event is propagated to its parents, who also do not change
Handledproperty, until it
reaches the
ListBox.
ListBoxfinds
ListBox_MouseDownhandler and it invokes it. Code shows
MessageBoxand
does not change
Handledproperty so event can be propagated further. If
Windowhad
MouseDownevent
handler, it would be invoked.
When I click on
ListBoxIteminside
ListBoxfollowing happens:
ListBoxItemis first control that receives event. It’s
MouseDownhandler have code that deals
with the selected item inside
ListBox(sets properties related to selection and changes visual appearance). Finally it sets
Handledproperty
to
true. This suggests that event does not need further handling.
Work around: how to handle ‘handled’ routed events
Fortunately, there are two ways to work around this situation:Use the “Preview” event which happens before the bubbling event. This event can be added in
XAML. When using this approach, you should be careful not to set
Handledproperty
to true, because it will prevent bubbling events to be invoked.
Add handler by using the
handledEventsToosignature of
AddHandler(RoutedEvent, Delegate, Boolean). Limitation of this workaround is that it can be set only in code, not in
XAML.
More details on this can be found in last section of MSDN article Marking Routed Events as Handled, and Class Handling.
Finally, here is the code that uses both approaches – one
ListBoxhave preview event attached, while the other has handler added in code.
XAML:
01 | < Window x:Class = "ListBoxMouseEvents.Window1" |
02 | xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
03 | xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" |
04 | Title = "Window1" Height = "316" Width = "655" > |
05 | < Grid > |
06 | < Grid.ColumnDefinitions > |
07 | < ColumnDefinition /> |
08 | < ColumnDefinition Width = "20" /> |
09 | < ColumnDefinition /> |
10 | </ Grid.ColumnDefinitions > |
11 | < ListBox x:Name = "listBox1" Mouse.PreviewMouseDown = "ListBox_MouseDown" > |
12 | < ListBoxItem >Lorem ipsum dolor sit amet,</ ListBoxItem > |
13 | < ListBoxItem >consectetur adipiscing elit. </ ListBoxItem > |
14 | < ListBoxItem >Duis mollis egestas ornare. </ ListBoxItem > |
15 | </ ListBox > |
16 | < ListBox Grid.Column = "2" x:Name = "listBox2" > |
17 | < ListBoxItem >Lorem ipsum dolor sit amet,</ ListBoxItem > |
18 | < ListBoxItem >consectetur adipiscing elit.</ ListBoxItem > |
19 | < ListBoxItem >Duis mollis egestas ornare.</ ListBoxItem > |
20 | </ ListBox > |
21 | </ Grid > |
22 | </ Window > |
01 | public partial class Window1 : Window |
02 | { |
03 | public Window1() |
04 | { |
05 | InitializeComponent(); |
06 | // Add handler. Note third parameter: handledEventsToo = true |
07 | listBox2.AddHandler(UIElement.MouseDownEvent, |
08 | new MouseButtonEventHandler(ListBox_MouseDown), true ); |
09 | } |
10 |
11 | private void ListBox_MouseDown(Object sender, MouseButtonEventArgs e) |
12 | { |
13 | ListBox listBox = (ListBox)sender; |
14 | this .Title = "MouseDown event on " + listBox.Name; |
15 | } |
16 | } |
MessageBox. I changed it because showing message box in
PreviewMouseDownevent
was interfering with event propagation and item in left list box was not selected after click – looked like click never happened. It probably has something to do with the fact that there were other mouse events happening when I was closing message box. So,
be careful with actions in preview event.
For drag/drop handling I will use second approach – adding handler that receives handled events. Drag and drop functionality needs information about selected item. I could get that myself in preview event, but why, when there is code in event handler of ListBoxItem.
Referenced from: http://www.wpfnewbie.com/2010/07/22/how-to-attach-to-mousedown-event-on-listbox/
相关文章推荐
- How to Attach to MouseDown Event on WPF ListBox
- How to get the MouseEvent coordinates for an element that has CSS3 Transform?
- [Selenium]How to click on a hidden link ,move to the drop down menu and click submenu
- how can i change the back color on mouse out to the color specified in gridview
- How to Use the Mouse Wheel Event in HTML5 Pages
- How to Determine the Blocking Session for Event: 'cursor: pin S wait on X' (文档 ID 786507.1)
- [WP7] How to press the mouse on a control, and detect MouseLeftButtonUp on another
- [Code Snippet]How to shut down the computer on C#
- How to invoke a JSF managed bean on a HTML DOM event using native JavaScript?
- how to set onclick event priority on both client & server
- WPF中的MVVM模式:How to render dynamic controls on the fly in MvvM pattern
- js中window.createPopup()方法以及attachEvent("onmouseover",OverFuncOne)实例
- How to Move ListBox Items with the Mouse
- How to simulate Mouse Click event
- how to catch the NIC interrupt(up/down) event?
- How to handle the MouseLeftButtonDown and MouseLeftButtonUp events of the Button control?
- How to Find Blocking Session for Mutex Wait Event cursor: pin S wait on X
- Experience share on how to perform trouble shooting – a CRM Central Instance down problem
- how to remove MouseListener / ActionListener on a JTextField
- How to get the MouseEvent coordinates for an element that has CSS3 Transform?