add MouseButtonEventArgs to userControl in wpf - wpf

I have a usercontrol. This usercontrol has a button that when you click on it, It has to get the mouse position for mainWindow and show a message. the problem is that for getting the mouse position, The event has to be a "MouseButtonEventArgs" event but you can only add "RoutedEventArgs"
to user control.

You can get the mouse position relative to your app's MainWindow whenever you want and wihtout using event-handlers at all..
Point mousePosition = Mouse.GetPosition(Application.Currect.MainWindow);
If you want the position relative to some other UIElement
// element can be usercontrol, window dialog, etc..
// it would return negative x,y values if the mouse is out of the element
Point mousePosition = Mouse.GetPosition(element);

Related

C# WPF - Canvas MouseMove event firing even when mouse moves over child control

How to make it so the Canvas MouseMove event only fires if my mouse is over the Canvas and the Canvas only?
I have a TextBox as a child of the Canvas and it still fires when my mouse is moving over that TextBox, i would like this to not happen, it should only fire when the mouse is moving over the Canvas background/blank space for example.
How to make it so the canvas MouseMove event only fires if my mouse is over the Canvas and the Canvas only?
You can't prevent the event from being fired but you can check whether the mouse is directly over the Canvas area in your event handler and simply do nothing if it isn't:
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (Mouse.DirectlyOver == sender)
{
//your code...
}
//else, i.e. when the mouse moves over the TextBox or another child element, do nothing
}
You have to listen to the preview version of that event on the canvas PreviewMouseMove and set the e.Handled = true.
Take a look at this url
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/routed-events-overview

How to get a one-to-one match of an Adorner with its adorned element within a ScrollViewer?

wpf
I have a control A, (an inkcanvas), within a Grid within a ScrollViewer. Conrol A is taller then the physical window, so the ScrollViewer correctly adds a vertical scroll bar and the entire control can be viewed by scrolling down. When attaching an Adorner with a control B, (another inkcanvas), to control A, scrolling downward shows the Adorner to be cut off at the bottom of the screen. That is, the Adorner is not completely covering the adorned element and/or is not extended downward when scrolling.
How do I get the Adorner (the control) to completely cover the adorned element and respect the ScrollViewer. (I need a one-to-one match between the pixels of the Adorner control and the adorned element within the ScrollViewer).
TIA
Edit#1: The key line in the Adorner that sets the background of the InkCanvas is
_inkcanvas.Background = CreateGrid();
public InkCanvasTextAdorner(InkCanvas element)
: base(element)
{
_element = element;
_visuals = new VisualCollection(this);
_inkcanvas = new InkCanvas();
_inkcanvas.Background = CreateGrid();
_visuals.Add(_inkcanvas);
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(element);
adornerLayer.Add(this);
}
If an InkCanvas is used (as the above) the Adorner's background is clipped at the bottom. The adorner control, however, does continue to the bottom of the adorned element.
However, if a Canvas is used instead of the InkCanvas, the Adorner's background does extend to the bottom of the adorned element.
What's wrong?
I'm guessing that the difference in the Background property expanding past the physical screen with the Canvas and not the InkCanvas may be because the Canvas inherits from Panel whereas the InkCanvas does not. Based on the finding that the Canvas background does do what I need, I find the below code does accomplish what I want--the canvas allows images from layers beneath it to be seen yet posts a grid of lines overwhich the InkCanvas will accept strokes. All is well :)
public InkCanvasTextAdorner(InkCanvas element)
: base(element)
{
_element = element;
// The VisualCollection has only one visual parent. I.e. InkCanvasTextAdorner is the parent to the VisualCollection.
// By overriding default rendering behavior of the VisualCollection, any kind of control and its children can be placed in the Adorner.
_visuals = new VisualCollection(this);
_inkcanvas = new InkCanvas();
_inkcanvas.Background = Brushes.Transparent;
_canvas = new Canvas();
_canvas.Background = CreateGrid();
_grid = new Grid();
_grid.Children.Add(_canvas);
_grid.Children.Add(_inkcanvas);
// The _grid is a logical child of the VisualCollection of the Adorner. The ArrangeOverride and MeasureOverride will set up the Grid control.
_visuals.Add(_grid); // Adding a single control for display.
// AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(element);
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(element);
adornerLayer.Add(this);
}
Which looks like:

Popup to appear on the bottom-right corner of its parent

