我花了很多时间试图弄清楚如何将我的XML文件中的数据绑定到TreeView控件,但我不知道从哪里开始。我甚至尝试在codeproject上查看Two-way binding of Xml data to the WPF TreeView和Josh Smith的代码示例,但仍然无法理解如何开始!!!
我在文件“C:\ SPDependencies.xml”中有XML(如果需要,我可以更改格式)!!!:
<node type="SPDependencies" Name="SPDependencies">
<node type="StoredProc" Name="SP1">
<node type="OperationType" Name="Type1">
<node type="TableName" Name="Table1"/>
<node type="TableName" Name="Table2"/>
</node>
<node type="OperationType" Name="Type2">
<node type="TableName" Name="Table1"/>
<node type="TableName" Name="Table2"/>
</node>
.....
</node>
<node type="StoredProc" Name="SP2">
<node type="OperationType" Name="Type1">
...
...
</node>
</node>
我需要以下列格式在Treeview控件中显示它:
<SP1>
<Type1>
<Table1>
<Table2>
<Table3>
<Type2>
<Table1>
<Table2>
<Table3>
<SP2>
<Type1>
........
谢谢, ABHI。
答案 0 :(得分:5)
给出以下xml文件:
<node type="SPDependencies" Name="SPDependencies">
<node type="StoredProc" Name="SP1">
<node type="OperationType" Name="Type1">
<node type="TableName" Name="Table1"/>
</node>
<node type="OperationType" Name="Type2">
<node type="TableName" Name="Table1"/>
</node>
</node>
<node type="StoredProc" Name="SP2">
<node type="OperationType" Name="Type1">
</node>
</node>
</node>
查看:强>
<Window x:Class="Tree.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Tree"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<Window.Resources>
<HierarchicalDataTemplate x:Key="template">
<TextBlock Text="{Binding XPath=@Name}" />
<HierarchicalDataTemplate.ItemsSource>
<Binding XPath="node" />
</HierarchicalDataTemplate.ItemsSource>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid DataContext="{Binding Path=XmlData}">
<TreeView ItemsSource="{Binding}" ItemTemplate="{StaticResource template}">
</TreeView>
</Grid>
</Window>
查看型号:
public class ViewModel
{
public XmlDataProvider XmlData { get; set; }
public ViewModel()
{
XmlData = new XmlDataProvider();
XmlData.Source = new Uri(@"C:\input.xml");
XmlData.XPath = "node";
}
}
<强>输出:强>
如果您只想在根目录下显示 节点,只需将XPath更改为:
XmlData.XPath = "/node/node";
答案 1 :(得分:3)
继承树:
<Window.Resources>
<HierarchicalDataTemplate DataType="node"
ItemsSource="{Binding XPath=node}">
<TextBox Width="Auto"
Text="{Binding XPath=@Name, UpdateSourceTrigger=PropertyChanged}" />
</HierarchicalDataTemplate>
<XmlDataProvider
x:Key="xmlDataProvider"
XPath="node" Source="C:\Data.XML">
</XmlDataProvider>
</Window.Resources>
<Grid>
<StackPanel>
<Button Click="Button_Click">Save</Button>
<TreeView
Width="Auto"
Height="Auto"
Name="treeview"
ItemsSource="{Binding Source={StaticResource xmlDataProvider}, XPath=.}"/>
</StackPanel>
</Grid>
我添加了一个简单的按钮来保存更改。所以对于你背后的代码中的Button_Click方法:
XmlDataProvider dataProvider = this.FindResource("xmlDataProvider") as XmlDataProvider;
dataProvider.Document.Save(dataProvider.Source.LocalPath);
有关数据绑定和WPF的文章,请参阅here。
答案 2 :(得分:1)
我已经找到了如何在不踩TreeView.DataContext
的情况下做到这一点。绑定很容易。 Codebehind几乎一样容易,但有一点点问题。
如果绑定XmlDataProvider
到ItemsSource
,则不会得到任何结果。它不是IEnumerable
(虽然它是INotifyPropertyChanged
)并且没有隐式转换。你想要的是XmlDataProvider.Data
,它被声明为Object
,但我看到了XmlDataCollection
的运行时类型(继承自ReadOnlyObservableCollection<XmlNode>
)。
绑定Data
很简单。我不知道将XmlDataProvider
放在你的视图模型中是不是纯粹的MVVM,也许不是。
视图模型:
public XmlDataProvider ViewModelXMLDataProp { ... }
XAML
<TreeView
ItemsSource="{Binding ViewModelXMLDataProp.Data}"
...
/>
完成 - 即,除非您需要使用XPath
的{{1}}属性。如果您这样做,则必须使用Binding
kludge。您无法在同一个绑定上同时设置DataContext
和Path
。
XPath
的XPath属性做同样的事情。如果你可以使用它,那你很好。
您认为XmlDataProvider
会起作用,因为当您的Binding.Source
是静态资源时,它会起作用。当XmlDataProvider
为Binding.Source
而DataSourceProvider
未指定时,Path
默认为Path
:
Data
...但是这样可行,因为你给它一个静态资源。以下实际上绑定到字符串<TreeView
ItemsSource="{Binding Source={StaticResource MyXmlDataProviderResource}}"
...
/>
,而不是通过该名称查找"ViewModelXMLDataProp"
属性。那不好。
DataContext
也许你可以写一个<TreeView
ItemsSource="{Binding Source=ViewModelXMLDataProp}"
...
/>
来做那个工作,但是没有必要。
你应该学习和使用MVVM,但事情发生的原因很多,你没有来这里讲道。
Codebehind有点棘手。 MarkupExtension
只需要您提供的对象必须实现TreeView.ItemsSource
,因此将System.Collections.IEnumerable
强制转换为provider.Data
并且不必担心确切的运行时类型。
现在这里是问题:System.Collections.IEnumerable
是异步填充的。
XmlDataProvider.Data
即使我创建protected void LoadXML(String path)
{
var provider =
new XmlDataProvider()
{
Source = new Uri(path, UriKind.Absolute),
XPath = "./*"
};
// FAIL: provider.Data is still null
treeView.ItemsSource = (IEnumerable)provider.Data;
}
,致电XmlDocument
并将文档分配给XmlDocument.Load()
,我发现这也是一个问题。当XmlDataProvider.Document
属性最终设置完成后,Binding
仍然会闲置,然后它会更新Data
。但是在代码隐藏文件中对ItemsSource
的赋值没有这样的事情。
与Stack Overflow中无处不在的民间信仰相反,在下面的代码中没有任何约束发生,并且在任何意义上都没有任何约束:
ItemsSource
如果没有人创建// NOT A BINDING
treeView.ItemsSource = someRandomCollectionOfStuff;
或System.Windows.Data.Binding
的实例,则不是绑定。这种区别很重要:“使用x:Bind
的当前值”与“每次x
提升y.x
”时“使用y
的未来值无限更新”概念不同。
您可以通过编程方式创建PropertyChanged
或甚至处理Binding
,但他们继续为您提供了一个更简单的选项。只需处理PropertyChanged
事件即可。
XmlDataProvider.DataChanged
就是这样。您甚至可以保留该提供程序,在其中加载新的XML,并使protected void LoadXML(String path)
{
var provider =
new XmlDataProvider()
{
Source = new Uri(path, UriKind.Absolute),
XPath = "./*"
};
provider.DataChanged += (s,e)
=> treeView.ItemsSource = (IEnumerable)provider.Data;
}
事件保持树视图最新。虽然看起来像是浪费精力。