65.9K
CodeProject 正在变化。 阅读更多。
Home

在树形视图中显示自引用分层数据

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (10投票s)

2012年9月12日

CPOL

4分钟阅读

viewsIcon

52476

downloadIcon

1948

如何在 TreeView 中显示自引用分层数据库表。

treeview showing data

引言

这是我一直想写一篇小文章的东西。 我终于找到了必要的时间/精力,敲击键盘,让自己看起来有点博学,因此我带来了

“WPF – 表格自引用父子绑定 TreeView 的巧妙之处”

或者 – 如何让 TreeView 正确显示行具有父子关系的自引用表。

背景

有时你需要在数据库表中描述分层信息,其中条目引用其他条目作为父条目,有时你想在 TreeView 控件中显示数据。 本文向您展示如何在 WPF 中以非常简单的方式做到这一点。

请注意,为了保持代码的简单性,我没有添加异常处理、错误捕获等。

我们的数据

首先,让我们拥有我们的数据。

如你所见,我为一家假想的公司创建了一个虚假的组织结构。 每个元素都有一个 ID。 它也可能(或可能不)有一个父元素。 该父元素由 parent_element_id 标识(即父元素的 ID)。 应该很明显我们在描述一个汇报结构。 例如,我们可以看到,茶水工 Chris 向卑微的 Maunder 程序员汇报,而 Maunder 程序员又向经理 3 汇报。

太棒了,这看起来很像一棵树,我可以告诉你你很兴奋。 除非你是个茶水工。

现在是 XAML 时间

启动你信任的 Visual Studio – 我正在使用 Visual Studio 2010。打开随本文一起提供的 WPF 解决方案的下载 – 我称它为 WpfTreeviewStuff,因为我没有特别的想象力。

现在,看看 MainWindow.xaml 文件。

包含嵌入式 TreeView 的窗口的 XAML 如下;

WTF? WPF

XAML 告诉 WPF 我们有一个 TreeView,它将绑定(附加)一些数据。 这一段

ItemsSource="{Binding}"

创建一个默认绑定对象供以后使用。

换句话说 - TreeView 显示的项目列表(即 itemsource)将在未来某个时候连接到 TreeView。

分层数据显示

这部分下一个有趣的部分不仅仅是漂亮的颜色,还有 HierarchicalDataTemplate 标签。 通常,对于 TreeView,我们想要显示具有某种逻辑层次结构的数据集合。 为了在 XAML 中做到这一点,我们使用 HierarchicalDataTemplate 标签。

在我们的例子中,数据集合由 "rsParentChild" 描述 – 在这种情况下(您将看到)它是一个数据关系对象。 TreeView 可以使用绑定到名为 rsParentChild 的对象的数据来填充自身。

要显示的内容

我们想要显示的实际文本项称为 element_name,是的,它与数据库中的列名称相同。 TextBlock 标签告诉 TreeView 实际在屏幕上显示什么,即 TextBlock。 你可以从中获得很多乐趣,因为你可以随心所欲地做任何事情。

代码时间

好吧,如果你对 WPF 还不太熟悉,那么这些都没什么意义,但也可能有一些意义。 现在,转到代码隐藏(为了保持简单,今天我们是一个无 MVVM 区)。

在构造函数中,您将看到以下内容

public partial class MainWindow : Window
{
    string connString = @"Data Source=.\SQLEXPRESS;AttachDbFilename={0}\" + 
           @"treeviewdata.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True";
    SqlConnection conn = new SqlConnection();

    public MainWindow()
    {
        InitializeComponent();

        //get the folder where i put the mdf file.
        string baseDir = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        string whereTheWildFileLives = Directory.GetParent(baseDir).ToString() ;
                
        whereTheWildFileLives = Directory.GetParent(whereTheWildFileLives).ToString();
    
        //build out connection string
        connString = string.Format(connString, whereTheWildFileLives);

        conn.ConnectionString = connString;
        conn.Open();
        // select the data from our table and fill our dataset                                       
        String sql = "select element_name,element_id,parent_element_id from sexytimetable";
        DataSet myGroovySet = new DataSet();
    
        SqlDataAdapter adpt = new SqlDataAdapter(sql, conn);
        adpt.Fill(myGroovySet);

        myGroovySet.Relations.Add("rsParentChild",
                    myGroovySet.Tables[0].Columns["element_id"],
                    myGroovySet.Tables[0].Columns["parent_element_id"]);
                
        //get the default view and then filter based on the parent element id being null
        DataView vw = myGroovySet.Tables[0].DefaultView;
        vw.RowFilter = "parent_element_id IS NULL"; //try commenting me out later
        treeView1.DataContext = vw;
        conn.Close();
    }
}

第一个有趣的代码片段如下

String sql = "select element_name, element_id, parent_element_id from sexytimetable";
DataSet myGroovySet = new DataSet();
            
SqlDataAdapter adpt = new SqlDataAdapter(sql, conn);
adpt.Fill(myGroovySet);

现在我们可以聪明一点并创建一个实体模型,但本文不是关于这种技术的。 而且我花了很多时间来设置我的 Visual Studio,以便使用大型 Oracle 数据库的实体模型。 所以我不喜欢它们(与 Oracle 数据库一起使用),为了简单起见,我坚持使用你看到的代码。

下一段代码是发生有趣事情的地方

myGroovySet.Relations.Add("rsParentChild",
            myGroovySet.Tables[0].Columns["element_id"],
            myGroovySet.Tables[0].Columns["parent_element_id"]);

该代码显示正在创建一个关系(称为 "rsParentChild")并将其添加到数据集中,该关系位于两列 element_id 和 parent_element_id 之间。 这种关系将显示在 TreeView 中。

在显示数据之前,我们需要过滤数据集以首先关注“最顶层”的元素,即没有任何父元素的元素。 我们可以通过创建一个 dataview 对象并根据具有空 parent_element_id 的行进行过滤来实现。

DataView vw = myGroovySet.Tables[0].DefaultView;
vw.RowFilter = "parent_element_id IS NULL";
treeView1.DataContext = vw;

当我们运行代码时,我们会得到一个组织良好的 TreeView,看起来像,我们可以看到“员工”正在正确地向他们的“经理”汇报。

happy treeview

展开所有节点后,它看起来像以下内容(是的,即使是茶水工 Chris 也在正确汇报)

happier treeview

那么,如果我们不添加行过滤器 "parent_element_id IS NULL" 会发生什么?

这就是发生的事情,这不是我们想要的(原因很明显)

unhappyrelations

差不多就是这样了,我们像喝了一品脱的 Maunder 一样结束了。 感谢你的阅读,我希望你喜欢这个节目。

其他参考

最后但同样重要的是,非常酷的 Josh Smith

© . All rights reserved.