从C#访问ListBox的ScrollViewer中从C#访问ListBox的ScrollViewe

2019-05-12 02:00发布

我想改变的属性ScrollViewer一个的ListBox从C#。

我发现这个问题,在这里#2。 我把接受的答案的意见,并暴露了ScrollViewer的一个子类的属性。 然而,这不会出现在下面所示的例子是工作。 一些在这个问题的评论还指出,这种技术没有工作。

XAML:

<Window x:Class="StackoverflowListBoxScrollViewer.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">

</Window>

C#:

using System;
using System.Windows;
using System.Windows.Controls;

namespace StackoverflowListBoxScrollViewer
{
    public class MyListBox : ListBox
    {
        public ScrollViewer ScrollViewer
        { get { return (ScrollViewer)GetTemplateChild("ScrollViewer"); } }
    }

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            var myListBox = new MyListBox();

            Content = myListBox;

            myListBox.Items.Add(new Button() { Content = "abc" });
            myListBox.Items.Add(new Button() { Content = "abc" });
            myListBox.Items.Add(new Button() { Content = "abc" });
            myListBox.Items.Add(new Button() { Content = "abc" });
            myListBox.Items.Add(new Button() { Content = "abc" });

            var button = new Button() { Content = "Check ScrollViewer" };
            button.Click += (s, e) =>
                {
                    if (myListBox.ScrollViewer == null)
                        Console.WriteLine("null");
                };
            myListBox.Items.Add(button);
        }
    }
}

当我点击“检查的ScrollViewer”按钮,它打印“空”。 即, ScrollViewer没有检索。

我如何去织补ScrollViewer ? :-)

Answer 1:

如果您将使用标准列表框,这样你就可以改变你消气剂这一项:

public class MyListBox : ListBox
{
    public ScrollViewer ScrollViewer
    {
        get 
        {
            Border border = (Border)VisualTreeHelper.GetChild(this, 0);

            return (ScrollViewer)VisualTreeHelper.GetChild(border, 0);
        }
    }
}


Answer 2:

你可以试试这个小助手功能

用法

var scrollViewer = GetDescendantByType(yourListBox, typeof(ScrollViewer)) as ScrollViewer;

辅助函数

public static Visual GetDescendantByType(Visual element, Type type)
{
  if (element == null) {
    return null;
  }
  if (element.GetType() == type) {
    return element;
  }
  Visual foundElement = null;
  if (element is FrameworkElement) {
    (element as FrameworkElement).ApplyTemplate();
  }
  for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) {
    Visual visual = VisualTreeHelper.GetChild(element, i) as Visual;
    foundElement = GetDescendantByType(visual, type);
    if (foundElement != null) {
      break;
    }
  }
  return foundElement;
}

希望这可以帮助



Answer 3:

我修改@ punker76伟大的答案开创了视觉的扩展方法,并提供明确的返回类型:

   public static class Extensions
   {
      public static T GetDescendantByType<T>(this Visual element) where T:class
      {
         if (element == null)
         {
            return default(T);
         }
         if (element.GetType() == typeof(T))
         {
            return element as T;
         }
         T foundElement = null;
         if (element is FrameworkElement)
         {
            (element as FrameworkElement).ApplyTemplate();
         }
         for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
         {
            var visual = VisualTreeHelper.GetChild(element, i) as Visual;
            foundElement = visual.GetDescendantByType<T>();
            if (foundElement != null)
            {
               break;
            }
         }
         return foundElement;
      }

   }

您现在可以通过SomeVisual.GetDescendantByType调用它,它返回要么已经正确类型化的ScrollViewer或空(这是默认(T))



Answer 4:

至于我,露出的ScrollViewer为一个属性是一个坏主意。 首先,有一个ScrollViewer中存在的模板不能保证。 其次,ScrollViewer中工作与ItemsPanel和ItemContainerGenerator同步。 重写,这是直接的方式来罕见的行为。

WPF控件使用另一种模式。 其类似外的逻辑使用和内部可视化表示之间的调停。 你的列表框应该公开可通过ScrollViewer中在模板中使用,但不能ScrollViewer中的属性。 通过这样做,你打破WPF的标准,限制你的控制,以特定的模板,并允许用户代码破解内部列表框的实现。



Answer 5:

这里的@ punker76的答案为C#6的另一个整顿和通用版:

public static class VisualExtensions
{
    public static T FindVisualDescendant<T>(this Visual element) where T : Visual
    {
        if (element == null)
            return null;

        var e = element as T;

        if (e != null)
            return e;

        (element as FrameworkElement)?.ApplyTemplate();

        var childrenCount = VisualTreeHelper.GetChildrenCount(element);

        for (var i = 0; i < childrenCount; i++)
        {
            var visual = VisualTreeHelper.GetChild(element, i) as Visual;

            var foundElement = visual.FindVisualDescendant<T>();

            if (foundElement != null)
                return foundElement;
        }

        return null;
    }
}


文章来源: Accessing the ScrollViewer of a ListBox from C#