views:

169

answers:

2

Hi – I have a pretty straight forward data binding question (from the side of writing data bindable controls) that has me confused.

Looking at the .NET source code, it seems that most data binding is abstracted via the DataBinder.GetPropertyValue() method. This method takes an object and a property name, and the method will find the value via a TypeDescriptor or reflection or whatever. This works great on an IListSource such as DataSet, however I can’t get it working with an XmlNode object. I know that you can bind an XmlNodeList to a data source in ASP.NET, so I would expect this to work. Here’s the code:

class Program
{
   static void Main(string[] args)
   {
      XmlDocument doc = new XmlDocument();
      doc.Load("Data.xml");
      IEnumerable list = doc.SelectNodes("/Data/Row");

      foreach (object item in list)
      {
         object val = DataBinder.GetPropertyValue(item, "Number"); //Expect to see “1”, “2” and “3”
      }
   }
}

And Data.xml is:

<?xml version="1.0" encoding="utf-8" ?>
<Data>
   <Row Number="1" />
   <Row Number="2" />
   <Row Number="3" />
</Data>

When I call GetPropertyValue, I get this exception:

DataBinding: 'System.Xml.XmlElement' does not contain a property with the name 'Number'.

In my Data Binding loop, I just want to loop through any IEnumerable – I don’t want to special case the XmlNode type. Controls such as DropdownList will special case IListSource and do some conversions, however other IEnumerables look like they’re treated as is. Thanks!

A: 

First I would use var and not object other wise your casting each node to an object.

foreach (var item in list)
{
    object val = DataBinder.GetPropertyValue(item, "Number"); //Expect to see “1”, “2” and “3”
}
// this isn't going to work...

Then I would have to check but I don't think your going to have a property called Number. You might have an property call Attributes that is a Dictionary which you then could call:

//object val = DataBinder.GetPropertyValue(item, "Attributes")["Number"].Value;
// this isn't going to work either...

If all you are wanting to do is get the value of that attribute on the node then use this:

for (int index = 0; index < nodes.Count; index++)
{
    var value = nodes.Item(index).Attributes["Number"].Value;
}

System.Web.UI.DataBinder is usually used in the html portion of a asp.net page. I have never used it inside of a static void Main().

Edit:

I found a link after googling: "databound dropdownlist to xml" that I think might help.

ASP Net - databinding xml to dropdownlist

J.13.L
If you do that, you're special casing XmlNode. I want to be able to pass in an IEnumerable of DataRows, a HashTable, etc. Basically anything you could typically bind to a datasource in ASP.NET.
Mike
Made some changes...
J.13.L
As I said, I don't want to assume the IEnumerable is an XmlNode. I want it to work with anything.. Thanks anyway.
Mike
Actually I might be totally wrong, I just tried DataBinding to a DropDownList object by adding this code:DropDownList dd = new DropDownList();dd.DataSource = list;dd.DataTextField = "Number";dd.DataBind();And I get the same exception on DataBind(). Do ASP.NET data bound controls not support data binding to an XmlDocument? I could have sworn they did..
Mike
Added a link that I think might help...
J.13.L
Thanks! My question is how to actually /write/ a control that does this, not how to use the DropDownList control. Anyway, I tracked down the correct answer..
Mike
Just a recommendation, if you found an answer you can post it yourself and mark it as the answer... I you ask question and never mark any of the suggestions "the answer" people will no longer post suggestions to your questions.
J.13.L
A: 

I tracked this down and it's correct, XmlDocument is not bindable because XmlNode doesn't implement a property descriptor. According to my sources, there has been talk of doing this for several years but it hasn't happened yet. However, the XmlDataSource class actually provides this feature. The trick is to create an XmlDataSource from your XmlDocument and bind to that instead, which will work perfectly..

XmlDocument doc = new XmlDocument();
doc.Load("Data.xml");

XmlDataSource source = new XmlDataSource();
source.Data = doc.OuterXml;
source.EnableCaching = false;
source.DataBind();

DropDownList dd = new DropDownList();
dd.DataSource = source;
dd.DataTextField = "Number";
dd.DataBind();
Mike