具有命名空间的XML数据绑定

5

我希望使用数据绑定来填充一个简单的表单,显示有关一组人员的详细信息。目前,我已经将其全部设置好并运行如下:

<Window x:Class="DataBindingSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1">
<Window.Resources>
    <XmlDataProvider x:Key="xmlProvider" XPath="People" Source="c:\someuri.xml"/>
</Window.Resources>
<Grid>        
    <ListBox Name="personList" ItemsSource="{Binding Source={StaticResource xmlProvider}, XPath=Person}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding XPath=Name}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

    <GroupBox Header="GroupBox" Name="groupBox1" DataContext="{Binding ElementName=personList, Path=SelectedItem}">
        <Grid>
            <TextBox Name="nameText" Text="{Binding XPath=Name}"/>
            <ComboBox Name="genderCombo" Text="{Binding XPath=Gender}">
                <ComboBoxItem>Male</ComboBoxItem>
                <ComboBoxItem>Female</ComboBoxItem>
            </ComboBox>
        </Grid>
    </GroupBox>
</Grid>
</Window>

现在它很好地工作了!如果我提供的XML与提供的路径相匹配,当我单击时,列表框中会显示名称和性别。问题出现在当我开始尝试在我的XML源中使用命名空间时。然后XAML看起来像这样:

<Window x:Class="DataBindingSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1">
<Window.Resources>
    <XmlNamespaceMappingCollection x:Key="namespaceMappings">
        <XmlNamespaceMapping Uri="http://www.mynamespace.com" Prefix="mns"/>
    </XmlNamespaceMappingCollection>
    <XmlDataProvider x:Key="xmlProvider" XmlNamespaceManager="{StaticResource namespaceMappings}" XPath="mns:People" Source="c:\someuriwithnamespaces.xml"/>
</Window.Resources>
<Grid>        
    <ListBox Name="personList" ItemsSource="{Binding Source={StaticResource xmlProvider}, XPath=mns:Person}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding XPath=mns:Name}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

    <GroupBox Header="GroupBox" Name="groupBox1" DataContext="{Binding ElementName=personList, Path=SelectedItem}">
        <Grid>
            <TextBox Name="nameText" Text="{Binding XPath=mns:Name}"/>
            <ComboBox Name="genderCombo" Text="{Binding XPath=mns:Gender}">
                <ComboBoxItem>Male</ComboBoxItem>
                <ComboBoxItem>Female</ComboBoxItem>
            </ComboBox>
        </Grid>
    </GroupBox>
</Grid>
</Window>

使用这段代码(当然还需要适当命名空间的xml),ListBox仍然正确显示名称,但是点击这些名称不再更新名称和性别字段!我怀疑某种方式xml命名空间对GroupBox的DataContext产生了不良反应,但我不确定为什么或如何解决。有人知道如何在这种情况下使用XML命名空间吗?

2个回答

3

我也在MSDN WPF论坛上提出了这个问题。Marco Zhou回答了我,这最终是我想要的答案。我在这里为寻找相同答案的任何人复制了它:

This works:

    <XmlDataProvider x:Key="dataProvider"
                     XmlNamespaceManager="{StaticResource namespaceMappings}"
                     XPath="p:players/p:player">
        <x:XData>
            <p:players xmlns:p="http://www.footballism.com/2005/SoccerPlayers">
                <p:player>
                    <p:fullName>Sebastian Batistuta</p:fullName>
                    <p:age>26</p:age>
                </p:player>
                <p:player>
                    <p:fullName>Andriey Shevchenko</p:fullName>
                    <p:age>30</p:age>
                </p:player>
                <p:player>
                    <p:fullName>Paviel Nedved</p:fullName>
                    <p:age>21</p:age>
                </p:player>
                <p:player>
                    <p:fullName>David Beckham</p:fullName>
                    <p:age>19</p:age>
                </p:player>
            </p:players>
        </x:XData>
    </XmlDataProvider>
</Page.Resources>
<StackPanel>
    <TextBlock
        Text="{Binding XPath=p:fullName}"
        FontWeight="Bold"
        Binding.XmlNamespaceManager="{StaticResource namespaceMappings}"
        DataContext="{Binding ElementName=listBox, Path=SelectedItem}"/>
    <ListBox ItemsSource="{Binding Source={StaticResource dataProvider}}"
             x:Name="listBox"
             DisplayMemberPath="p:fullName">
    </ListBox>
</StackPanel> </Page>

I suppose after looking at the code, you should be able to understand why it works after specify the Binding.XmlNamespaceManager attached property for TextBlock.

ListBox is data bound to a data provider which has xml namespace mapping information, but the binding on the TextBlock doesn't have this information, that's why it fails.

Actually, when doing master detail data binding, it's more appropriate to do something like the following:

    <XmlDataProvider x:Key="dataProvider"
                     XmlNamespaceManager="{StaticResource namespaceMappings}"
                     XPath="p:players/p:player">
        <x:XData>
            <p:players xmlns:p="http://www.footballism.com/2005/SoccerPlayers">
                <p:player>
                    <p:fullName>Sebastian Batistuta</p:fullName>
                    <p:age>26</p:age>
                </p:player>
                <p:player>
                    <p:fullName>Andriey Shevchenko</p:fullName>
                    <p:age>30</p:age>
                </p:player>
                <p:player>
                    <p:fullName>Paviel Nedved</p:fullName>
                    <p:age>21</p:age>
                </p:player>
                <p:player>
                    <p:fullName>David Beckham</p:fullName>
                    <p:age>19</p:age>
                </p:player>
            </p:players>
        </x:XData>
    </XmlDataProvider>
</Page.Resources>
<StackPanel DataContext="{Binding Source={StaticResource dataProvider}}">
    <TextBlock
        Text="{Binding XPath=p:fullName}"
        FontWeight="Bold"/>
    <ListBox ItemsSource="{Binding}"
             x:Name="listBox"
             DisplayMemberPath="p:fullName"
             IsSynchronizedWithCurrentItem="True">
    </ListBox>
</StackPanel> </Page>

Hope this clears things up a little bit.


2
你可以像这样在XPath查询中使用本地名称:
 <TextBox Name="nameText">
    <TextBox.Text>
       <Binding XPath="*[local-name()='Name']" />
    </TextBox.Text>
 </TextBox>

好的,这个可以运行,但在我打上“已回答”的标记之前,我想更多地了解一些原因。我对数据绑定还比较新,所以对于一些更高级的语法不太熟悉。这里的local-name()到底是做什么的? - Toji
local-name() 是一种 XPath 函数,它允许您仅使用元素的本地名称而不是完整名称(命名空间 + 本地名称)来选择 XML 元素。 - aogan
啊,谢谢!现在我明白了。这是可行的解决方案,但我仍然很想知道为什么我失去了在这个级别上使用命名空间查询的能力。不过还是感谢你的帮助! - Toji
非常抱歉,尽管您的回答很有帮助,但我在另一个论坛上得到了更全面的答案。我在这里复制了它,并且为了社区参考的目的,将其标记为被接受的答案。仍然感谢您的帮助,如果我能给您的答案评分更高,我一定会这样做! - Toji

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接