I have a SurfaceListBox that inside has a ScrollViewer. I have access to that ScrollViewer and I want to detect when the scrolling ends. Since it is a touch app and I can drag it, right now I'm detecting the PreviewTouchUp to do what I want, however, if I do a fast swipe, like you would do on a smartphone, because the content of the ScrollViewer is still dragging/scrolling, the PreviewTouchUp does not reflect the end of the scrolling, but is instead triggered before.
I have tried Manipulation events and several others on both the ScrollViewer and the SurfaceListBox. I have also tried ScrollViewer.PanningDeceleration and honestly, I don't see a difference. Basically, no luck so far.
So, how can I detect the end of the scrolling, even after the PreviewTouchUp in a ScrollViewer?
Can't you just handle the ScrollViewer.ScrollChanged event? From the linked page, it says that it...
Occurs when changes are detected to the scroll position, extent, or viewport size.
So you could just start a DispatcherTimer to wait for a short instant each time the event has been raised, eg. when it is scrolling. When the scrolling stops and the event stops being raised, then the Tick handler will be called and you can do whatever you like in it. Try something like this:
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 0, 0, 250);
timer.Tick += Timer_Tick;
...
private void ScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (timer.IsEnabled) timer.Stop();
timer.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
timer.Stop();
// Do what you want now that scrolling has stopped
}
Seems a bit messy but Sheridan's solution was the best way I could find to determine when a scrollviewer has stopped moving. I just tweaked the timer interval and, more importantly, put the "// Do what you want now that scrolling has stopped" between hittestvisible = false and then hittestvisible = true on the scrollviewer control.
Related
I'm trying to make an animation for my C# program. There's a space rocket that ascends 8 pixels vertically with a timer interval of 25ms. I've managed to make the animation but since the picturebox's background (I've used for the rocket) is set to transparent it flickers the form's background image everytime it moves. What can I do to prevent it?
The code I've used for timer tick :
pictureBox1.Top -= 8;
P.S: I've tried to change the picturebox with panel, slow downed the rocket and timer but nothing seemed to change.
Well i haven't tried it myself now.
There needs to be a render event which you can hook to and make manipulations to your UI which would render smoothly.
Control.Paint
Try something like these :
private void Form1_Load(object sender, System.EventArgs e)
{
pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint);
}
private void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
pictureBox1.Top -= 8;
}
Again this isn't tested and i haven't developed any thing in winforms for ages.
But that's the direction you should go for to render things smoothly.
That double buffered thing mentioned above is also a factor in some cases.
but this is mainly the way to do it.
I am developing a windows 8 app and have to enable panning on the image through mouse.It is working on the Tablet but somehow I need to enable it from the mouse also.
And I am writing pointer wheel changed event for zooming the image but it is calling just once.
This is my code for Zooming
private void MyScrollView_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
{
MyScrollView.ChangeView(MyScrollView.HorizontalOffset + 40, MyScrollView.VerticalOffset + 20, MyScrollView.ZoomFactor + 0.1f);
}
Any help would be grateful to me.
I encountered the same problem while trying to do the same thing. Your code will work as long as the Scrollviewer is not handling scroll event internally.
To explain more closely:
When all of the content of the Scrollviewer is visible (ie no need to scroll), the Scrollviewer will not handle any scroll event internally and the event will fire and you handle it in your code.
If, however, there is content that is larger than the visible area of the Scrollviewer, the scrollbars will show up. At this point the Scrollviewer will handle scroll event (so that when you scroll, you move the scrollbar). This is the expected behaviour, as it is in web browsers and other applications with content that's larger than the viewport or visible area. The event will no longer fire and your handler will not run because the internal logic stops the event from ever reaching your code.
You can capture the event by setting e.Handled to true like so:
private void MyScrollView_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
{
e.Handled = true; // Tell the event system that the event has been handled and it should not execute any more handlers.
MyScrollView.ChangeView(MyScrollView.HorizontalOffset + 40, MyScrollView.VerticalOffset + 20, MyScrollView.ZoomFactor + 0.1f);
}
But I found it to be a bad experience. The zooming is not cenetered on the pointer and moves the content in a way that's confusing and jarring. I found no good way to override this.
As a last point, I want to mention that there's built in zoom functionality in the Scrollviewer by using Ctrl+Scroll. Works nicely and it's the same shortcut used in browsers.
I had this issue yesterday and it seems a lot of people have had similar issues in the past, so I figured I would pose my question & the solution I ended up coming up with. Microsoft has cleaner solutions to this in the 8.1 SDK, but the vast majority of WP app users are on 8.0 and below, so I imagine this will still be helpful.
When you open the virtual keyboard in a Windows Phone 7/8 Silverlight app, and the text box that caused the keyboard to open is on the lower half of the screen (that would be covered by the keyboard), it scrolls the entire page up. How can you determine how much it has scrolled, in case there was content at the top that you need displayed?
It's a little clunky, but you can get the amount the page was scrolled up by looking at the offset of the root frame.
Since this is animated into position, the question becomes "when". What I found that works is, when a text box's GotFocused event is fired, subscribe to the LayoutUpdated event, and when LayoutUpdated is fired, grab the offset from there. If you weren't already subscribed to that event, you can unsubscribe in the LostFocus event. That way as it moves, you'll get the change.
double lastOffset = 0;
private void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
LayoutUpdated += MyControl_LayoutUpdated;
}
private void MyControl_LayoutUpdated(object sender, EventArgs e)
{
// Grab the offset out of the root frame's RenderTransform object
PhoneApplicationFrame root = App.Current.RootVisual as PhoneApplicationFrame;
TransformGroup transform = root.RenderTransform as TransformGroup;
double offset = transform.Value.OffsetY;
if (offset != lastOffset)
{
// Do your logic here if the offset has changed
lastOffset = offset;
}
}
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
// Unsubcribe to updates and reset the offset to 0
LayoutUpdated -= MyControl_LayoutUpdated;
lastOffset = 0;
}
After you have this offset, you can alter your controls as needed. You can either shrink the height of a control by that amount, or if you have something small at the top, like a header, you can apply a TranslateTransform by the inverse of the offset to just move it downward.
I'm trying to move a GridView with the ManipulationDelta event, similar to dragging.
My ManipulationDelta event looks like this:
private void GridView_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
var tt = (TranslateTransform)(sender as GridView).RenderTransform;
tt.X += e.Delta.Translation.X;
UpdateLayout();
}
The problem with this approach is that it's not smooth at all. Is there any better way to do this?
Remove the update layout call.
Changing the render transform is fast since it applies purely on the render thread and doesn't have to synchronize with the code thread or do a layout pass. UpdateLayout force everything to re-layout which is slow and unnecessary.
I'm trying to develop an application that, when running, will hide the mouse cursor wherever it happens to be on the screen after 5 seconds of inactivity, even if my app isn't in the foreground. Then, once the mouse moves again, the mouse should reappear instantly.
I've been reading a lot about low-level mouse hooks, but can't seem to wrap my head around the delegates and callbacks that, to me, make the code a lot harder to read.
Here are some of the things I've been looking at in terms of solutions:
Hide mouse cursor after an idle time
http://blogs.msdn.com/b/toub/archive/2006/05/03/589468.aspx
http://www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C
And I seemed to get closest with this one:
http://weblogs.asp.net/jdanforth/archive/2011/03/19/detecting-idle-time-with-global-mouse-and-keyboard-hooks-in-wpf.aspx
My problem seems to be that if I set up a timer on my main form for 5 seconds, then yes the mouse disappears after those 5 seconds if it's inactive, but then it also takes 5 seconds for the mouse to reappear! Would the solution simply be to have two separate timers and separate events?
Thanks so much for the help!
Add a handler for the MouseMove event on your form then call Cursor.Show() in the MouseMove handler.
You dont have to create 2 different timers. I would use the same timer, but have a private member variable that keeps track of whether the cursor is hidden. Once you hide it, you can reset the timer to be a lot shorter (say 500 ms) and continue to track it to turn it back on.
You can try this:
private Timer t;
void OnLoad(object sender, EventArgs e)
{
t = new Timer();
t.Interval = 5000;
t.Tick += new EventHandler(t_Tick);
}
private bool _hidden = false;
void t_Tick(object sender, EventArgs e)
{
if(!_hidden)
{
Cursor.Hide();
t.Interval = 500;
}
else
{
if(--some parameter---)
Cursor.Show();
}
}