At the moment, the user can click on the Slider's thumb and move it to the left and to the right in the same speed independent from the mouse cursor's position. I want to update its work, so that the drag speed decreases, when the mouse cursor distance to the Slider increases. That means, when the user drags the Slider's thumb with his mouse and the mouse cursor is over the Slider itself, the drag speed is normal (as it is at the moment). But if he moves the mouse cursor away from the Slider while he is still dragging the Slider's thumb, the drag speed is lower. The further away the mouse cursor is, the lower the drag speed becomes.
Try something like:
public class YourSlider : Slider
{
protected override void OnThumbDragDelta(System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
// Use distance to modify value change
}
}
And of course you're going to have to calculate where the mouse is, relative to the thumb.
You can work out the thumb using visual.pointtoscreen
https://msdn.microsoft.com/en-us/library/aa346961.aspx?f=255&MSPPError=-2147217396
You can use mouse.getposition and visual.pointtoscreen to get the mouse position.
Related
I am trying to construct some SVG shapes which should be resize-able along one or more edges.
The way I do this is by creating an additional shape on top of the shape which I want to be able to resize. I use this shape to indicate to the user that an edge can be clicked on and dragged. This shape tends to be a line that lights up once the user moves their mouse over it and I change it's position while resizing the main shape.
Using a combination of the mousedown, mousemove and mouseup events, I get the mouse's current position and adjust the shape accordingly.
All seems to work. However, what I can't seem to figure out is that should I move my mouse a little bit too quickly, while dragging the edge, it seems as though the mouse looses track of the event and the dragging of the edge fails. At this point I am have to find the edge again and restart the process.
Any idea how to either stop the mouse from losing the edge while dragging? Or perhaps slow down the event so as not to allow the mouse to jerk into any one direction too fast?
I have created a a sandbox here to demonstrate the issue.
I'm using a horizontal slider in WPF, but would like to also perform some action if the mouse is moved vertically (like change the brightness of some control).
I tried responding to MouseMove, but I don't get an update when dragging the slider, if the mouse moves purely vertically - my function only gets called when the slider actually moves.
You could attach a handler to the slider's PreviewMouseMove event.
I have a Rectangle nested within a Canvas. The rectangle has a MouseDragElementBehavior attached to it, so it can move freely in the canvas.
I need to calculate the position of the rectangle after each drag. The problem is that the
Canvas.GetTop(rectangle1)
only works for the first time, i.e. before the rectangle is dragged. After the drag, the method call returns the initial position.
Those behaviors usually work by applying a RenderTransform, if it uses a TranslateTransform you can get the offset value from that and add it to the canvas position.
Alternatively you might just want to implement your own dragging logic.
I have good model (I think!) for how to allow a user to drag an element in a stackpanel and reposition it to another location within the stackpanel.
However, my Stackpanel is placed within a ScrollViewer, like this (generalized):
<ScrollViewer>
<StackPanel>
....First item
....Second item
....Third item
....Etc.
</StackPanel>
<ScrollViewer>
Here is the problem, I wish to simulate the functionality of programs like word, where if I am dragging selected content (or an object) outside the viewable area, the window will scroll in the direction of the mouse to see more places to drop my nifty little object.
...i.e. If I move the mouse to the top of my ScrollViewer while dragging a stackpanel's contents, I want the scrollviewer to slowly move up so I can see more locations to drop my content.
Any suggestions?
If you can help me solve this, you will be a godsend!
No problem. Handle the DragOver routed event at the ScrollViewer level. Get the position. If it is near the top of the ScrollViewer bounds, scroll up. If it is near the bottom of the ScrollViewer bounds, scroll down.
The scrolling itself is done by calling scrollViewer.LineUp() or scrollViewer.LineDown().
The DragOver events come frequently, so save the value of DateTime.Now in a field each time you call LineUp() or LineDown(). Before calling them again, check DateTime.Now and if not enough time has elapsed, don't call LineUp() or LineDown().
For better control over scrolling speed you can use scrollViewer.ScrollToVerticalOffset(scrollViewer.ContentVerticalOffset + delta) instead of scrollViewer.LineUp() and scrollViewer.LineDown().
You can provide a better user experience if you allow faster scrolling when nearer to the top or bottom of the scroll viewer. This can be done by dividing the scroll area into zones, or calculating the speed from the mouse position. In this case, speed changes can be done by calling LineUp()/LineDown() multiple times when closer to the edge, or by increasing the delta value if you are using ScrollToVerticalOffset. You probably should not modify the timing (DateTime.Now comparison) for this purpose, because it will be unreliable.
I'm trying to modify the default graph viewer of the Graph# library because its user interface is awful (just try dragging a node outside of the boundaries, you'll see!)
The basic setup is this: there is a GraphCanvas control (inherited from Panel) which has children of Vertex and Edge control types. What I want to achieve is:
GraphCanvas has scroll bars if the contents do not fit in the screen;
GraphCanvas can also be scrolled by "dragging" it (just click on an empty space and drag);
GraphCanvas can be zoomed in and out (via CTRL+mouse wheel);
Vertices can be dragged around. If a vertex is dragged outside the current boundaries of GraphCanvas, the boundaries are increased. The scroll bars should reflect this, however the current viewport should not scroll away while the vertex is being dragged . The same goes if dragging a vertex reduces the boundaries of GraphCanvas - it should stay the same size until the drag operation is finished and resize only then. Automatically scrolling the viewport during a drag operation is awfully confusing and easily introduces dragging errors. See the original implementation if you want to know what I mean.
Although I've got a fair bit of experience with .NET, I'm still a complete beginner in WPF. My current attempt is (in the measure/arrange layout phase) to give each vertext the XY coordinate it desires (even if negative) and implement zooming/scrolling by handling mouse events on the GraphCanvas and modifying the RenderTransform property. Dragging just changes the XY coordinates on the specific vertex (probably triggering the re-layout of the whole thing which would be nice to avoid too). Scrollbars are implemented by placing the GraphCanvas inside a ScrollViewer and implementing IScrollInfo on the GraphCanvas.
Unfortunately there seems to be a problem: I can get mouse events on the GraphCanvas itself only if it has a background at the point. That would be OK, I want a white background anyway, but in the negative coordinates of the GraphCanvas it does not draw the background - and thus does not respond to mouse events.
I'm also wondering if I'm doing the Right Thing by allowing all my child controls (vertices and edges) to go into negative coordinates. How would you implement this?
Added: To clarify about the background problem check out the following screenshot:
(source: valts.21.lv)
What you see here is a simple Windows Forms form with a WPF Host control on it. That has a ScrollViewer in it, and the ScrollViewer has the GraphCanvas in it. The GraphCanvas contains 4 vertices and 6 edges.
The GraphCanvas is stretched to fill the ScrollViewer. But since some of the vertices are at negative coordinates, it has a RenderTransform applied which simply shifts everything to the right (TranslateTransform). It also has a white background brush.
Note the gray area on the left. That's still a part of the GraphCanvas, but the background brush somehow doesn't exted there. Also, if I left-click there with my mouse (not on a node, but on the gray area), I do NOT get an event. If I left-click on the white area, I get all events just fine.
Call CaptureMouse on canvas.mouseDown and ReleaseMouseCapture on mouse up. Also, if you set your canvas background to transparent it will still be hit testable
You can attach a 'Draggable' behavior to each element.