locked
Double Tap to Zoom Image, Windows 8.1 ScrollViewer.ChangeView RRS feed

  • Question

  • After learning to "Double Tap to Zoom Image" (no link because account hasn't yet been verified) for windows 8, I've successfully managed to implement the double tap to zoom my item from a listview's double tapped event, at the expense of mouse and pointer events. The problem I'm running into is that the animations aren't working, and the Scrollviewer.ChangeView method has to be called twice, or else only the vertical offset is updated. Here's my code that works for mouse, but not for touch.

                    await dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                    {
                        _zoomedInScrollViewer.ChangeView(point.X + _zoomedInScrollViewer.HorizontalOffset * 2,
                              point.Y + _zoomedInScrollViewer.VerticalOffset * 2, 2, false);
                    });

    This is successful when zooming the image vertically, but requires a second call to ChangeView to reposition the horizontal scrolling too. Here is the code that works for touch, but not for mouse.

                    await dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
                    {
                        _zoomedInScrollViewer.ChangeView(null,
                              point.Y + _zoomedInScrollViewer.VerticalOffset * 2, 2, false);
                        _zoomedInScrollViewer.ChangeView(point.X + _zoomedInScrollViewer.HorizontalOffset * 2,
                              null, 2, false);
                    });
    Is this bug in ChangeView? 

    Wednesday, January 15, 2014 11:30 PM

Answers

  • Hi Bryan,

    Try this code, works fine for me with 100 milliseconde deferral. Should help you with this issue. I believe that system is doing something else while double tap event fired.

            private void UIElement_OnDoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
            {
                ScrollViewer sv = (sender as ListView).GetFirstDescendantOfType<ScrollViewer>();
                if (sv == null) return;
                Point p = e.GetPosition(sv);
    
                TimeSpan period = TimeSpan.FromMilliseconds(10);
    
                Windows.System.Threading.ThreadPoolTimer.CreateTimer(async (source) =>
                {
                    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                    {
                        if (sv.ZoomFactor <= 1)
                        {
                            var k = sv.ChangeView(p.X + sv.HorizontalOffset * 2, p.Y + sv.VerticalOffset * 2, 2);
                        }
                        else
                        {
                            sv.ChangeView(sv.HorizontalOffset / 2 - p.X, sv.VerticalOffset / 2 - p.Y, 1);
                        }
                    });
                }
                , period);
                
            }

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.



    Saturday, January 18, 2014 2:36 PM
    Moderator

