Search code examples
xmlwpfxamldata-binding

WPF How do I setup proper data binding (XPath) on a textbox with an XML element or attribute?


Good day, I've been trying to crack this for several days now to no avail. I have a xml file and I'm trying to bind it's elements and attributes in a dynamic way to various textbox controls. I've tried different ways of going at this and but they've all failed. This last attempt is with

<UserControl x:Class="L5RCharacterManager.CharacterHeaderControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:L5RCharacterManager"
             mc:Ignorable="d"
             d:DesignHeight="100" d:DesignWidth="800">

    <Grid>
        <Grid>
            <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
            <Grid.Resources>
                <XmlDataProvider x:Key="data" Source="myXmlFile"/>
            </Grid.Resources>
            <Label Content="Clan" Grid.Column="0" Grid.Row="0" />
            <TextBox Grid.Column="1" Grid.Row="0">
                <TextBox.Text>
                    <Binding Source="{}" XPath="root/element/attribute" />
                </TextBox.Text>
            </TextBox>

Thanks for you time. Edit: a quick sample of the xml document I'm trying to bind.

<?xml version="1.0" encoding="utf-8"?>
<root>
  <element1 attr11="Scorpion" attr12="" attr13="" attr14="" />
  <elements2>
    <element21 name="twentyone" value="21">
      <subElement1a name="twentyoneA" />
      <subElement2b name="twentyoneB" />
    </element21>
    <element22 name="twentytwo" value="22">
      <subElement1a name="twentytwoA" />
      <subElement2b name="twentytwoB" />
    </element22>
   </elements2>
</root>

Solution

  • Examples:

            <StackPanel.Resources>
                <XmlDataProvider x:Key="xmlData" Source="myXmlFile.xml"/>
            </StackPanel.Resources>
            <TextBox Text="{Binding XPath=root/element1/@attr11, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
                     Source={StaticResource xmlData}}"/>
            <TextBox Text="{Binding XPath=root/element1/@attr12, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
                     Source={StaticResource xmlData}}"/>
    
        <StackPanel>
            <StackPanel.DataContext>
                <XmlDataProvider Source="myXmlFile.xml"/>
            </StackPanel.DataContext>
            <TextBox Text="{Binding XPath=root/element1/@attr11, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            <TextBox Text="{Binding XPath=root/element1/@attr12, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        </StackPanel>
    

    But the editing results will not be automatically saved.
    To do this, when you close the Window, get the XmlDataProvider and explicitly save it XML.

    An example that implements the saving of editing results.

        public static class Handlers
        {
            public static EventHandler SaveXmlOnClosed { get; } = (s, e) =>
            {
                Window window = (Window)s;
    
                XmlDataProvider provider = (XmlDataProvider)window.Resources["xmlData"];
    
                string file = provider.Source.OriginalString;
    
                provider.Document.Save(file);
            };
        }
    
    <Window ----------------------
            ----------------------
            Closed="{x:Static local:Handlers.SaveXmlOnClosed}">
       <Window.Resources>
                <XmlDataProvider x:Key="xmlData" Source="myXmlFile.xml"/>
        </Window.Resources>
        <StackPanel>
            <TextBox Text="{Binding XPath=root/element1/@attr11, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
                     Source={StaticResource xmlData}}"/>
            <TextBox Text="{Binding XPath=root/element1/@attr12, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged,
                     Source={StaticResource xmlData}}"/>
        </StackPanel>
    </Window>