为什么我的 TreeViewItem 文本没有包含在我的示例代码中?如何让它包裹起来?

Why my TreeViewItem text do not wrap in my sample code? How to make it wrap?

为什么我的 TreeViewItem 没有包含在我的示例代码中?

Xaml:

<Window x:Class="WpfAppTestScrollViewBehavior.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfAppTestScrollViewBehavior"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainWindowModel></local:MainWindowModel>
    </Window.DataContext>

    <TabControl>
        <TabItem Header="Test">
            <TreeView ItemsSource="{Binding Level1s, Mode=OneWay}" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                      Background="LightGoldenrodYellow">
                <TreeView.Resources>
                    <HierarchicalDataTemplate DataType="{x:Type local:Level1}"
                                            ItemsSource="{Binding Path=InstalledFontCollection}">
                        <Grid HorizontalAlignment="Stretch" Background="LightGreen">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"></ColumnDefinition>
                                <ColumnDefinition></ColumnDefinition>
                            </Grid.ColumnDefinitions>
                            <CheckBox Grid.Column="0" IsChecked="{Binding Path=IsSelected}"></CheckBox>
                            <TextBlock Grid.Column="1" Text="{Binding Path=Name}" 
                                        TextWrapping="Wrap" Margin="5,0,0,0"></TextBlock>
                        </Grid>
                    </HierarchicalDataTemplate>
                </TreeView.Resources>
            </TreeView>
        </TabItem>
    </TabControl>
</Window>

代码:

using System;
using System.Collections.Generic;

namespace WpfAppTestScrollViewBehavior
{
    public class MainWindowModel
    {
        public List<Level1> Level1s { get; } = new List<Level1>();

        public MainWindowModel()
        {
            Level1s.Add(new Level1());
        }
    }
}


using System;
using System.Drawing.Text;

namespace WpfAppTestScrollViewBehavior
{
    public class Level1
    {
        public bool IsSelected { get; set; }
        public string Name { get; set; } = "a very long name in order to test text wrapping functionnality";

        public InstalledFontCollection InstalledFontCollection { get; } = new InstalledFontCollection();
    }
}

只是为了防止快速错误的答案:

您可以添加这段代码,它工作正常:

<TabItem Header="Test 2">
    <ScrollViewer HorizontalScrollBarVisibility="Disabled">
        <Grid HorizontalAlignment="Stretch" Background="LightPink">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <CheckBox Grid.Column="0"></CheckBox>
            <TextBlock Grid.Column="1" Text="long name just for testing" 
                        TextWrapping="Wrap" Margin="5,0,0,0"></TextBlock>
        </Grid>
    </ScrollViewer>
</TabItem>

之前工作代码的结果(就像我期望的例子):

ColumnDefinition 默认为 *,因此第 1 列中的 TextBlock 将占用所有可用的 space。

像这样尝试 MaxWidth<ColumnDefinition Width="Auto" MaxWidth="100"/>

编辑

如果您不想使用预定义的WidthMaxWidth,请将GridWidth绑定到[=20的ActualWidth =] 像这样:

<Grid Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=ActualWidth}" />

我刚刚测试了这种方法,它很好地包装了 TextBlock,并在我调整 window 的大小时重新包装了它...如果 TextBlock 的文本没有边距相对于右 window 边框,当以这种方式设置宽度时,您可以通过将 TextBlock 的右边距设置为 10 或更多来解决此问题,具体取决于所需的填充...

由于您没有指定 Width 它正在为 <Textblock>

提供可用的 Width

Why does my TreeViewItem does not wrap in my sample code?

文本正在换行,但由于宽度不受限制,所以看不到可用的换行

例如:

XAML:宽度:150 个单位 TextWrapping = "NoWrap"

<TextBlock Grid.Column="1" Text="{Binding Path=Name}"   Width="150" Name="textblock1"
                                        TextWrapping="NoWrap" Margin="10,0,0,0"></TextBlock>

输出:

XAML:宽度:150 个单位 TextWrapping = "Wrap"