All replies

  • Hi Bryan,

    Why ScrollViewer.ChangeView fire twice? It is not a bug. Read the documentation of DoubleTapped event:

    If a user interaction also fires DoubleTapped, Tapped will fire first to represent the first tap, but the second tap won't fire an additional Tapped. If you want different logic for Tapped  versus DoubleTapped, your Tapped  handler may need to use app-specific variables and a timer in order to avoid running on interactions that are eventually interpreted as  a DoubleTap action.

    That's the reason, try with a app-specific variable to determine if the user action belong to a doubleTap or just Tap.

    And for the question why the code only work for vertical, I believe that the first ChangeView has been fired, the Vertical scrolling is succeed, but you should wait for the first ChangeView has complete to continue with your second ChangeView which is for Horizontal.

    Why the code works for touch but not for mouse? I can hardly to tell why because there might be several reasons. Basically a mouse click event is a Tap event, the double click should be DoubleTapped as well.

    Furthermore I would not suggest you to use CoreDispatcherPriotity.High in your app, because it is reserved for system events. Using this priority can lead to the starvation of other messages, including system events. Use CoreDispatcherPriority.Normal instead.

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Thursday, January 16, 2014 2:55 AM
    Moderator
  • Jamles, thank you very much for the response, the information is thoughtful but does not help with my specific issue. Here is more information about the bug to help recreate the issue.

    Start with a List View in the xaml.

     <ListView DoubleTapped="UIElement_OnDoubleTapped" SelectionMode="None">
                <Image Height="600" Width="600" Source="http://i.telegraph.co.uk/multimedia/archive/02421/windows_2421293b.jpg"></Image>
                <Image Height="600" Width="600" Source="http://i.telegraph.co.uk/multimedia/archive/02421/windows_2421293b.jpg"></Image>
                <Image Height="600" Width="600" Source="http://i.telegraph.co.uk/multimedia/archive/02421/windows_2421293b.jpg"></Image>
                <Image Height="600" Width="600" Source="http://i.telegraph.co.uk/multimedia/archive/02421/windows_2421293b.jpg"></Image>
                <Image Height="600" Width="600" Source="http://i.telegraph.co.uk/multimedia/archive/02421/windows_2421293b.jpg"></Image>
                <Image Height="600" Width="600" Source="http://i.telegraph.co.uk/multimedia/archive/02421/windows_2421293b.jpg"></Image>
            </ListView>

    Here is the code behind:

    note: "GetFirstDescendantOfType..." is from the Win RT Xaml Toolkit 

            private void UIElement_OnDoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
            {
                ScrollViewer sv = (sender as ListView).GetFirstDescendantOfType<ScrollViewer>();
                if (sv == null) return;
                Point p = e.GetPosition(sv);
    
                if (sv.ZoomFactor <= 1)
                {
                    sv.ChangeView(p.X + sv.HorizontalOffset*2, p.Y + sv.VerticalOffset*2, 2);
                }
                else
                {
                    sv.ChangeView(sv.HorizontalOffset/2 - p.X, sv.VerticalOffset/2 - p.Y, 1);
                }
    
            }

    Now try double click vs. double tap.

    You can see that double tap does not do anything, but double click does change the view.

    When you dispatch the changeview, notice how for tap, only the Y coordinate is respected, and there is no animation.

    await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                    {
                        sv.ChangeView(point.X + sv.HorizontalOffset * 2,
                              point.Y + sv.VerticalOffset * 2, 2, false);
                    });

    Does this code help recreate the bug for you? 

    Thanks again, your input is highly appreciated. 

    Thursday, January 16, 2014 4:38 PM
  • Hi Bryan,

    Thank you for your code and I can reproduce it, everything works fine with double click but nothing change while double tap. Also the dispatcher.RunAsync can only fire with VerticalOffset.

    I will try to figure it out and return to you later. Thanks.

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.


    Friday, January 17, 2014 9:50 AM
    Moderator
  • Thank you James, I look forward to your response.

    Friday, January 17, 2014 11:21 PM
  • Hi Bryan,

    Try this code, works fine for me with 100 milliseconde deferral. Should help you with this issue. I believe that system is doing something else while double tap event fired.

            private void UIElement_OnDoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
            {
                ScrollViewer sv = (sender as ListView).GetFirstDescendantOfType<ScrollViewer>();
                if (sv == null) return;
                Point p = e.GetPosition(sv);
    
                TimeSpan period = TimeSpan.FromMilliseconds(10);
    
                Windows.System.Threading.ThreadPoolTimer.CreateTimer(async (source) =>
                {
                    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                    {
                        if (sv.ZoomFactor <= 1)
                        {
                            var k = sv.ChangeView(p.X + sv.HorizontalOffset * 2, p.Y + sv.VerticalOffset * 2, 2);
                        }
                        else
                        {
                            sv.ChangeView(sv.HorizontalOffset / 2 - p.X, sv.VerticalOffset / 2 - p.Y, 1);
                        }
                    });
                }
                , period);
                
            }

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.



    Saturday, January 18, 2014 2:36 PM
    Moderator
  • James, 

    I am having the same problem where ChangeView() does not work for me. I tried your code above where creating a timer before calling ChangeView(), but that does not help

             private void NewItemTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
            {
                    var period = TimeSpan.FromMilliseconds(10);
                    ThreadPoolTimer.CreateTimer(async (source) =>
                    {
                        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                        {
                            scrollViewer.ChangeView(null, offset, null, true);
                        });
                    }, period);

           }

    I have tried increasing the time out, but that does not help either.

    However, if I just call scrollViewer.ChangeView(null, offset, null, true); and inside debugger with break point set, it works. So how can I fix this problem?

    Friday, October 31, 2014 6:25 AM