我正在尝试从此处更改数据绑定树视图的布局:
alt text http://www.freeimagehosting.net/uploads/776c1333f5.png
对此:
alt text http://www.freeimagehosting.net/uploads/99106b4cfd.png
当然,选择必须正常:
alt text http://www.freeimagehosting.net/uploads/8b628758d7.png
您对如何做到这一点有任何想法吗?我一直在尝试更改模板,但我找不到有这种行为的方法。也许一个组件已经存在......
感谢您的帮助!
答案 0 :(得分:4)
这很难。它似乎需要一个HierarchicalDataTemplate
,但因为你想要的行为需要多个ItemsControls,它不会按预期工作。我认为没有办法在XAML中创建TreeView
模板来执行此操作。您最好的选择是创建某种自定义项控件。您可能需要在代码中而不是在XAML中执行项绑定,因为如果没有HierarchicalDataTemplate
,则XAML无法理解嵌套关系。
话虽如此,如果您保证只有2级嵌套(如您的示例所示),您可以使用以下标记轻松完成此操作:
<Window.Resources>
<DataTemplate x:Key="ItemTemplate">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</Window.Resources>
<StackPanel Orientation="Horizontal">
<ListBox Name="Level1" Width="150" Height="150"
ItemsSource="{Binding Collection}"
ItemTemplate="{StaticResource ItemTemplate}"/>
<ListBox Name="Level2" Width="150" Height="150"
ItemsSource="{Binding ElementName=Level1, Path=SelectedValue.Children}"
ItemTemplate="{StaticResource ItemTemplate}"/>
<ListBox Name="Level3" Width="150" Height="150"
ItemsSource="{Binding ElementName=Level2, Path=SelectedValue.Children}"
ItemTemplate="{StaticResource ItemTemplate}"/>
</StackPanel>
其中Collection
是您的根项集合,并且每个项目都有一个名为Children
的属性,其中包含子集合。
但我认为你要求的是一个可以支持任意数量嵌套级别的项目控件,而不仅仅是2.所以在这种情况下,我会在代码隐藏中执行此操作。绑定将是相同的 - 也就是说,在每个级别,ListBox
应绑定到父级别的项目。但是你显然需要迭代并为每个嵌套级别创建一个ListBox
。
答案 1 :(得分:0)
我终于找到了出路,但就像你说Charlie一样,它涉及创建ListBox:
我在博客上写了这个解决方案(包含源代码)on my blog。
答案 2 :(得分:0)
太糟糕了,在你完成所有工作之前,我没有注意到这个问题。很容易重新设计TreeView以这种方式出现:唯一需要的代码是一个非常简单的附加属性,“VisibleWhenCurrentOf”。
这样做的方法是:
样式TreeViewItem
要在ListBox
之外的ControlTemplate
中添加ItemsPresenter
。
使用“VisibleWhenCurrentOf”控制TreeViewItem
模板的可见性,以便给定项目仅在ItemsPresenter 内可见,如果它是ListBox中的当前项目。
重新定位细节
以下是相关模板的XAML:
<ControlTemplate TargetType="TreeView">
<DockPanel>
<ListBox
ItemsSource="{TemplateBinding ItemsSource}"
IsSyncrhonizedWithCurrentItem="true"
Style="{DynamicResource BoxesTreeViewBoxStyle}"
ItemTemplate="{Binding HeaderTemplate}"
ItemTemplateSelector="{Binding HeaderTemplateSelector}" />
<ItemsPresenter />
</DockPanel>
</ControlTemplate>
<ControlTemplate TargetType="TreeViewItem">
<DockPanel
local:VisibilityHelper.VisibleWhenCurrentOf="{Binding ItemsSource, RelativeSource={RelativeSource FindAncestor,HeaderedItemsControl,2}">
<ListBox
ItemsSource="{TemplateBinding ItemsSource}"
IsSyncrhonizedWithCurrentItem="true"
Style="{DynamicResource BoxesTreeViewBoxStyle}"
ItemTemplate="{Binding HeaderTemplate}"
ItemTemplateSelector="{Binding HeaderTemplateSelector}" />
<ItemsPresenter />
</DockPanel>
</ControlTemplate>
除了条件可见性之外,这两个模板是相同的。这样做的方式是树项前面的“+”变为ListBox
,除了ListBox
中选择的项目之外的所有项目都被隐藏。
您的BoxesTreeViewBoxStyle
应在ListBox
附近设置一个边距,以便它们正确放置。您可以通过在样式中添加ListBox
属性值来进一步简化此操作,但我发现在ControlTemplate
中设置它们更方便,因此我可以重新设置ListBox
而不必记住这些设置。
附加财产
以下是VisibleWhenCurrentOf
附加属性的代码:
public class VisibilityHelper : DependencyObject
{
// VisibleWhenCurrentOf
public static object GetVisibleWhenCurrentOf(DependencyObject obj) { return (object)obj.GetValue(VisibleWhenCurrentOfProperty); }
public static void SetVisibleWhenCurrentOf(DependencyObject obj, object value) { obj.SetValue(VisibleWhenCurrentOfProperty, value); }
public static readonly DependencyProperty VisibleWhenCurrentOfProperty = DependencyProperty.RegisterAttached("VisibleWhenCurrentOf", typeof(object), typeof(VisibilityHelper), new UIPropertyMetadata
{
PropertyChangedCallback = (sender, e) =>
{
var element = sender as FrameworkElement;
if(e.OldValue!=null)
{
var oldView = e.OldValue as ICollectionView ?? CollectionViewSource.GetDefaultView(e.OldValue);
oldView.CurrentChanged -= UpdateVisibilityBasedOnCurrentOf;
if(e.NewValue==null) element.DataContextChanged -= UpdateVisibilityBasedOnCurrentOf;
}
if(e.NewValue!=null)
{
var newView = e.NewValue as ICollectionView ?? CollectionViewSource.GetDefaultView(e.OldValue);
newView.CurrentChanged += UpdateVisibilityBasedOnCurrentOf;
if(e.OldValue==null) element.DataContextChanged += UpdateVisibilityBasedOnCurrentOf;
}
UpdateVisibilityBasedOnCurrentOf(sender);
}
});
static void UpdateVisibilityBasedOnCurrentOf(object sender, DependencyPropertyChangedEventArgs e) { UpdateVisibilityBasedOnCurrentOf(sender); }
static void UpdateVisibilityBasedOnCurrentOf(object sender, EventArgs e) { UpdateVisibilityBasedOnCurrentOf(sender); }
static void UpdateVisibilityBasedOnCurrentOf(object sender)
{
var element = sender as FrameworkElement;
var source = GetVisibleWhenCurrentOf(element);
var view = source==null ? null : source as ICollectionView ?? CollectionViewSource.GetDefaultView(source);
var visible = view==null || view.CurrentItem == element.DataContext;
element.Visibility = visible ? Visibility.Visible : Visibility.Collapsed;
}
}
此处没有任何复杂内容:任何时候DataContext
或视图的Current
更改,都会重新计算可见性。 PropertyChangedCallback
只是设置事件处理程序来检测这些条件,UpdateVisibiltyBasedOnCurrentOf处理程序重新计算可见性。
此解决方案的优势
由于此解决方案是真正的TreeView:
HierarchicalDataTemplate
的所有功能,包括HeaderTemplate
和HeaderTemplateSelector
ItemsSource
绑定,而不是每个需要“儿童”级别的集合