DropDownList零代碼綁定XmlDataSource完全詳解

DropDownList控件在直接綁定XmlDataSource的時候會出現錯誤提示,這個問題把我折騰了好幾宿都沒睡安穩。MSDN上沒有對這個問題的詳細解答,CSDN上大家的解決辦法也都是五花八門。終歸離不開一個思路:以DataSet爲跳轉,先創建本地數據集從XmlDataSource裏把數據取出來,再作爲DropDownList的數據源進行數據綁定。這種做法不錯,但是寫代碼的時候難免會出錯,並且我對這樣做的效率深表懷疑。究其根源,DropDownList不能直接綁定XmlDataSource不是VS的Bug,我也是看了國外一個大牛寫的文章,才恍然大悟。

首先創建一個名爲XMLDataBing的網站,在App_Data下添加新項,VS會自動添加一個數據庫項。選擇XML文件,如圖。XML的內容就隨便寫一點吧:
這裏寫圖片描述
這裏寫圖片描述

<?xml version="1.0" encoding="utf-8" ?>

<Texts>

  <Text>
    <Name>Text1</Name>
    <Id>1</Id>
  </Text>

  <Text>
    <Name>Text2</Name>
    <Id>2</Id>
  </Text>

  <Text>
    <Name>Text3</Name>
    <Id>2</Id>
  </Text>

</Texts>

這是最簡單也是最基本的。現在看Default.aspx的設計視圖,拖一個DropDownList、一個XmlDataSource出來。一般人都會順手寫DropDownList的數據綁定:

<asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="XmlDataSource1"
    DataTextField='XPath("Name")' DataValueField='XPath("Id")'>
</asp:DropDownList>
<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/App_Data/XMLFile.xml"
    XPath="/Texts/Text">
</asp:XmlDataSource>

然後編譯通過,卻在IE裏很詫異地得到一個錯誤:

DataBinding:“System.Web.UI.WebControls.XmlDataSourceNodeDescriptor”不包含名爲“XPath(“Name”)”的屬性。

很醒目!錯誤說得很清楚,但是查MSDN死活也找不到XmlDataSourceNodeDescriptor的類定義。Google一下,查到Microsoft Online Community Support上某大牛的解釋:

System.Web.UI.WebControls.XmlDataSourceNodeDescriptor is an undocumented internal class which functions like a TypeDescriptor. It is used during data binding when the data source is XmlDataSource. Since it is an internal class, we are not having any public document on it.

大意是:System.Web.UI.WebControls.XmlDataSourceNodeDescriptor是一個未歸檔的內部類,它的工作原理就像TypeDescriptor。它應用在數據源是XmlDataSource的數據綁定時。由於是個內部類,我們還沒有任何關於它的公開文檔。

不知各位看了是個什麼心情,反正我是萬念俱灰了。。。。。。

MS把XmlDataSourceNodeDescriptor作爲XmlDataSource數據源進行綁定的重要內部類,出很低級的Bug讓DropDownList不能直接綁定XmlDataSource的可能性很小,只是我們忽略了什麼重要的東西。再回頭想想剛纔的整個過程,表面上看不出任何問題。我們不妨重新寫一個XML文件,作個小改動:

<?xml version="1.0" encoding="utf-8" ?>

<Texts>

  <Text Name="Text1" Id="1" />

  <Text Name="Text2" Id="2" />

  <Text Name="Text3" Id="3" />

</Texts>

在Default.aspx上新加一個XmlDataSource,DropDownList選擇數據源時會有明顯的變化!數據源選擇XmlDataSource2之後DataTextField和DataValueField選項會自動提示選擇Name還是Id。注意,這說明DropDownList能正確讀取XML文檔了!

問題解決了,但原因還沒找到。CSDN裏有人說直接綁定就OK,顯然是用第二種方法寫的XML。這兩種寫法的區別在於

<Text Name="Text1" Id="1" />
中,Name和Id是Text元素的屬性,而

<Text>
  <Name>Text1</Name>
  <Id>1</Id>
</Text>

中,Name和Id並非Text元素的屬性,而是一個元素節點。當數據綁定時,元素的屬性會被提升爲XmlDataSourceNodeDescriptor的屬性,通過XmlDataSource暴露出來,但這裏的元素節點卻不會,導致出錯。所以最簡單的辦法,把你的XML按第二種方法寫,就可以零代碼綁定了!

不過有人跟我一樣喜歡犯賤,非得按第一種方法寫。其實照樣可以成功,只不過要引入一個XLST文件。不多廢話,MSDN對XLST的解釋如下:

XSL 轉換 (XSLT) 樣式表(.xslt 或 .xsl 文件)用於將源 XML 文檔的內容轉換爲專門適合於特定用戶、媒介或客戶端的表現形式。

說白了,XSLT就是XML的模板。XmlDataSource會按照XSLT規定的模板讀取並轉換XML文檔裏的數據,而不考慮XML文檔裏規定的數據結構。在站點上點右鍵選添加新項,如圖會有XLST文件的模板出現。恩,寫一下前面例子的XSLT吧:
這裏寫圖片描述

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="Texts">

    <Texts>

      <xsl:apply-templates select="Text"/>

    </Texts>

  </xsl:template>

  <xsl:template match="Text">

    <Text>

      <xsl:attribute name="Name">

        <xsl:value-of select="Name"/>

      </xsl:attribute>

      <xsl:attribute name="Id">

        <xsl:value-of select="Id"/>

      </xsl:attribute>

    </Text>

  </xsl:template>

</xsl:stylesheet>

OK,別忘了在XmlDataSource1裏說明使用剛纔的XSLT文件

<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/App_Data/XMLFile.xml"
    XPath="/Texts/Text" TransformFile="~/XSLTFile.xsl"></asp:XmlDataSource>

大功告成!現在得到了正確結果,大家不用再失眠了。使用XSLT還能讓DataTextField和DataValueField同時綁定多個元素屬性,具體方法大家可以自行Google。只有一個可考慮可忽略的問題:按照第一種寫法,使用DataList或者其他某些控件時,用XPath是有效的;DropDownList爲什麼不能用XPath,還得多研究。

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章