Silverlight: How to route mouse events from one control to another? - silverlight

If I catch mouse move/mouse button down events in one control, how do I route the caught event to another control?
In MSDIN documentation I found WPF UIElement.RaiseEvent but it seems it doesn't exist in Silverlight.
The reason for this question is the following issue.
I have an application where user is able to pick a control on the screen to retrieve control's ID (a custom property). While user picks a control, I don't want default actions of the control to be triggered - no button clicks, no text highlighting, no link navigation etc. That's why when entering the "picking mode", I put a transparent overlay over my application and after user clicks on it I find the element behind the overlay, get its ID and remove the overlay.
This approach is working fine except one scenario when there is a scroll viewer on the screen and user might want to pick an element which is scrolled out of view. Thus when picking elements, user at first clicks on a scrollbar to scroll the required element into view, but the scrollbar doesn't work because its behind the overlay.
Currently I have working code which detects if the element under mouse cursor (and behind the overlay) is a scrollbar instance, and thus I ignore it for my picking process - my application doesn't require picking scrollbars. But how do I pass the mouse event from the overlay to the scrollbar behind?

The short answer is, you can't route the mouse events.
But what you can do is: as long as the mouse is hovered over a Scrollbar you can set the IsHitTestVisible property of your mouseClick catcher overlay to false. The click will just go through it. Or can you only detect the Scrollbar the moment the user clicks?

Related

RichTextBox scroll to end not working when not visible

I have a WPF RichTextBox in my application that sits in Grid. It gets updated every second or two as it displays logs (though sometimes there are no logs for up to a minute depending on the load).
The grid is not always visible, as it sits in its own tab. If the user is on another tab, the logger is not visible.
My problem is that I want the RichTextBox to scroll to the end every time a new paragraph is added. It seemed simple as there is a 'ScrollToEnd' method on the RichTextBox control and so I call that method every time text is added to the control.
The problem is that that method only works if the control is visible, if the user is on another tab, the RichTextBox will not scroll to the end and it looks weird when you click on the tab with the logger and after a couple of seconds or longer it scrolls to the bottom when it should already be at the bottom.
Is there a way around this annoying "feature" of the control? I would like to ALWAYS have the RichTextBox be at the bottom unless the user is manually taking control of the scroll bar.
Thanks!
By default, the TabControl actually doesn't change its contents visibility, it removes them from the view completely when you change tabs and then "re-attachs" them when you navigate back to the previous tab.
That's why the Visibility change doesn't get fired. Instead, you should handle the Loaded event, which should get fired right before the view is re-rendered.
Is there a reason you cannot simply call ScrollToEnd in response to the text box becoming visible? That seems like the simplest approach. Did you try it and run into an issue?
Edit: If you are using a TabControl, each TabItem has an IsSelected property you can bind to from the ItemContainerStyle. You could probably scroll your text box in response to the tab becoming selected.
As a separate note: if you are planning to make a custom control for this, here are some things to consider.
I wrote an auto-scrolling version of a FlowDocumentScrollViewer. (I never needed a RichTextBox specifically, but they display similar content.) I can tell you that there are a lot of things to account for, such as knowing when and when not to auto-scroll based on what the user is currently doing.
For example:
If the user takes over the scrolling themselves via the scrollbar or mousewheel, you don't want the control to fight with them.
If they start selecting text, you don't want to scroll it away from them mid selection.
If they scroll to the bottom, you probably want it to start auto-scrolling again.
Also, determining what the user is doing to begin with can sometimes be a complex process on its own.

MouseLeave of underlying object is fired even when overlapping object is IsHitTestVisible = false

