逻辑父类TreeView动态错误的异常

时间:2015-08-28 07:58:17

标签: c# wpf treeview

我构建了一个代码,该代码从在线数据库中获取数据,并通过TreeView中的while循环递归添加它们。当用户在树中选择一个新国家时,基本上会调用Add函数,例如,这是TreeView(可用国家/地区)中包含的内容:

<TreeView Name="nation_team" SelectedItemChanged="nation_team_SelectionChanged">
    <TreeViewItem Header="Italy"/>
    <TreeViewItem Header="Germany"/>    
</TreeView>

当用户选择例如意大利时,则运动中设置以下功能:

private void nation_team_SelectionChanged(object sender, RoutedPropertyChangedEventArgs<Object> e)
{
     soccerSeason.getChampionshipsForTeams();
}

以下函数包含以下内容:

string stm = @" SELECT * FROM league 
                            WHERE country = '" + MainWindow.AppWindow.nation_team.SelectedValue.ToString() + "'";

MySqlCommand cmd = new MySqlCommand(stm, database.Connection);
MySqlDataReader rdr = cmd.ExecuteReader();
TreeViewItem rootNode = new TreeViewItem() { Header = MainWindow.AppWindow.nation_team.SelectedValue.ToString() };

while (rdr.Read())
{
      rootNode.Items.Add(getTreeViewChampionships(rdr.GetString(3)));
      MainWindow.AppWindow.nation_team.Items.Add(rootNode);
}

rdr.Close();

正如你所看到的,我运行一个查询来下载所选国家的所有锦标赛,这正是TreeView(意大利或德国)的价值。 现在我运行查询并执行阅读器“RDR”。 然后我声明一个对应于用户选择的国家的rootNode,在这个国家你必须添加从Query返回的锦标赛,如果用户选择“意大利”,我在TreeView中等待这个结果结构:

Italy
   Serie A //this two values was returned by query
   Serie B

到目前为止,没有问题查询成功并且读取了值。 此时它在循环遍历所有值时被激活,在while循环中我们找到了这个方法:

rootNode.Items.Add(getTreeViewChampionships(rdr.GetString(3)));

将意大利加入“甲级联赛和乙级联赛”。方法getTreeViewChampionships,该方法接收他们正在阅读“RDR”的锦标赛作为参数,特别是“A系列”和“B系列”。

private TreeViewItem getTreeViewChampionships(string campionato)
{
      TreeViewItem item = new TreeViewItem() { Header = campionato };
      return item;
}

似乎应该没有任何问题,但是每当我选择一个国家时,在这一行上都会出现以下错误:

MainWindow.AppWindow.nation_team.Items.Add(rootNode);
  

System.InvalidOperationException:对于该项已存在逻辑父元素。您必须先将其与旧父级取消关联,然后才能绑定到新父级。   在MS.Internal.Controls.InnerItemCollectionView.AssertPristineModelChild(对象项)中   在MS.Internal.Controls.InnerItemCollectionView.Add(Object item)中   在System.Windows.Controls.ItemCollection.Add(Object newItem)

我做错了什么?

注意:XAML中提供的国家只是一个例子,我在代码后面添加了国家,就像这样:

TreeViewItem rootNode = new TreeViewItem() { Header = rdr.GetStringOrNull(0) };
MainWindow.AppWindow.nation_team.Items.Add(rootNode);

1 个答案:

答案 0 :(得分:1)

第一个答案

我设法用最小的代码重现你的问题:

private void nation_team_SelectionChanged(object sender, RoutedPropertyChangedEventArgs<Object> e)
{
    TreeViewItem rootNode = new TreeViewItem() { Header = nation_team.SelectedValue.ToString() };
    for (int i = 0; i < 3; ++i)
    {
        rootNode.Items.Add(new TreeViewItem() { Header = "some data" });
        nation_team.Items.Add(rootNode);
    }
}

这是解决问题的方法:

private void nation_team_SelectionChanged(object sender, RoutedPropertyChangedEventArgs<Object> e)
{
    TreeViewItem rootNode = (TreeViewItem)e.NewValue;
    for (int i = 0; i < 3; ++i)
    {
        rootNode.Items.Add(new TreeViewItem() { Header = "some data" });
    }
}

在该代码中,您不会创建与所选项目具有相同标题的新TreeViewItem。您只需获得实际选择的项目(即e.NewValue),这样您就可以直接添加所需内容。

点击结果:

enter image description here

希望有所帮助。

回答评论

为了分离根节点(即国家)和子节点(即系列节点),我建议这样的事情:

TreeViewItem rootNode = (TreeViewItem)e.NewValue;
if (rootNode.Parent is TreeView)
{
    //Country
}
else
{
    //Serie
}

如果父类型为TreeView,则该节点是根节点,您可以从数据库中获取数据。如果没有,你就在一个子节点上,你可以做其他事情。

上下文更改后编辑

我无法重现您的问题。我在XAML代码中使用了空TreeView,然后是代码隐藏:

public MainWindow()
{
    InitializeComponent();
    var rootNode1 = new TreeViewItem() { Header = "Italy" };
    var rootNode2 = new TreeViewItem() { Header = "Germany" };
    nation_team.Items.Add(rootNode1);
    nation_team.Items.Add(rootNode2);
}

private void nation_team_SelectionChanged(object sender, RoutedPropertyChangedEventArgs<Object> e)
{
    TreeViewItem rootNode = (TreeViewItem)e.NewValue;
    for (int i = 0; i < 3; ++i)
    {
        rootNode.Items.Add(new TreeViewItem() { Header = "some data" });
    }
}

所有工作都是例外。 e.NewValue不为空。你确定你是这样做的吗?