WPF - Updating XmlDataProvider when source XML changes
Some days back i had answered a question on the WPF Forum on how to ensure that when the base XML file changes, the XmlDataProvider is udpated and hence the bound control on the UI.
The key is to set a watch on the particular XML file for changes and then update the provider appropriately. See details here. This solution works fine, but I didn't particularly like my initial code that I wrote since the FileSystemWatcher was set externally. It would be better if this could be self contained within the XmlDataProvider itself.
I hence decided to write my own XmlDataProvider for this purpose. Well, not write entirely, but obviously extend the existing provider. Following is the class that I wrote for this purpose. Since all I am really interested in is to get the FileSystemWatcher setup, I modify the Source property implementation and on the file change event, I force a refresh on the provider.
public class MyXmlDataProvider : XmlDataProvider
{
public new Uri Source
{
get { return base.Source; }
set
{
base.Source = value;
FileSystemWatcher watcher = new FileSystemWatcher();
//set the path of the XML file appropriately as per your requirements
watcher.Path = AppDomain.CurrentDomain.BaseDirectory;
//name of the file i am watching
watcher.Filter = value.OriginalString;
//watch for file changed events so that we can refresh the data provider
watcher.Changed += new FileSystemEventHandler(file_Changed);
//finally, don't forget to enable watching, else the events won't fire
watcher.EnableRaisingEvents = true;
}
}
void file_Changed(object sender, FileSystemEventArgs e)
{
base.Refresh();
}
}
This is all that is required. Using this in XAML is pretty straightfoward and following is a sample XAML.
<Window x:Class="TestWPFApp.XmlRefreshTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestWPFApp"
Title="XmlRefreshTest" Height="300" Width="300">
<Window.Resources>
<local:MyXmlDataProvider x:Key="xmlFromFile" Source="PersonXml.xml" XPath="persons/person" />
</Window.Resources>
<Grid>
<ListView ItemsSource="{Binding Source={StaticResource xmlFromFile}}" x:Name="list" >
<ListView.View>
<GridView>
<GridViewColumn Header="FirstName" DisplayMemberBinding="{Binding XPath=@firstname}" />
<GridViewColumn Header="LastName" DisplayMemberBinding="{Binding XPath=@lastname}" />
<GridViewColumn Header="Age" DisplayMemberBinding="{Binding XPath=@age}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
For my testing, I used the following Xml file. Note that I had marked the Xml as Content and Copy if newer in its properties to ensure that the Xml file is available in the output directory.
<?xml version="1.0" encoding="utf-8" ?>
<persons xmlns="">
<person firstname="Atul" lastname="Gupta" age="35" />
<person firstname="Sidharth" lastname="Ghag" age="30" />
<person firstname="Virendra" lastname="Wadekar" age="30" />
</persons>
Comments are welcome !
