一个XmlDataProvider WPF有多个XPath

本文关键字:XPath XmlDataProvider WPF 一个 | 更新日期: 2023-09-27 18:12:56

我有两个DataGrid和一个用于XML文件的XmlDataProvider。XML文件结构如下:

<Setting>
  <Element Name="..." Offset="..." ID="...">
    <Item Name="..." Type="..." Count="..." ID="..." />
    <Item Name="..." Type="..." Count="..." ID="..." />
    <Item Name="..." Type="..." Count="..." ID="..." />
    ...
  </Element>
  <Element Name="..." Offset="..." ID="...">
    <Item Name="..." Type="..." Count="..." ID="..." />
    <Item Name="..." Type="..." Count="..." ID="..." />
  </Element>
  ...
</Setting>

我需要使用相同的XmlDataProvider显示第一个DataGrid中所有元素的属性值,以及第二个DataGrid中所有项目的属性值。

XAML显示第一个DataGrid:中所有元素的属性值

...
<Grid.DataContext>
  <XmlDataProvider x:Name="xml_setting" XPath="/Setting/Element"/>
</Grid.DataContext>
<DataGrid ItemsSource="{Binding}">
  <DataGrid.Columns>
    <DataGridTextColumn Header="Name" Width="*" Binding="{Binding XPath=@Name}"/>
    <DataGridTextColumn Header="Offset" Width="80" Binding="{Binding XPath=@Offset}"/>
    <DataGridTextColumn Header="ID" Width="80" Binding="{Binding XPath=@ID}"/>
  </DataGrid.Columns>
</DataGrid>
...

我试着在"/Setting"中设置XmlDataProvider XPath值,在"/Element/@Name"、"/Element/_Offset"answers"/Element//@ID"中设置了Columns XPath值,但只显示第一个Element。

如何使用一个XmlDataProvider绑定到不同DataGrids的不同列以显示XML文件的不同节点的属性值?

一个XmlDataProvider WPF有多个XPath

问题是必须将XML根节点的默认名称空间设置为空字符串:

<Setting xmlns="">

否则,它将使用在窗口范围中分配的xmlns(当然是"http://schemas.microsoft.com/winfx/2006/xaml/presentation"(,并且元素的Path将不正确。

要填充第二个网格的数据,可以将ItemsSource绑定到第一个DataGridPath应该是SelectedItem,这正是XmlElement,也就是IEnumerable。因此,您可以使用XPath将每个Item元素的每个属性绑定到相应的DataGridTextColumn,如下所示:

<!-- the first Grid -->
<DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False" Name="grid1">
  <DataGrid.Columns>
    <DataGridTextColumn Header="Name" Width="*" Binding="{Binding XPath=@Name}"/>
    <DataGridTextColumn Header="Offset" Width="80" Binding="{Binding XPath=@Offset}"/>
    <DataGridTextColumn Header="ID" Width="80" Binding="{Binding XPath=@ID}"/>
  </DataGrid.Columns>
</DataGrid>
<!-- the second Grid -->
<DataGrid Grid.Column="1" ItemsSource="{Binding ElementName=grid1,Path=SelectedItem}"
          AutoGenerateColumns="False">
  <DataGrid.Columns>    
    <DataGridTextColumn Header="Name" Width="*" Binding="{Binding XPath=@Name}"/>
    <DataGridTextColumn Header="Type" Width="100" Binding="{Binding XPath=@Type}"/>
    <DataGridTextColumn Header="Count" Width="80" Binding="{Binding XPath=@Count}"/>
    <DataGridTextColumn Header="ID" Width="80" Binding="{Binding XPath=@ID}"/>      
  </DataGrid.Columns>
</DataGrid>

更新:第二个DataGrid的上述代码可以读取(显示(数据,但不支持修改。这是因为我们绑定数据的方式,实际上底层集合是ChildNodes,它实际上是一个XmlNodeList,这个集合只是实现了IEnumerable接口。因此它不支持编辑。底层集合应该实现IEditableCollectionView接口。通过更改绑定数据的方式,我们可以将基础集合设置为IEditableCollectionView。事实上,XPath查询数据的方式可以帮助我们获得IEditableCollectionView。因此,在这种情况下,我们尝试使用XPath来获取底层集合(而不是通过ChildNodes进行访问,后者可以通过类型为XmlElementSelectedItem隐式枚举(:

<DataGrid Grid.Column="1" 
          DataContext="{Binding ElementName=grid1,Path=SelectedItem}"
          ItemsSource="{Binding XPath=Item}"
          AutoGenerateColumns="False">
    <!-- .... -->
</DataGrid>

现在它就像一个符咒(经过测试(。

更新:要按名称筛选元素,必须使用属性元素语法(而不是属性语法(,如下所示:

<DataGrid Grid.Column="1" AutoGenerateColumns="False">
    <DataGrid.ItemsSource>
        <Binding XPath="Setting/Element[@Name='SomeName']"/>
    </DataGrid.ItemsSource>
    <!-- ...... -->
</DataGrid>

注意,上面的代码只是如何指定XPath的一个示例,实际表达式取决于隐含的Source