23

I am writing my custom WPF ItemsControl to display a list of item. The items are shown embedded inside a ScrollViewer:

<Style TargetType="MyCustomItemsControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="MyCustomItemsControl">
                    <ScrollViewer x:Name="PART_MyScrollViewer" >
                           <ItemsPresenter/>
                    </ScrollViewer>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
</Style>

I want to make sure that when I move the mouse into the control, a particular item (marked as selected) will be scrolled into the mouse position. In my OnMouseEnter method I am able to find the item but I don't know what to do next. Does anyone have any idea?

protected override void OnMouseEnter(MouseEventArgs e)
{
    for (int i = 0; i < Items.Count; i++)
    {
        ContentPresenter uiElement = (ContentPresenter)ItemContainerGenerator.ContainerFromIndex(i);
        var item = uiElement.Content as MyCustomObject;
        if (item.IsSelected)
        {
            // How to scroll the uiElement to the mouse position?
            break;
        }
    }
}
H.B.
  • 166,899
  • 29
  • 327
  • 400
Metro
  • 1,121
  • 1
  • 13
  • 33

4 Answers4

38
// How to scroll the uiElement to the mouse position?
uiElement.BringIntoView();

REF: https://msdn.microsoft.com/en-us/library/ms598110.aspx

UPDATE: (thanks to @jmbpiano) Note, it does not bring the control exactly to the current mouse cursor position. It just brings the control to a visible position, where the Operator will be able to click it with the mouse (which in 99% of cases is all someone who finds this question is likely to need).

epox
  • 9,236
  • 1
  • 55
  • 38
  • 1
    Thank you so much ! I spent a whole day with other ways but finally your solution saved me..really really appreciate so much !!! – Kay Lee May 27 '16 at 09:42
  • 5
    This doesn't actually do what the asker requested, as it completely ignores the mouse's position, but it does at least bring the control into view on the screen (which in 99% of cases is all someone who finds this question is likely to need). So it's certainly a valuable contribution. – jmbpiano Oct 20 '16 at 21:00
  • 1
    Thanks! This really save the day! – Mike97 Jan 06 '21 at 14:09
26

Something like the following:

var sv = (ScrollViewer)Template.FindName("PART_MyScrollViewer", this); // If you do not already have a reference to it somewhere.
var ip = (ItemsPresenter)sv.Content;
var point = item.TranslatePoint(new Point() - (Vector)e.GetPosition(sv), ip);
sv.ScrollToVerticalOffset(point.Y + (item.ActualHeight / 2));
H.B.
  • 166,899
  • 29
  • 327
  • 400
9

Use UIElement.TranslatePoint() to calculate what position you want to scroll to

Use ScrollViewer.ScrollToVerticalOffset() to do the scrolling

Robert Levy
  • 28,747
  • 6
  • 62
  • 94
0

Try this below code :


private void ScrollViewerFromVSTree(DependencyObject element, double pos)
{
    try
    {
        int totalElementcount = VisualTreeHelper.GetChildrenCount(element);
        for (int counter = 0; counter < totalElementcount; counter++)
        {
            DependencyObject ele = VisualTreeHelper.GetChild(element, counter);
            if (ele.GetType().Name == "ScrollViewer")
            {
                ScrollViewer scrollViewer = ele as ScrollViewer;
                if (pos > "YourAssumption") // for me it is 610
                {
                    scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + 45);
                }
                else if (pos < "YourAssumption") //for me it is 40
                {
                    scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - 45);
                }
                break;
            }
            ScrollViewerFromVSTree(VisualTreeHelper.GetChild(element, counter), pos);
        }
    }
    catch (Exception)
    {
    }
}

Alexandre Tranchant
  • 4,426
  • 4
  • 43
  • 70