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
不为空。你确定你是按照同样的方式做的吗?
我构建了一个代码,从在线数据库中获取数据并通过 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
不为空。你确定你是按照同样的方式做的吗?