我想改变的属性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
? :-)
如果您将使用标准列表框,这样你就可以改变你消气剂这一项:
public class MyListBox : ListBox
{
public ScrollViewer ScrollViewer
{
get
{
Border border = (Border)VisualTreeHelper.GetChild(this, 0);
return (ScrollViewer)VisualTreeHelper.GetChild(border, 0);
}
}
}
你可以试试这个小助手功能
用法
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;
}
希望这可以帮助
我修改@ 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))
至于我,露出的ScrollViewer为一个属性是一个坏主意。 首先,有一个ScrollViewer中存在的模板不能保证。 其次,ScrollViewer中工作与ItemsPanel和ItemContainerGenerator同步。 重写,这是直接的方式来罕见的行为。
WPF控件使用另一种模式。 其类似外的逻辑使用和内部可视化表示之间的调停。 你的列表框应该公开可通过ScrollViewer中在模板中使用,但不能ScrollViewer中的属性。 通过这样做,你打破WPF的标准,限制你的控制,以特定的模板,并允许用户代码破解内部列表框的实现。
这里的@ 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;
}
}