<TextBlock Grid.Column="1" Text="{Binding Path=Name}"   Width="150" Name="textblock1"
                                        TextWrapping="Wrap" Margin="10,0,0,0"></TextBlock>

<Grid HorizontalAlignment="Stretch" Width="150" Background="LightGreen">
     public string Name { get; set; } = ;

我想出了一个通用的解决方案,似乎适用于任何情况,无论 TreeViewItem 中有什么内容。 它可以作为一种行为来应用(我赞成这样做是为了使其更易于使用)。

使用此行为的一个限制是:将行为定义为 TreeView xaml 中的最后一个元素。通过这样做,它将支持之前定义的任何其他 ItemContainerStyle。

行为代码:

using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using HQ.Wpf.Util;
using HQ.Wpf.Util.Converter;

namespace WpfAppTestScrollViewBehavior
{
    public class BehaviorTreeView : Behavior<TreeView>
    {
        public static readonly DependencyProperty ShowHorizontalScrollBarProperty = DependencyProperty.Register(
            "PropertyType", typeof(bool), typeof(BehaviorTreeView), new PropertyMetadata(true));

        /// <summary>
        /// Settting this poroperty to false will fake a TreeView-ScrollView ViewPort finite width. 
        /// TreeViewItem will be advise to Calculate their width according to the width of the 
        /// ViewPort of the ScrollView of the TreeView.
        /// </summary>
        public bool ShowHorizontalScrollBar
        {
            get { return (bool)GetValue(ShowHorizontalScrollBarProperty); }
            set { SetValue(ShowHorizontalScrollBarProperty, value); }
        }

        // ******************************************************************   
        protected override void OnAttached()
        {
            base.OnAttached();

            if (!ShowHorizontalScrollBar)
            {
                Style style = AssociatedObject.ItemContainerStyle ?? new Style(typeof(TreeViewItem));
                var eventSetter = new EventSetter(FrameworkElement.LoadedEvent, new RoutedEventHandler(this.TreeViewItemLoaded));
                style.Setters.Add(eventSetter);
                AssociatedObject.ItemContainerStyle = style;
            }
        }

        // ******************************************************************   
        private void TreeViewItemLoaded(object sender, RoutedEventArgs e)
        {
            var tvi = sender as TreeViewItem;
            var contentPresenter = tvi.FindFirstChildWithNameRecursive<ContentPresenter>("PART_Header");

            var treeView = tvi.GetVisualParentRecursive<TreeView>();

            double offsetX = contentPresenter.TransformToAncestor(treeView).Transform(new Point(0, 0)).X;

            var scrollViewer = treeView.FindVisualChild<ScrollViewer>();

            Binding binding = new Binding();
            binding.Source = scrollViewer;
            binding.Path = new PropertyPath(nameof(ScrollViewer.ViewportWidth));
            binding.Mode = BindingMode.OneWay;

            var converter = new NumericFixedNumberAddedConverter();
            binding.Converter = converter;
            binding.ConverterParameter = -offsetX;

            BindingOperations.SetBinding(contentPresenter, FrameworkElement.WidthProperty, binding);
        }

        // ******************************************************************   

    }
}

