I'm building SL application for zooming and panning across the layout. Everything is working fine, except that when I zoom in using mouse wheel , after some zoom scrollbars start to use mouse wheel so after that I can scroll not zoom. I only can zoom again if I put scrollbars at the end or begining. How to prevent scrollviewer from using mouse wheel? I want that zoom only be operated by wheel. Thank you in advance!
Here is my code of MouseWheel method when I'm zooming content :
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
base.OnMouseWheel(e);
if (e.Delta > 0)
{
this.aniScaleX.To += 0.2;
this.aniScaleY.To += 0.2;
this.sbScale.Begin();
}
else if (e.Delta < 0 && (this.aniScaleX.To > 1 && this.aniScaleY.To > 1))
{
this.aniScaleX.To -= 0.2;
this.aniScaleY.To -= 0.2;
this.sbScale.Begin();
}
Sizer.Width = Board.ActualWidth * (double)this.aniScaleX.To;
Sizer.Height = Board.ActualHeight * (double)this.aniScaleY.To;
Try to set:
e.Handled=true;
The MouseWheel event is a bubbling
event. This means that if multiple
MouseWheel event handlers are
registered for a sequence of objects
connected by parent-child
relationships in the object tree, the
event is potentially received by each
object in that relationship. The
bubbling metaphor indicates that the
event starts at the source and works
its way up the object tree. For a
bubbling event, the sender available
to the event handler identifies the
object where the event is handled, not
necessarily the object that actually
received the input condition that
initiated the event. To get the object
that initiated the event, use the
OriginalSource value of the event
data. http://msdn.microsoft.com/en-us/library/system.windows.uielement.mousewheel(VS.95).aspx
In my case,ScrollViewer always received event before because he is on the top of the visual tree. So I just registered event handler in scrollviewer on mouse wheel event and always when It happens, I simply redirect him to my "original" mousewheel function which do zoom.
I hope so that this will help somebody who is "stuck" like me here. Thank you all on your answers and suggestions..
This took me awhile (WPF), but basically you should use AddHandler in whatever parent UIElement that has the event.
For me, I did this in my MainWindow. So my code looked like:
public MainWindow()
{
InitializeComponent();
this.AddHandler(MainWindow.MouseWheelEvent, new RoutedEventHandler(this.MouseWheel_1), true);
}
This will also mean not overriding OnMouseWheelDown, but instead creating a method that matches the RoutedEventHandler delegate and casting e (which will be a RoutedEventArg) as MouseWheelEventArgs to get access to the properties required to determining zoom.
I hope this helps for your situation.
Related
I'm working with WPF.
My visual tree hierarchy as the following:
RadDiagram > RadDiagramShape > MyControl
The content of RadDiagramShape is mycontrol.
In myControl class, I have handled (MouseLeftButtonDown) Event, I put drag-drop code inside it(which I need it in another place). So, it's Direct Event not Tunneling or Bubbling!
While I'm moving my Custom Control which is the content of the RadDiagramShape, in RadDiagram, it doesn't move (It's trying to be dragged) because the MouseLeftButtonDown has been handled inside MyControl.
It prevents the event from bubbling up the Visual tree, preventing any parent handlers from being notified of the event.
I tried to handled the Event for the RadDiagramShape and for the RadDiagram as e.Handled = true;
but it did nothing because It's MouseLeftButtonDown and it's handled inside the root element so, it won't bubble or tunnel and I didn't override movement code, which I don't want to override it. Because I tried it before and it didn't give me the same slightly move that built-in in WPF.
How can I block MouseLeftButtonDown event in root element and let the event fired in the container(parent) level?
Please check in your control handler if 'OriginalSource' is the same control that you want or not.
if ((e.OriginalSource is TextBox) && (e.OriginalSource as TextBox).Name == "TextBoxName")
{
//Do every thing you want
}
Thank you leila karimi. You gave me the orientation, the condition itself didn't work. But I put another condition and it worked
void MyLabel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MyLabel dc = (MyLabel)sender;
if (dc.Parent.GetType() != typeof(RadDiagramShape))
{///....drop it}
}
I'm trying to add a fade effect (animation) for WPF UserControls (although rather for FrameworkElement, to make it more general).
If I let the Loaded event trigger the initial fade-in, the fade animation will sometimes have started before the UserControl has been displayed. The result is a mess. That happens for example if the UserControl does something lengthy (a few tenths of a second), like execute a query, in the Loaded event handler.
So, I would need to handle some event that FrameworkElement/UserControl gets when the content has been rendered, and start the fade-in then. The System.Windows.Window has a ContentRendered event, but UserControl has not. So, what event is fired when a FrameworkElement (or UserControl) has been rendered?
Try to check size on SizeChanged or LayoutUpdated. Do job when actual width or height not equals to 0.
view.LayoutUpdated+=(o,e)=>
{
if (!loaded && (view.ActualHeight > 0 || view.ActualWidth > 0))
{
// You can also unsubscribe event here.
loaded =true;
}
}
Years late, but since I was looking for working solution since now in vain, I want to share my discovery.
If you want a ContentRendered event for any Control (or any Visual or even DependencyObject), you have to dig down to Visual.
I use this code:
// Wait for Control to Load
void TestUserControl_Loaded(object sender, RoutedEventArgs e)
{
// Get PresentationSource
PresentationSource presentationSource = PresentationSource.FromVisual((Visual)sender);
// Subscribe to PresentationSource's ContentRendered event
presentationSource.ContentRendered += TestUserControl_ContentRendered;
}
void TestUserControl_ContentRendered(object sender, EventArgs e)
{
// Don't forget to unsubscribe from the event
((PresentationSource)sender).ContentRendered -= TestUserControl_ContentRendered;
// ..
}
You have to wait for Control Loaded otherwise PresentationSource.FromVisual() returns null.
Various Dispatcher.BeginInvoke methods didn't work consistently for me. Sometimes firing my rendered event long before the control was actually displayed.
This does work for me every time.
I am aware that I am playing with HwndSource here, which is quite low level and I'm not sure of possible implications. (Maybe somebody more experienced can elaborate.)
You can use IsVisibleChnaged event
Assign event handler
MyUserControl.IsVisibleChanged += ScheduleUserControl_IsVisibleChanged;
In event handler check for if is visible or not.
void _IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
//Visible
}
else
{
//Not Visible
}
}
You can schedule the beginning of your Storyboard with a lower priority, for example:
Dispatcher.BeginInvoke(BeginStoryboardAction, DispatcherPriority.ContextIdle);
Here's an article that discusses the issues related to using this method:
Build More Responsive Apps With The Dispatcher
Maybe try IsVisibleChanged, haven't used it much myself though.
This event is not raised if the element is not being rendered by the layout system, for reasons other than the value of the IsVisible property. For example, the element might not have an associated visual.
You can use GotFocus Event
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<i:InvokeCommandAction Command="{Binding ContentControlLoadedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
I'm starting to make some tests with a touch screen and I've found that if a UIControl has the "IsManipulationEnabled" attribute set to true then the MouseRightClick Events fired by the press and hold gesture (WIN7) is not captured. Am I doing something wrong?
public MainWindow()
{
InitializeComponent();
WC_Rectangle.IsManipulationEnabled = true;
WC_Rectangle.MouseRightButtonUp += new MouseButtonEventHandler(WC_Rectangle_MouseRightButtonUp);
}
void WC_Rectangle_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
System.Diagnostics.Debug.WriteLine("RIGHT CLICK : " + sender.ToString());
}
After setting IsManipulationEnabled = true; all touchevents are captured and handled by the WC_Rectangle which does transform them to Manipulation events. So the touchevents do not tunnel back to the control that raised them which in turn means the control can't promote unhandled touch events to mouse events (the default). see:
http://nui.joshland.org/2010/04/why-wont-wpf-controls-work-with-touch.html
If you cancel the manipulation events you should get the mouse events.
Use Behavior Instead
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
I wanted to get the type of the control on mouseover. Please help
You can get the type of the UIElement over which the mouse is currently moving using the MouseMove event. Since this is a bubbling event you can attach a handler to the container such as a Canvas.
The UIElement over which the mouse is currently moving can be aquired from the the MouseEventArgs OriginalSource property.
Hence to determine the type over which the mouse is moving you could use code like this:-
void Canvas_MouseMove(object sender, MouseEventArgs e)
{
Type currentType = e.OriginalSource.GetType();
// Make decisions based on value of currentType here
}
However you need be careful, MouseMove fires frequently as the user moves the mouse so you might want to defer any heavy work until there is some time period after the last mouse move.
There is unfortunately no bubbling mouse over event.
The other alternative is to attach the same MouseEnter handler to each child UIElement you add to the Canvas. You could use sender instead of e.OriginalSource in that case. You would have to be careful to remove the handler if the element is removed from the Canvas, else you can create what would appear to be a memory leak.
Add mouse_enter event to the control.
You can get the type with a line of code as follow
var x = sender.GetType();
You can then compare it using something like:
if (x.Equals(typeof(TreeView)))