-->

How to bind XmlDataProvider.Source to MVVM propert

2019-01-20 05:14发布

问题:

I've got a treeview bound to an XmlDataProvider following this example. The app I am working on is following the MVVM pattern and the Xml is from a file that the user will open.

When I try to bind the Source property of the XmlDataProvider like so

<XmlDataProvider Source="{Binding Path=XmlFilePath}"/>

I get a "Binding can only be applied to a DependencyProperty of a Dependency object." or somesuch.

So short of cobbling the binding together procedurally is there a way to declaratively bind the XmlDataProvider Source? If I try to forgo the data provider and bind the tree directly to an XmlNode property I get an error about using XPath binding only with Xml objects; which makes absolutely no sense to me but I'm sure it's trying to tell me something important.

回答1:

The answer appears to be: you can't.

I was able to solve my underlying problem (binding a treeview to an Xml document) by removing the XmlDataProvider from the equation and binding the TreeView directly to a ViewModel property that returns an XmlNode.

What had been tripping me up was that I took the binding code that pointed at the XmlDataProvider and pointed it at my property, leaving the XPath argument in place.

<TreeView ItemsSource="{Binding Path=ProjectDocument XPath=.}">

This would result in a runtime error: System.Windows.Data Error: 44 : BindingExpression with XPath cannot bind to non-XML object.; XPath='.'

Which was not the most helpful. What it was really trying to say is that you can't bind to an XmlNode property AND provide an XPath argument in the binding (because it's the XmlDataProvider that knows what to do with that??).

<TreeView ItemsSource="{Binding Path=ProjectDocument}">


回答2:

actually that was rather tough problem for me, cause I needed the app to load treeview from temp file, and assuming application can have different locations, I can't set strict link in the XmlDataProvider Source property;

Add source as resource to the project

the solution I found is adding temp file (markup is created via XAML, see below) to the project with build action set to Content thus, application reloads it every time you call InitializeComponent() on the object containing XmlDataProvider and my treeview updates.

    <XmlDataProvider x:Key="dshPreview" 
                     Source="~tmpConstruct.xml" 
                     XmlNamespaceManager="{StaticResource argNms}"   
                     IsAsynchronous="true"/>

TreeView is bound like this:

  <TreeView  x:Name="PreviewTree" 
             ItemsSource="{Binding Source={StaticResource dshPreview},
             XPath=/mns:engine/mns:ws}"
              />         

Maybe this will help someone



回答3:

I didn't find how to bind the source straight away, but you can change the XmlDataProvider source in the code behind as following:

var xdp = (XmlDataProvider)this.Resources["key-of-your-XmlDataProvider-in-resources"];
xdp.Source = new Uri("http://url-of-your-xml");

You can use that combined with an event handler to bind.