WPF_拖拽任意XML结构生成TreeView
- 使用 HierarchicalDataTemplate、DataTrigger、MultiBinding 和 Converter 。
- 数据源为拖拽的任意具有 XML 标准结构(如HTML、XAML和MXML)的文件或字符串文本。
- 通过 CheckBox 选择显示 XmlElement 的 Name 或 Attributes。
示例
- 新建一 TreeView ,为了能拖拽及处理拖拽动作,需要在 TreeView 中添加代码:
AllowDrop="True" PreviewDragOver="treeView_PreviewDragOver" PreviewDrop="treeView_PreviewDrop
- 允许拖拽的数据对象中的数据存储格式应该为文本数据或文件放置格式,所以 PreviewDragOver 时判断:
if (e.Data.GetDataPresent(DataFormats.Text, false) || e.Data.GetDataPresent(DataFormats.FileDrop, false))
并设置当前相应拖放效果的:
e.Effects = DragDropEffects.Copy; 或:
e.Effects = DragDropEffects.None;
-
因为在 XAML 中绑定 XML :
<XmlDataProvider x:Key="xmlDataProvider"> <x:XData>
同理, C# 参照着,以便绑定到合适的数据源格式:
XmlDataProvider xmlDataProvider = new XmlDataProvider();
- 根据不同数据格式处理数据:
if (e.Data.GetDataPresent(DataFormats.Text, false)) { string text = e.Data.GetData(DataFormats.Text, false).ToString(); XmlDocument xd = new XmlDocument(); xd.LoadXml(text); xmlDataProvider.Document = xd; } else if (e.Data.GetDataPresent(DataFormats.FileDrop, false)) { string fileName = (e.Data.GetData(DataFormats.FileDrop, false) as string[]).FirstOrDefault(); xmlDataProvider.Source = new Uri(fileName); }
- 最后别忘记:
treeview.DataContext = xmlDataProvider;
注意,这相应于在 XAML 中设置 DataContext 属性,但 XAML 中仍然需要设置 ItemsSource 属性:ItemsSource="{Binding}" <!--若没 ItemsSource="{Binding XPath=*}" 则原 XML 外少包一层,导致无法显示最外层的非 Element 节点-->
-
接下来开始设计 TreeView 外观:
<HierarchicalDataTemplate x:Key="ItemTemplate" ItemsSource="{Binding}"> <!--ItemsSource="{Binding}"才能显示子节点数据--> <StackPanel Orientation="Horizontal"> <CheckBox x:Name="checkBox" Opacity="0"> </CheckBox> <TextBlock x:Name="text" Text="?" /> </StackPanel> </HierarchicalDataTemplate>
CheckBox 将处理 XmlElement 相关显示。
- 处理 NodeType 为 Element 比较复杂,需要多重绑定和
<HierarchicalDataTemplate.Triggers> <DataTrigger Binding="{Binding NodeType}" Value="Element"> <Setter TargetName="text" Property="Text"> <Setter.Value> <MultiBinding Converter="{StaticResource textConverter}"> <Binding></Binding> <Binding ElementName="checkBox" Path="IsChecked"></Binding> </MultiBinding > </Setter.Value> </Setter> <Setter TargetName="checkBox" Property="Opacity" Value="1"> </Setter> </DataTrigger> </HierarchicalDataTemplate.Triggers>
-
上面的<Binding></Binding>为了在转换中获取 Element:
XmlElement element = values[0] as XmlElement;
所以可以对 element 对象作处理,如属性:foreach (XmlAttribute e in element.Attributes)
-
注意操作转换要在 XAML 中增加:
xmlns:local="clr-namespace:WPF_XML_AnyStyle"
<local:TextConverter x:Key="textConverter"></local:TextConverter> -
如果 checkBox 选中则只是:
return element.Name;
没选可以返回如属性等的值。(详见代码) -
为了能显示其他类型的 XML 节点:
<DataTrigger Binding="{Binding NodeType}" Value="Element">
这里的 ="Element" 可以换成如 "Comment" 等的 XmlNodeType 枚举类型。 -
请点击下载示例(内含一个示例的XML文件)。
想想:- XML中不能出现任何中文字符,结构也必须正确,否则将无法生成 TreeView。
- 没有用延迟加载技术(XML文件直接在内存中),但点击打开节点才延迟加载显示内容。(调试 textConverter 可知)
- 若拖拽多个文件,只处理“第一个”。(见FirstOrDefault())(与点击的顺序无关,真怪异!)
- 本文只处理了常用的节点类型。如果要处理 XML 的其他 XmlNodeType 的节点类型(如 <!DOCTYPE...>,类型为 DocumentType),可以在 VS 中设断点调试,在“快速监视”窗口中查看获得的 Document(或 Element)的相关父子属性,然后再添加相应的 DataTrigger ,设置其 Value="......"。如果对象复杂可参照 MultiBinding 用转换返回所需要显示的数据。
- 欢迎意见或建议!