Связывание данных XML с пространствами имен
Я хочу использовать привязку данных к документу XML, чтобы заполнить простую форму, которая показывает подробности о списке людей. У меня все настроено и работает так прямо сейчас:
<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 по-прежнему правильно отображает имена, но нажатие на эти имена больше не обновляет поля Name и Gender! Я подозреваю, что пространство имен xml каким-то образом отрицательно реагирует на DataContext группы, но я не уверен, почему и как. Кто-нибудь знает, как использовать пространства имен XML в этом контексте?
2 ответа
Вы можете использовать локальные имена в своих запросах XPath, например:
<TextBox Name="nameText">
<TextBox.Text>
<Binding XPath="*[local-name()='Name']" />
</TextBox.Text>
</TextBox>
Я также задавал этот вопрос в формах MSDN WPF. Марко Чжоу ответил мне этим, и в конечном итоге я искал ответ. Я воспроизвел это здесь для пользы любого, кто ищет тот же ответ:
Это работает:
<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>
Я полагаю, что после просмотра кода вы сможете понять, почему он работает, после того, как укажите вложенное свойство Binding.XmlNamespaceManager для TextBlock.
ListBox - это данные, привязанные к поставщику данных, который имеет информацию о сопоставлении пространства имен xml, но привязка к TextBlock не имеет этой информации, поэтому она терпит неудачу.
На самом деле, при связывании основных данных более уместно сделать что-то вроде следующего:
<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>
Надеюсь, это немного прояснит ситуацию.