I have created a custom popup to decorate my buttons with animated tooltips. I track Button.MouseEnter for the button to decide when to display the popup. I use Button.MouseLeave to determine when to hide the popup.
Problem is Button.MouseLeave is fired prematurely if the popup moves over the mouse cursor (its appearance is animated) despite the fact that I have set IsHitTestVisible = false for the popup and all its visual children.
Is this the way WPF is designed to work? I need MouseLeave to only fire when the cursor moves away from the button itself and not be influenced by the popup.
Thanks
I believe that the Popup control is actually contained within a window, which is why the popup can extend beyond the window bounds in some cases. (It's also why popup transparency is not supported in Silverlight.)
I believe that while the popup control is no longer processing "hits", the container window is, which is why you are losing your button's mouse focus.
I've not tested this, but you might try creating a template for your button and actually declaring the popup as part of the button (rather than below it). This may cause WPF to view the popup control as part of the button and eliminate the problem of losing mouse focus. This works in other scenarios, but I'm not 100% sure how this will work with a Popup.
EDIT: As a side note, the deault WPF tooltip allows you to override the template. I'm not sure what your goals are, but you may find it easier to change the appearance and behavior of the default tooltip than to try to roll your own, as a lot of these sorts of problems have already been solved in the default Tooltip.

Window GotFocus event not firing

I couldnt get the GotFocus() event fired in the WPF window by clicking. But if I click any controls, it will be fired.
My requirement is as follows: I have a hostwindow which has a viewport with two datagrids which can host user controls. I do animations like flip and fade on this user controls. I am using a transparent background(glass effect) for the controls. But when one user control get on top of the other, both of them overlap. So I want to make the top one opaque when the user click on one user control.
Try using the Activated event, as GotFocus is intended to be used only with controls.

Capture Silverlight 4 event when panel clicked

I have a small Silverlight 4 app that essentially consists of a grid containing a label and a combo box. When I click the label, I replace it with a second text box so that I can edit the label (much the way you can edit the name of a Silverlight control in VS2010).
I have a LostFocus event handler on the text box that will end editing when the control loses focus (restoring the updated label). Trouble is, users tend to click on the panel when they are done editing rather than on another control (or hitting Enter, which is also supported).
I tried adding a left mouse down event handler to the panel. However, that only fires when the text box does not have the focus (I guess the text box captured the mouse?)
Is there an approach to recognize that a non-input control was clicked that would enable me to terminate edit mode?
You can subscribe to Grid's MouseLeftButtonDown routed event using the following code:
panel.AddHandler(UIElement.MouseLeftButtonDownEvent,
new MouseButtonEventHandler(panel_OnMouseLeftButtonDown), true);
Unlike common events routed events are bubbled from innermost control to its parent, then to grandparent etc. In the same way you could subscribe to panel's parent to intercept clicks outside your panel.

Binding a Popup to another control's relative screen position

I'm writing an XBAP with a complex Popup (Canvas Z-index of 99 with a grid on it...) that I would like to "attach" to the button that opens it and follow that button around wherever it goes on the screen. For example, if the button is in a ListBox or an XamDataGrid I would like the popup to follow the button as it scrolls through. If it is beneath an Expander I want it to stay attached to the button when the expander forces it to move, etc.
Any Ideas?
When using a Popup, neither PlacementTarget nor CustomPopupPlacementCallback is used after the popup has originally appeared. So any use of these properties will not allow the popup to track the button as it moves.
Several ways occur to me of achieving what you desire:
Attach a custom Adorner to the button and put the popup inside it. Disadvantage: Popup is not connected to Button or surrounding elements, so it won't inherit properties & DataContext from them.
Attach a custom Adorner to the button. This adorner will get measure and arrange calls when the button moves relative to the AdornerLayer, allowing you to manually update the Popup position. As long as your AdornerDecorator doesn't move relative to your Window (eg if it is the direct child of the Window), you can easily detect the AdornerLayer being moved by monitoring changes to Window size. Disadvantage: Complex to code & get right.
Don't use a Popup at all. Instead wrap the button in a <Grid> alongside a <Canvas> with zero width and height and the desired position. Inside the <Canvas> add the UserControl for the popup with an appropriate ZIndex. It will extend past the edge f the Canvas, which is just fine in WPF. Instead of using a Popup control just control the visibility of the UserControl. Disadvantage: Will not really be totally on top of all other objects, can't extend off edge of window (may not be an issue for XBAP, though).
I'm not sure if it will auto-update for you or not, but the PlacementTarget property allows you to specify a control to position the popup relative to. If that doesn't work, then maybe CustomPopupPlacementCallback will do the trick?

Resources