【问题标题】:Transforming a TreeView to Multiple ListBoxes将 TreeView 转换为多个 ListBox
【发布时间】:2014-04-07 09:12:38
【问题描述】:

给定表格的分层数据结构:

public class MyData
{
    public string Description { get; set; }
    public IEnumerable<MyData> SubNodes { get; set; } 
}

我想显示一系列表示该结构的 ListBox。流程应该是左 --> 右(例如,像 OS X 的 Finder),其中最左边的 ListBox 包含根节点和最右边的子节点。

每个 ListBox 中的多个项目应该是可选择的,从而导致后续 ListBox 中的可用项目更新。这对于一些 LINQ 和硬编码数量的 ListBox 来说是微不足道的,但是我希望模板是动态的(即,应该根据项目的可用性添加和删除 ListBox)。我还希望该解决方案与 MVVM 兼容。

这种类型的控件可能已经捆绑在 WPF 中,但是我不确定要搜索什么!任何指针将不胜感激。

【问题讨论】:

    标签: c# wpf mvvm listbox treeview


    【解决方案1】:

    首先,您不需要使用 LINQ(或任何 C# 代码!)在下一个 ListBox 上设置 ItemSource。您可以为此使用 WPF 数据绑定:

        <ListBox x:Name="listbox1" ItemsSource="{Binding Path=YourDataCollection}"/>
        <ListBox x:Name="listbox2" ItemsSource="{Binding ElementName=listbox1, Path=SelectedItem.SubNodes}" />
        <ListBox x:Name="listbox3" ItemsSource="{Binding ElementName=listbox2, Path=SelectedItem.SubNodes}" />
    

    基本上,您将下一个列表框绑定到前一个列表框的 SelectedItem 的子节点(您可能应该确保列表框一次只能选择一个)

    现在要隐藏没有任何项目的列表框,您可以使用 IValueConverter 将对象转换为可见性状态。为此,请创建一个类:

    public class ObjectToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value != null)
                return Visibility.Visible;
            else
                return Visibility.Collapsed;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    并为您的列表框添加更多数据绑定:

    <Window.Resources>
        <local:ObjectToVisibilityConverter x:Key="objectToVisible" />
    </Window.Resources>
    <Grid>
        <ListBox x:Name="listbox1" ItemsSource="{Binding ElementName=mw1, Path=dataCollection}"/>
        <ListBox x:Name="listbox2" ItemsSource="{Binding ElementName=listbox1, Path=SelectedItem.SubNodes}" 
        Visibility="{Binding ElementName=listbox2, Path=ItemsSource, Converter={StaticResource objectToVisible}}" />
        <ListBox x:Name="listbox3" ItemsSource="{Binding ElementName=listbox2, Path=SelectedItem.SubNodes}" 
        Visibility="{Binding ElementName=listbox3, Path=ItemsSource, Converter={StaticResource objectToVisible}}" />
    </Grid>
    

    确保将你的命名空间添加到窗口中,这样实际上可以找到 valueconverter,在我的例子中,我添加了这个:

    xmlns:local="clr-namespace:WpfApplication1"
    

    现在这个解决方案只适用于固定数量的列表框,但它不依赖于任何 C# 代码,除了 valueconverter。你真的不知道你可能需要多少个子级别吗?例如,您可以使用此技术将数十个列表框添加到滚动视图。 为了实际上,在UserControl中使这种动态可能会变得非常痛苦,因为在选择不同的根节点时,将在添加列表框中涉及的大量代码涉及添加列表框,请在选中不同的根节点时设置。

    另一种可能性可能是为 TreeView 创建 HierarchicalDataTemplate 以自定义 treeview 的外观。这具有保留树视图的优点,因为它是分层数据最有用的控件,但是使用 WPF 及其模板应该完全可以更改它的外观。不过,您可能需要更改树视图的 controltemplate(我建议使用 Blend 来编辑任何类型的 WPF 模板)

    【讨论】:

    • 很遗憾我不知道会有多少个子级别。我正在从 SQL Server 数据库中的自引用表中获取关系。正如您所说,固定数量的子级别是完全可行的。推广到 n 是一个棘手的问题!
    • 另外,我需要使用 LINQ 来支持多选功能(到 .Concat() 所选项目的子节点)
    • 从您的问题来看,尚不清楚您是否在选择时从数据库中获取子节点。您可以首先创建一个具有 StackPanel(水平方向)的 UserControl,给它一个 x:Name,然后您可以从代码中引用它。因此,您在代码中创建了一个新的 ListBox 对象,通过执行 myStackPanel.Children.Add(myListBoxObject) 将其添加到堆栈面板 如果您保留对您在集合中创建的所有 ListBox 对象的引用,您以后可以随时从堆栈面板中删除它们
    猜你喜欢
    • 2011-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多