为什么我的 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"/>
编辑
如果您不想使用预定义的Width
或MaxWidth
,请将Grid
的Width
绑定到[=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>
感谢库加院长。它的解决方案让我开始了我的想法。
结果:
为什么我的 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"/>
编辑
如果您不想使用预定义的Width
或MaxWidth
,请将Grid
的Width
绑定到[=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>
感谢库加院长。它的解决方案让我开始了我的想法。
结果: