Search code examples
c#xmlwpfxamldata-binding

How to Add/Remove Items from XML Databound ListBox in WPF?


I am new to WPF and XML Databinding confuses me a lot so please have patience if I have no Idea what I am talking about.

I am trying to make a XML bound Listbox that has a two-way binding. I was able to bind the Listbox to the XML Doc and edit the Items. But I am struggling to Add or Remove items. I simply want to remove the single-selected item, or add new item via a UI prompt.

XAML:

    <Window.Resources>
        <DataTemplate x:Key="QuickDataTemplate">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="100" />
                </Grid.ColumnDefinitions>
                <TextBlock Text="{Binding XPath=Title}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                <ui:TextBox x:Name="ListTextBox" Grid.Column="1" Text="{Binding XPath=Value}" IsEnabled="False" Foreground="Black" Opacity="100" VerticalAlignment="Center" HorizontalAlignment="Center"/>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.DataContext>
            <XmlDataProvider x:Name="QuickData" Source="QuickData.xml" XPath="List/Item" />
        </Grid.DataContext>

...

                                <ListBox Width="200" Height="140" Name="QuickDataList"                      HorizontalContentAlignment="Stretch" IsSynchronizedWithCurrentItem="True"
                                         Visibility="Visible" ItemsSource="{Binding}" ItemTemplate="{StaticResource QuickDataTemplate}">
                                </ListBox>
</Grid>

C# Code Behind:

string QuickDataPath = path + "QuickData.xml";
QuickData.Source = new Uri(QuickDataPath);

        private void ListEdit_Click(object sender, RoutedEventArgs e)
        {
            P_EditQuickData.Visibility = Visibility.Visible;
            ListSave.Visibility = Visibility.Visible;
        }
        private void ListDelete_Click(object sender, RoutedEventArgs e)
        {
            QuickDataList.Items.RemoveAt
            (QuickDataList.Items.IndexOf(QuickDataList.SelectedItem));
            ListSave.Visibility = Visibility.Visible;
        }
        private void ListSave_Click(object sender, RoutedEventArgs e)
        {
            ListSave.Visibility = Visibility.Collapsed;
            string source = QuickData.Source.LocalPath;
            QuickData.Document.Save(source);

        }

XML Doc:

<?xml version="1.0" encoding="utf-8"?>
<List xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Item>
    <Title>Holes</Title>
    <Value>29</Value>
  </Item>
  <Item>
    <Title>Holes</Title>
    <Value>28</Value>
  </Item>
  <Item>
    <Title>Holes</Title>
    <Value>14</Value>
  </Item>
</List>

I can edit the items easily but I get this error when trying to remove or add items via 'QuickDataList.Items.RemoveAt':

System.InvalidOperationException: 'Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead.'

I referenced this article but I just cannot wrap my head around it.

I think I can deserialize/load the xml doc, select the right item, then remove/add the child and re-serialize, but that seems like such an excessive amount of code in comparison to what it took to simply just bind the xml and edit it.

I appreciate any feedback at all.


Solution

  • What the error is telling you is you can't modify the Items collection when the control is bound to an ItemsSource. You need to modify the source directly, in this case you are using an URI so you will have to modify the Xml file and refresh the XmlDataProvider.

    Alternatively you can load the Xml file as a XmlDocument and bind that to the Data provider (through the Document property, instead of Source). This method makes manipulation of the XML a lot easier.