行为依赖:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace WpfAppTestScrollViewBehavior
{
    class NumericFixedNumberAddedConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            try
            {
                return (double) value + double.Parse(parameter.ToString());
            }
            catch (Exception ex)
            {
                Debug.Print(ex.ToString());
                return value;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace WpfAppTestScrollViewBehavior
{
    public static class UiUtility
    {
        // ******************************************************************
        public static Window GetTopLevelOwnerWindowOrMainAppWindow(Control usercontrol)
        {
            return GetTopLevelOwnerWindow(usercontrol) ?? Application.Current.MainWindow;
        }

        // ******************************************************************
        public static Window GetTopLevelOwnerWindowOrMainAppWindow(DependencyObject dependencyObject)
        {
            return GetTopLevelOwnerWindow(dependencyObject) ?? Application.Current.MainWindow;
        }

        // ******************************************************************
        public static Window GetTopLevelOwnerWindow(Control usercontrol)
        {
            return GetTopLevelOwnerWindow((DependencyObject)usercontrol);
        }

        // ******************************************************************
        public static Window GetTopLevelOwnerWindow(DependencyObject dependencyObject)
        {
            while (dependencyObject != null && !(dependencyObject is Window))
            {
                var dependencyObjectCopy = dependencyObject;
                dependencyObject = VisualTreeHelper.GetParent(dependencyObject);

                if (dependencyObject == null)
                {
                    dependencyObject = dependencyObjectCopy;
                    String propName = "DockSite";
                    PropertyInfo pi = dependencyObject.GetType().GetProperty(propName);
                    if (pi != null)
                    {
                        DependencyObject dependencyObjectTemp = null;
                        try
                        {
                            dependencyObjectTemp = dependencyObject.GetType().InvokeMember(propName,
                                BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public, null, dependencyObject, null) as DependencyObject;
                        }
                        catch (Exception)
                        {

                        }

                        if (dependencyObjectTemp != null)
                        {
                            dependencyObject = LogicalTreeHelper.GetParent(dependencyObjectTemp);
                        }
                        else
                        {
                            dependencyObject = LogicalTreeHelper.GetParent(dependencyObject);
                        }
                    }
                    else
                    {
                        dependencyObject = LogicalTreeHelper.GetParent(dependencyObject);
                    }
                }
            }

            return dependencyObject as Window;
        }

        // ******************************************************************
        public static T FindVisualParent<T>(DependencyObject element) where T : DependencyObject
        {
            var parent = element;
            while (parent != null)
            {
                var correctlyTyped = parent as T;
                if (correctlyTyped != null)
                {
                    return correctlyTyped;
                }

                parent = VisualTreeHelper.GetParent(parent) as DependencyObject;

            }
            return null;
        }

        // ******************************************************************
        public static bool IsParentOf(DependencyObject parent, DependencyObject child)
        {
            if (parent == null || child == null)
            {
                return false;
            }

            DependencyObject childParent = child;
            do
            {
                if (childParent == parent)
                {
                    return true;
                }

                childParent = VisualTreeHelper.GetParent(childParent);
            } while (childParent != null);

            return false;
        }

        // ******************************************************************
        public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
        {
            if (depObj != null)
            {
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                    if (child != null && child is T)
                    {
                        yield return (T)child;
                    }

                    foreach (T childOfChild in FindVisualChildren<T>(child))
                    {
                        yield return childOfChild;
                    }
                }
            }
        }

        // ******************************************************************
        public static DataGridColumnHeader GetColumnHeaderFromColumn(DataGrid dataGrid, DataGridColumn column)
        {
            // dataGrid is the name of your DataGrid. In this case Name="dataGrid"
            foreach (var columnHeader in FindVisualChildren<DataGridColumnHeader>(dataGrid))
            {
                if (columnHeader.Column == column)
                {
                    return columnHeader;
                }
            }
            return null;
        }

        // ******************************************************************
        public static void SafeInvoke(Action action)
        {
            if (Application.Current.Dispatcher.CheckAccess())
            {
                action();
            }
            else
            {
                Application.Current.Dispatcher.Invoke(action);
            }
        }

        // ******************************************************************
        public static void SafeBeginInvoke(Action action)
        {
            if (Application.Current.Dispatcher.CheckAccess())
            {
                action();
            }
            else
            {
                Application.Current.Dispatcher.BeginInvoke(action);
            }
        }

        // ******************************************************************
        public static void BindingRefresh(DependencyObject dependencyObject, DependencyProperty dependencyProperty)
        {
            BindingExpressionBase b = BindingOperations.GetBindingExpressionBase(dependencyObject, dependencyProperty);
            if (b != null)
            {
                b.UpdateTarget();
            }
        }

        // ******************************************************************
        /// <summary>
        /// Finds a Child of a given item in the visual tree. 
        /// </summary>
        /// <param name="parent">A direct parent of the queried item.</param>
        /// <typeparam name="T">The type of the queried item.</typeparam>
        /// <param name="childName">x:Name or Name of child. </param>
        /// <returns>The first parent item that matches the submitted type parameter. 
        /// If not matching item can be found, 
        /// a null parent is being returned.</returns>
        public static T FindChild<T>(DependencyObject depObj, string childName)
            where T : DependencyObject
        {
            // Confirm obj is valid. 
            if (depObj == null) return null;

            // success case
            if (depObj is T && ((FrameworkElement)depObj).Name == childName)
                return depObj as T;

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);

                //DFS
                T obj = FindChild<T>(child, childName);

                if (obj != null)
                    return obj;
            }

            return null;
        }

        // ******************************************************************
        public static void DebugPrintControlParentHierarchy(object frameworkElement)
        {
            StringBuilder hierarchy = new StringBuilder();
            var fe = frameworkElement as FrameworkElement;
            while (fe != null)
            {
                hierarchy.Append(String.Format("{0} [{1}] ==> ", fe.GetType(), fe.Name));
                fe = VisualTreeHelper.GetParent(fe) as FrameworkElement;
            }

            hierarchy.Append("!TOP!");

            Debug.Print(hierarchy.ToString());
        }

        // ******************************************************************
        /// <summary>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T FindVisualChild<T>(this DependencyObject obj) where T : DependencyObject
        {
            if (obj != null && obj is Visual)
            {
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                    var visualChild = child as T;
                    if (visualChild != null)
                        return visualChild;
                    else
                    {
                        T childOfChild = FindVisualChild<T>(child);
                        if (childOfChild != null)
                            return childOfChild;
                    }
                }
            }
            return null;
        }

        // ******************************************************************
        public static FrameworkElement GetVisualParent(this UIElement element)
        {
            DependencyObject parent = VisualTreeHelper.GetParent(element);
            do
            {
                var fe = parent as FrameworkElement;
                if (fe != null)
                {
                    return fe;
                }
                parent = VisualTreeHelper.GetParent(parent);
            } while (parent != null);

            return null;
        }

        // ******************************************************************
        public static void BringToFront(this Panel panel, UIElement element)
        {
            int maxIndex = 0;
            foreach (UIElement e in panel.Children)
            {
                maxIndex = Math.Max(maxIndex, Panel.GetZIndex(e));
            }

            Panel.SetZIndex(element, maxIndex + 1);
        }

        //// ******************************************************************
        ///// <summary>
        ///// Return the center point of an direct child of a Canvas (not yet tested)
        ///// </summary>
        ///// <param name=""></param>
        ///// <param name="elementRelativeTo">If elementRelativeTo == null, will use direct parent</param>
        ///// <returns></returns>
        //public static Point GetCanvasElementCenterPoint(this FrameworkElement element)
        //{
        //  return new Point(
        //      Canvas.GetLeft(element) + (element.ActualWidth / 2),
        //      Canvas.GetTop(element) + (element.ActualHeight / 2));
        //}

        // ******************************************************************
        public enum PointPositionVertical
        {
            Top,
            Center,
            Bottom
        }

        // ******************************************************************
        public enum PointPositionHorizontal
        {
            Left,
            Center,
            Right
        }

        // ******************************************************************
        public static Point GetChildCoordinate(this UIElement elementContainer, FrameworkElement childElement,
            PointPositionHorizontal pointPositionHorizontal = PointPositionHorizontal.Left,
            PointPositionVertical pointPositionVertical = PointPositionVertical.Top)
        {
            double x;
            switch (pointPositionHorizontal)
            {
                case PointPositionHorizontal.Center:
                    x = childElement.ActualWidth / 2;
                    break;
                case PointPositionHorizontal.Right:
                    x = childElement.ActualWidth;
                    break;
                default:
                    x = 0;
                    break;
            }

            double y;
            switch (pointPositionVertical)
            {
                case PointPositionVertical.Center:
                    y = childElement.ActualHeight / 2;
                    break;
                case PointPositionVertical.Bottom:
                    y = childElement.ActualHeight;
                    break;
                default:
                    y = 0;
                    break;
            }

            return childElement.TranslatePoint(new Point(x, y), elementContainer);
        }

        // ******************************************************************
        public static void ApplyToEachVisualChildRecursively(this DependencyObject obj, Action<DependencyObject> action)
        {
            if (obj != null && obj is Visual)
            {
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
                {
                    DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                    if (child != null)
                    {
                        action(child);
                        ApplyToEachVisualChildRecursively(child, action);
                    }
                }
            }
        }

        // ******************************************************************
        public static T GetVisualParentRecursive<T>(this DependencyObject obj) where T : class
        {
            var element = obj as FrameworkElement;
            if (element != null)
            {
                var frameWorkElement = VisualTreeHelper.GetParent(element) as FrameworkElement;
                if (frameWorkElement != null)
                {
                    var t = frameWorkElement as T;
                    if (t != null)
                    {
                        return t;
                    }
                    return frameWorkElement.GetVisualParentRecursive<T>();
                }
            }

            return null;
        }

        // ******************************************************************
        public static T HitTest<T>(this Visual visual, Point pt) where T : class
        {
            T hitResult = null;

            VisualTreeHelper.HitTest(visual, null, result =>
            {
                if (result.VisualHit is T)
                {
                    hitResult = result.VisualHit as T;
                    return HitTestResultBehavior.Stop;
                }

                hitResult = result.VisualHit?.GetVisualParentRecursive<T>();
                if (hitResult != null)
                {
                    return HitTestResultBehavior.Stop;
                }

                return HitTestResultBehavior.Continue;

            }, new PointHitTestParameters(pt));

            return hitResult;
        }

        // ******************************************************************
        public static IEnumerable<T> GetChildrenRecursive<T>(this DependencyObject depObj) where T : class
        {
            int count = VisualTreeHelper.GetChildrenCount(depObj);
            for (int n = 0; n < count; n++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, n);
                if (child is T)
                {
                    yield return child as T;
                }

                foreach (T depObjChild in child.GetChildrenRecursive<T>())
                {
                    yield return depObjChild;
                }
            }
        }

        // ******************************************************************
        /// <summary>
        /// EO, 2017-05-11: New code
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static T GetVisualParentRecursive<T>(this DependencyObject obj, Predicate<T> predicate = null) where T : class
        {
            var element = obj as FrameworkElement;
            if (element != null)
            {
                var frameWorkElement = VisualTreeHelper.GetParent(element) as FrameworkElement;
                if (frameWorkElement != null)
                {
                    var t = frameWorkElement as T;
                    if (t != null)
                    {
                        if (predicate == null || predicate(t))
                        {
                            return t;
                        }
                    }
                    return frameWorkElement.GetVisualParentRecursive<T>(predicate);
                }
            }

            return null;
        }

        // ******************************************************************   
        /// <summary>
        /// EO, 2017-05-11: New code
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static T FindFirstChildWithNameRecursive<T>(this DependencyObject parent, string name) where T : FrameworkElement
        {
            return FindFirstChildRecursive(parent, (T child) => child.Name == name);
        }

        // ******************************************************************   
        /// <summary>
        /// Find all controls (visual or not)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static T FindFirstChildRecursive<T>(this DependencyObject parent, Predicate<T> predicate = null) where T : DependencyObject
        {
            if (parent == null)
            {
                return null;
            }

            //use the visual tree for Visual / Visual3D elements
            if (parent is Visual || parent is Visual3D)
            {
                int count = VisualTreeHelper.GetChildrenCount(parent);
                for (int i = 0; i < count; i++)
                {
                    var child = VisualTreeHelper.GetChild(parent, i);
                    var childAsT = child as T;
                    if (childAsT != null)
                    {
                        if (predicate == null || predicate(childAsT))
                        {
                            return childAsT;
                        }
                    }

                    var result = FindFirstChildRecursive(child, predicate);
                    if (result != null)
                    {
                        return result;
                    }
                }
            }
            else //use the logical tree for content / framework elements
            {
                foreach (DependencyObject child in LogicalTreeHelper.GetChildren(parent))
                {
                    var childAsT = child as T;
                    if (childAsT != null)
                    {
                        if (predicate == null || predicate(childAsT))
                        {
                            return childAsT;
                        }
                    }

                    var result = FindFirstChildRecursive(child, predicate);
                    if (result != null)
                    {
                        return result;
                    }
                }
            }

            return null;
        }

        // ******************************************************************   
        /// <summary>
        /// Non recursive
        /// Based on Whosebug: 
        /// Find all controls (visual or not)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static IEnumerable<T> FindChilds<T>(this DependencyObject parent, Predicate<T> predicate) where T : DependencyObject
        {
            if (parent == null) yield break;

            //use the visual tree for Visual / Visual3D elements
            if (parent is Visual || parent is Visual3D)
            {
                int count = VisualTreeHelper.GetChildrenCount(parent);
                for (int i = 0; i < count; i++)
                {
                    var childAsT = VisualTreeHelper.GetChild(parent, i) as T;
                    if (childAsT != null)
                    {
                        if (predicate(childAsT))
                        {
                            yield return childAsT;
                        }
                    }
                }
            }
            else //use the logical tree for content / framework elements
            {
                foreach (DependencyObject obj in LogicalTreeHelper.GetChildren(parent))
                {
                    var childAsT = obj as T;
                    if (childAsT != null)
                    {
                        if (predicate(childAsT))
                        {
                            yield return childAsT;
                        }
                    }
                }
            }
        }

        // ******************************************************************   
        /// <summary>
        /// EO, 2017-05-11: New code
        /// Find all controls (visual or not)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static List<T> FindChildsWithNameRecursive<T>(this DependencyObject parent, string name) where T : FrameworkElement
        {
            return FindChildsRecursive(parent, (T child) => child.Name == name);
        }

        // ******************************************************************   
        /// <summary>
        /// Find all controls (visual or not)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="parent"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static List<T> FindChildsRecursive<T>(this DependencyObject parent, Predicate<T> predicate = null) where T : DependencyObject
        {
            List<T> childs = new List<T>();
            return FindChildsRecursiveInternal(parent, predicate, childs);
        }

        // ******************************************************************   
        private static List<T> FindChildsRecursiveInternal<T>(this DependencyObject parent, Predicate<T> predicate, List<T> childs) where T : DependencyObject
        {
            if (parent != null)
            {
                //use the visual tree for Visual / Visual3D elements
                if (parent is Visual || parent is Visual3D)
                {
                    int count = VisualTreeHelper.GetChildrenCount(parent);
                    for (int i = 0; i < count; i++)
                    {
                        var child = VisualTreeHelper.GetChild(parent, i);
                        var childAsT = child as T;
                        if (childAsT != null)
                        {
                            if (predicate == null || predicate(childAsT))
                            {
                                childs.Add(childAsT);
                            }
                        }

                        FindChildsRecursiveInternal(child, predicate, childs);
                    }
                }
                else //use the logical tree for content / framework elements
                {
                    foreach (DependencyObject child in LogicalTreeHelper.GetChildren(parent))
                    {
                        var childAsT = child as T;
                        if (childAsT != null)
                        {
                            if (predicate == null || predicate(childAsT))
                            {
                                childs.Add(childAsT);
                            }
                        }

                        FindChildsRecursiveInternal(child, predicate, childs);
                    }
                }
            }

            return childs;
        }

        // ******************************************************************   }
    }
}

用法:

        <!-- ScrollViewer.HorizontalScrollBarVisibility="Disabled" -->
        <TreeView ItemsSource="{Binding Level1s, Mode=OneWay}">

            ...

            <i:Interaction.Behaviors>
                <local:BehaviorTreeView ShowHorizontalScrollBar="False"></local:BehaviorTreeView>
            </i:Interaction.Behaviors>

感谢库加院长。它的解决方案让我开始了我的想法。

结果: