Get reference to my WPF ListBox's ScrollViewer in C#?

我的未来我决定 提交于 2019-11-29 11:39:18

You probably try to get a reference to the ScrollViewer too soon. Try to move your code in the loaded event and check if it still returns null:

in your customControl/form constructor:

this.Loaded += MainWindow_Loaded;

void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
   var x = PART_SoundList.Template.FindName("Scroller", PART_SoundList);
}

Use recursive call to Visual Tree to grab any Visual from the tree.

public static ChildItem FindVisualChild<childItem>(DependencyObject obj) where ChildItem : DependencyObject

        {

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)

            {

                DependencyObject child = VisualTreeHelper.GetChild(obj, i);

                if (child != null && child is ChildItem)

                    return (ChildItem)child;

                else

                {

                    ChildItem childOfChild = FindVisualChild<ChildItem>(child);

                    if (childOfChild != null)

                        return childOfChild;

                }

            }

            return null;

        }

This gives you a generic method to get Visual element of type mentioned from the Visual tree.

I'm assuming that the XAML you have above is part of the ControlTemplate for your CustomControl, right? I would also assume that you're getting the control parts on the OnApplyTemplate() method, right? If this is the case, then, I think what you need to do is to force a call to PART_SoundList.ApplyTemplate() before finding the ScrollViewer. So, the code for your Custom Control should look something like this:

public class MyControl : Control
{
    private ListBox lb;
    private ScrollViewer scroller;

    static MyControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(typeof(MyControl)));
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        lb = this.Template.FindName("PART_SoundList", this) as ListBox;
        lb.ApplyTemplate();
        scroller = lb.Template.FindName("Scroller", lb) as ScrollViewer;
    }
}

If you are going to use the reference to scroll/check viewport size the IScrollProvider should be sufficient for you.

You can access it like this in your code behind (Note Claudiu point of waiting til the loaded event):

ListBoxAutomationPeer svAutomation = (ListBoxAutomationPeer)ScrollViewerAutomationPeer.CreatePeerForElement(PART_SoundList);
// not feeling creative with my var names today...
IScrollProvider scrollInterface = (IScrollProvider)svAutomation.GetPattern(PatternInterface.Scroll);

Then scroll horizontally and vertically whenever you want and to your hearts content.

For those who got here seeking an answer to the original question:

In C#

ScrollViewer sv = FindVisualChild<ScrollViewer>(MyListBox);

or in VB

Dim sv As ScrollViewer = FindVisualChild(Of ScrollViewer)(MyListBox)

Where in XAML

<ListBox x:Name="MyListBox">
</ListBox>

Use this to access scroll viewer in WPF.

var scrollViewer = ((Border)PlaybackDeviceList.Template.FindName("Bd", PlaybackDeviceList)).Child;

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!