Search code examples
c#wpfxmlbindingxml-binding

Bind ListBox to XmlDocument


Could someone help me out, to why my listbox is empty?

The XmlDocument contains the following XML:

<Config>
  <Tabs>
    <Tab Name="Test1" />
    <Tab Name="Test2" />
  </Tabs>
</Config>

In my XAML file I have tried the following

<Window>
  <Grid>
     <ListBox DataContext="{Binding {StaticResource Data}, XPath=//Tabs}" ItemsSource="{Binding XPath=Tab/@Name}">
     </ListBox>
  </Grid>
<Window>

I know I haven't set up the binding to name attribute but shouldn't this display XmlDocument.XmlNode.ToString() for each Tab Node if it was working?

My C# Constructor Code behind:

InitializeComponent();
this.doc = new XmlDocument();
doc.LoadXml(config.document.OuterXml);
XmlDataProvider provider = (XmlDataProvider)Resources["Data"];
provider.Document = doc;
provider.Refresh();

With config.document.OuterXml being a valid document containing the above xml.

I got this working with procedural code using Collections, but I have been trying to figure out how to bind directly to XML.

Update: ListBox empty

Now there is no binding errors, but my listbox is coming up empty, I have double checked my XML file, and even did MessageBox.Show(provider.Document.OuterXML) and can confirm that the XmlDocument does have the correct nodes.

Thanks in advance


Solution

  • If you set the XmlDataProvider's Document property to your XmlDocument, it will refresh the bindings any time the XmlNode.NodeChanged event is raised. Since Document isn't a dependency property, you can't bind to it, so you have to set it in code; this should do the trick:

    In your XAML:

    <Window.Resources>
       <XmlDataProvider x:Key="Data"/>
    </Window.Resources>
    
    ...
    
    <ListBox 
        DataContext="{Binding {StaticResource Data}, XPath=Config/Tabs}"
        ItemsSource="{Binding XPath=Tab/@Name}"/>
    

    In the window's constructor:

    InitializeComponent();
    XmlDocument d = new XmlDocument();
    d.Load("MyData.xml");
    XmlDataProvider p = (XmlDataProvider)Resources["Data"];
    p.Document = d;
    

    Now any changes you make to your XmlDocument will be reflected in the ListBox.

    Edit:

    I can't tell you what you're doing wrong, but perhaps you'll be able to when you compare what you're doing with the below, which is a complete working example.

    Window1.xaml:

    <Window x:Class="Test.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="Data"/>
        </Window.Resources>
        <ListBox 
            DataContext="{Binding Source={StaticResource Data}, XPath=Config}" 
            ItemsSource="{Binding XPath=Tabs/Tab/@Name}"/>     
    </Window>
    

    Window1.xaml.cs:

    using System.Windows;
    using System.Windows.Data;
    using System.Xml;
    
    namespace Test
    {
        public partial class Window1 : Window
        {
            public Window1()
            {
                InitializeComponent();
    
                XmlDocument d = new XmlDocument();
                string xml = @"<Config><Tabs><Tab Name='foo'/><Tab Name='bar'/></Tabs></Config>";
                d.LoadXml(xml);
                ((XmlDataProvider) Resources["Data"]).Document = d;
            }
        }
    }