我构建了一个代码,该代码从在线数据库中获取数据,并通过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);
答案 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
),这样您就可以直接添加所需内容。
点击结果:
希望有所帮助。
为了分离根节点(即国家)和子节点(即系列节点),我建议这样的事情:
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
不为空。你确定你是这样做的吗?