I'm trying to design a Popup which will appear on the bottom-right corner of its PlacementTarget
Let's admit that you set its PlacementTarget to a Window, well, the Popup will act as classic toaster notifications.
Given the fact that WPF is not smart enough to provide us a "corner" solution, I'm trying to implement a new control, inheriting from Popup , which will place itself at the appropriate location.
Here is my first idea: work on Loaded event to determine where should I place the Popup.
Problem? I don't want to give any fixed dimensions to the popup, which is supposed to size itself according to the text displayed.
However, I can't get the ActualWidth property when Loaded event is raised.
I can't have it either when Opened event is raised.
Here is the draft code so far:
public class ExceptionPopup : Popup
{
public ExceptionPopup()
{
InitializeComponent();
Loaded += new RoutedEventHandler(ExceptionPopup_Loaded);
}
void ExceptionPopup_Loaded(object sender, RoutedEventArgs e)
{
if (PlacementTarget != null)
{
if (PlacementTarget is FrameworkElement)
{
parentWidth = (PlacementTarget as FrameworkElement).ActualWidth;
parentHeight = (PlacementTarget as FrameworkElement).ActualHeight;
}
}
}
protected override void OnOpened(EventArgs e)
{
this.HorizontalOffset = parentWidth;
this.VerticalOffset = parentHeight;
base.OnOpened(e);
}
}
Is there any other event I could use to catch what I want here?
I'd basically like to set HorizontalOffset to parentWidth - ActualWidth/2 , same for height :)
Any idea?
Thanks!
Usually I set the PlacementTarget to either Bottom or Right, then apply a RenderTransform which shifts the Popup by the remaining value.
For example, I might use Placement=Bottom, then use a RenderTransform to shift the popup (Window.Width - Popup.Width) to the right, and Popup.Height upwards. You might not even need to re-adjust based on the Popup Height/Width becauase MSDN says that Popups are not allowed to be displayed off screen, and it will automatically adjust their placement to keep them visible
Be sure you use a RenderTransform instead of a LayoutTransform, because RenderTransforms get applied after the Popup gets Rendered, so the ActualHeight and ActualWidth will be greater than 0.

Silverlight custom control ToolTip not showing up each time

In a Silverlight application I have a custom control with a number of custom properties. In the declaration class of the custom control additionally to defining its properties as dependency properties, I define showing a ToolTip:
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Border bordercntr = base.GetTemplateChild("PART_SBorder") as Border;
bordercntr.MouseEnter += new MouseEventHandler(bordercntr_MouseEnter);
bordercntr.MouseLeave += new MouseEventHandler(bordercntr_MouseLeave);
}
private void bordercntr_MouseEnter(object sender, MouseEventArgs e)
{
string _sno = this.SomeProperty.ToString();
ToolTipService.SetToolTip(this, "Some text " + _sno);
VisualStateManager.GoToState(this, "Hovered",false);
}
The problem is, that a ToolTip pops up not the first time mouse points to a custom control, but only after the second time. After I reload page this happens again: the first time I hover over a control nothing is shown up and then from the second time and further on the ToolTip pops up again. (not always in a stable way, I mean not 100% each time mouse hovers).
What could prevent the ToolTip from showing up in a stable manner each time a mouse hovers over control and starting showing up from the very first time of hovering it after reloading the page?
Set the ToolTip in the setter for SomeProperty The ToolTip you define in the ToolTipService will behave like a normal ToolTip and only appear when the mouse is over the control. You shouldn't need to handle the MouseEnter and MouseLeave events at all.

No events passed to WPF adorner layer

I am trying to make a nice "drag and drop zone" in WPF that is displayed in the adorner layer when something is being dragged into the main application. The problem is that I do not get any events from my adorner, even though it according to documentation should receive all input events since it is in a higher z-order.
To debug my problem I created a really simple example where I have a user control with only a button in it. This user control is displayed in the adorner layer, but I cannot click the button. Why? What have I done wrong?
My adorner class is constructed like this:
public ShellOverlayAdorner(UIElement element, AdornerLayer adornerLayer)
:base(element)
{
_adornerLayer = adornerLayer;
_overlayView = new AdornedElement();
_overlayView.AllowDrop = true;
_adornerLayer.Add(this);
}
and is created in the main window by
private void Window_Loaded(object sender, RoutedEventArgs e)
{
adornerLayer = AdornerLayer.GetAdornerLayer(MyTopGridWithButtonInIt);
ShellOverlayAdorner shell = new ShellOverlayAdorner(MyTopGridWithButtonInIt, adornerLayer);
}
I do not get any events at all from my control, i.e. no mouse clicks, mouse over, button clicks. I cannot even click the button in the adorner layer. What have I done wrong?
I don't know if you already tried that:
If you want the element added to react to events, I think that the element must be bound to the visual tree of the adorner.
The way to do it is to use a VisualCollection, intitialized to the adorner itself, or at least, this way it seems to be working:
VisualCollection visualChildren;
FrameworkElement #object;
public CustomAdorner(UIElement adornedElement) :
base(adornedElement)
{
visualChildren = new VisualCollection(this);
#object = new Button {Content = "prova"};
visualChildren.Add(#object);
}
protected override Visual GetVisualChild(int index)
{
return visualChildren[index];
}
This way the events are correctly routed.
I just had the same issue. Following the advice from MSDN sorted it for me:
Adorners receive input events just
like any other FrameworkElement.
Because an adorner always has a higher
z-order than the element it adorns,
the adorner receives input events
(such as Drop or MouseMove) that may
be intended for the underlying adorned
element. An adorner can listen for
certain input events and pass these on
to the underlying adorned element by
re-raising the event.
To enable pass-through hit testing of
elements under an adorner, set the hit
test IsHitTestVisible property to
false on the adorner.
i.e In the adorner itself, make sure IsHitTestVisible = false

Resources