none
XML Data binding with Namespaces and the Master-Detail Pattern

    Question



  • I want to use data binding with an XML document to populate a simple form that shows details about a list of people. I've got it all set up and working like so right now:

    <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>

    (All position/layout elements have been removed for clarity)

    Now this works great! If I provide it with some XML that matches the paths provided I get a list of names in the listbox that show both the name and gender in the appropriate fields when clicked. The problem comes when I start to try and use namespaces in my XML source. The XAML then changes to look like this:

    <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>

    With this code (and the appropriately namespaced xml, of course) the Listbox still displays the names properly, but clicking on those names no longer updates the Name and Gender fields! My suspicion is that somehow the xml namespace is reacting adversely to the groupbox's DataContext, but I'm not sure why or how. I have had someone on another form suggest that I use the following to access the fields:

    <TextBox Name="nameText">
        <TextBox.Text>
           <Binding XPath="*[local-name()='Name']" />
        </TextBox.Text>
     </TextBox>

    And this actually works, but it does not help explain why I suddenly lose the ability to query the nodes normally. Not to mention, this doesn't allow much control if multiple namespaces are in use and interwoven. Does anyone know how to use XML namespaces in this context?

    Friday, October 10, 2008 9:21 PM

Answers

  • This works:

    <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Page.Resources>
            <XmlNamespaceMappingCollection x:Key="namespaceMappings">
                <XmlNamespaceMapping Uri="http://www.footballism.com/2005/SoccerPlayers" Prefix="p"/>
            </XmlNamespaceMappingCollection>
           
            <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:

    <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Page.Resources>
            <XmlNamespaceMappingCollection x:Key="namespaceMappings">
                <XmlNamespaceMapping Uri="http://www.footballism.com/2005/SoccerPlayers" Prefix="p"/>
            </XmlNamespaceMappingCollection>
           
            <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.
    • Marked as answer by Tojiro Wednesday, October 15, 2008 3:56 AM
    • Marked as answer by Tojiro Wednesday, October 15, 2008 3:56 AM
    • Marked as answer by Tojiro Wednesday, October 15, 2008 4:00 AM
    Wednesday, October 15, 2008 3:27 AM

All replies

  • Hm. Well, it seems as if I've run into a situation that (inexplicably) no-one else seems to have ever tried. I certainly can't find anything about it online, and every example of this kind of behavior uses XML with no namespaces. I guess this just isn't supported? Seems rather strange, since namespaces are a failry core part of XML usage.

    Perhaps someone can at least tell me of a way to find view the XML for the DataContext of a control, with namespaces, so I can at least determine if the namespaces are being preserved? Debugging Data Binding is quite a pain, I've found.
    Saturday, October 11, 2008 6:25 PM
  • This works correctly for me:

    <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Page.Resources>
            <XmlNamespaceMappingCollection x:Key="namespaceMappings">
                <XmlNamespaceMapping Uri="http://www.footballism.com/2005/SoccerPlayers" Prefix="p"/>
            </XmlNamespaceMappingCollection>
           
            <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 age="26" fullName="Sebastian Batistuta"/>
                        <p:player age="30" fullName="Andriey Shevchenko"/>
                        <p:player age="21" fullName="Paviel Nedved"/>
                        <p:player age="19" fullName="David Beckham"/>
                    </p:players>
                </x:XData>
            </XmlDataProvider>
        </Page.Resources>
        <StackPanel>
            <TextBlock
                Text="{Binding XPath=@fullName}"
                FontWeight="Bold"
                DataContext="{Binding ElementName=listBox, Path=SelectedItem}"/>
            <ListBox ItemsSource="{Binding Source={StaticResource dataProvider}}"
                     x:Name="listBox"
                     DisplayMemberPath="@fullName">
            </ListBox>
        </StackPanel>
    </Page>

    Could you please provide a small, complete and ready-to-run example to demonstrate how it doesn't work for you when specifying xml namespace mapping?

    Thanks
    Tuesday, October 14, 2008 8:18 AM
  • Yes, that example works because you have simplified the example enough that it avoids the problem. The issue comes when attempting to use namespaces when querying a detail member in the master detail pattern. The XPath that you queried for the textblock did not use a namespace, and therefore queried correctly. If you change the code to the following, however, you'll notice that while the listbox still populates correctly the textblock no longer updates (because it is attempting a query that uses a namespace).

    <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Page.Resources>
            <XmlNamespaceMappingCollection x:Key="namespaceMappings">
                <XmlNamespaceMapping Uri="http://www.footballism.com/2005/SoccerPlayers" Prefix="p"/>
            </XmlNamespaceMappingCollection>

            <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"
                DataContext="{Binding ElementName=listBox, Path=SelectedItem}"/>
            <ListBox ItemsSource="{Binding Source={StaticResource dataProvider}}"
                     x:Name="listBox"
                     DisplayMemberPath="p:fullName">
            </ListBox>
        </StackPanel>
    </Page>

    Tuesday, October 14, 2008 9:54 PM
  • This works:

    <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Page.Resources>
            <XmlNamespaceMappingCollection x:Key="namespaceMappings">
                <XmlNamespaceMapping Uri="http://www.footballism.com/2005/SoccerPlayers" Prefix="p"/>
            </XmlNamespaceMappingCollection>
           
            <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:

    <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Page.Resources>
            <XmlNamespaceMappingCollection x:Key="namespaceMappings">
                <XmlNamespaceMapping Uri="http://www.footballism.com/2005/SoccerPlayers" Prefix="p"/>
            </XmlNamespaceMappingCollection>
           
            <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.
    • Marked as answer by Tojiro Wednesday, October 15, 2008 3:56 AM
    • Marked as answer by Tojiro Wednesday, October 15, 2008 3:56 AM
    • Marked as answer by Tojiro Wednesday, October 15, 2008 4:00 AM
    Wednesday, October 15, 2008 3:27 AM
  • Absolutely! Thank you very much. That certainly makes sense now that you lay it out like that. It's such a shame that these simple things are so hard to figure out sometimes. *sigh*

    Thank you again, and I dearly hope that this thread is of some use to some other poor developer out there who was as lost as I was! :)
    Wednesday, October 15, 2008 3:59 AM