Search code examples
c#scrolllistboxtouchpushpin

ScrollIntoView doesn't work with Touch


So I have a map with a number of PushPins on it and a list down the right hand side listing all the PushPins (using the same view models)

When I click a pin on the map I want to scroll the item into view on the list.

I currently use this code on Click and OnTouch:

private void ScrollPushPin(Pushpin pushpin)
{
      ScrollViewer scrollViewer = GetScrollViewer(MyList) as ScrollViewer;
      scrollViewer.ScrollToBottom();
      var index = this.MyList.Items.IndexOf(pushpin);

      //index is never -1 so I would expect it to work?
      this.MyList.ScrollIntoView(pushpin); 
}

On Click:

void pp_MouseDown(object sender, MouseButtonEventArgs e)
{
    ScrollPushPin(sender as PushPin);
}

On Touch:

void pp_TouchDown(object sender, TouchEventArgs e)
{
    var pushpin = (Pushpin)sender;
    pushpin.CaptureTouch(e.TouchDevice);
}

void pp_TouchUp(object sender, TouchEventArgs e)
{
   var pushpin = (Pushpin)sender;
    if (pushpin != null && e.TouchDevice.Captured == pushpin)
    {
        pushpin.ReleaseTouchCapture(e.TouchDevice);
        ScrollPushPin(pushpin);
    }
}

While this code works fine for when I click my pushpin with a mouse the Touch events don't scroll my PushPin into view and I can't see why?

I have also tried:

this.MyList.Dispatcher.Invoke((Action)(() => this.MyList.ScrollIntoView(pushpin)));

and

this.MyList.ScrollIntoView(this.MyList.Items[val]);

Solution

  • So don't ask me why this works but adding e.Handled = true to the end of my events solved the problem:

    void pp_TouchDown(object sender, TouchEventArgs e)
    {
        var pushpin = (Pushpin)sender;
        pushpin.CaptureTouch(e.TouchDevice);
        e.Handled = true
    }
    
    void pp_TouchUp(object sender, TouchEventArgs e)
    {
       var pushpin = (Pushpin)sender;
        if (pushpin != null && e.TouchDevice.Captured == pushpin)
        {
            pushpin.ReleaseTouchCapture(e.TouchDevice);
            ScrollPushPin(pushpin);
        }
        e.Handled = true
    }
    

    EDIT

    adding e.Handled = true caused more problems down the line so I decided to write my own ScrollIntoView

    var val = this.MyList.Items.IndexOf(myObj);
    if (val != -1)
    {
        ScrollViewer scrollViewer = GetScrollViewer(MyList) as ScrollViewer;
        var itemHeight = scrollViewer.ExtentHeight / this.MyList.Items.Count;
        scrollViewer.ScrollToVerticalOffset(itemHeight * val);
    }
    
    //where
    public static DependencyObject GetScrollViewer(DependencyObject o)
    {
        if (o is ScrollViewer)
        { return o; }
    
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
        {
            var child = VisualTreeHelper.GetChild(o, i);
    
            var result = GetScrollViewer(child);
            if (result == null)
            {
                continue;
            }
            else
            {
                return result;
            }
        }
    
        return null;
    }