TreeView 动态错误的逻辑父异常

Logic parent Exception for TreeView dynamic error

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

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

当用户 select 以意大利为例时,将启动以下功能:

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();

如您所见,我 运行 查询下载了国家 select 的所有锦标赛,这正是从 TreeView(意大利或德国)获取的值。 现在我 运行 查询并执行 reader "RDR"。 然后我声明一个rootNode对应于用户select的国家,在这个国家你必须添加从查询返回的冠军,如果用户select "Italy",我是在 TreeView 中等待此结果结构:

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

到目前为止没有问题查询成功并读取值。 此时激活while循环,循环遍历所有的值,在while循环里面我们发现这个方法:

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

这会将 "Serie A and Serie B" 添加到意大利。该方法 getTreeViewChampionships,该方法接收他们正在阅读的锦标赛作为参数 "RDR",特别是 "Series A" 和 "Series B".

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

似乎应该没有问题,但每当我 select 一个国家返回此行时出现以下错误:

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

System.InvalidOperationException: For the item already exists a logical parent element. You must disassociate it from the old parent before it can bind to a new parent.     in MS.Internal.Controls.InnerItemCollectionView.AssertPristineModelChild (Object item)     in MS.Internal.Controls.InnerItemCollectionView.Add (Object item)     in System.Windows.Controls.ItemCollection.Add (Object newItem)

我做错了什么?

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

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

第一个回答

我设法用最少的代码重现了您的问题:

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" });
    }
}

在该代码中,您不会创建与所选项目具有相同 header 的新 TreeViewItem。你只是得到实际选择的项目(即e.NewValue)所以你可以直接添加你想要的。

点击结果:

希望对您有所帮助。


回复评论

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

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

如果parent类型是TreeView,那么节点就是根节点,可以从数据库中获取数据。如果没有,你在一个 child 节点上,你可以做其他事情。


上下文更改后编辑

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

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 不为空。你确定你是按照同样的方式做的吗?