Blogs

Paul Kimmel's Blog

September 2009 - Posts

  • Using the ASPxUploadControl and Displaying Image Thumbnails

         

    I am surprised at the myriad ways in which companies make money. I wrote some software a few years ago for a company that sold millions of dollars worth of labels. Labels for medicine, warnings, and all kinds of other things. The application was pretty simple. The application permitted the user to add, browse, and edit the text content of the images. The fun part was that I integrated Adobe Illustrator into the application and used Illustrator CS3 to read the text layer from the image, spell check it, and search the image database by things like the text on the image. The application wasn’t very complicated but it was fun writing code that used Illustrator as an application servlet and playing with images, thumbnail versions of those images, and creating a couple of custom components.

    This blog entry shows you how to use DevExpress’ ASPxUploadControl to upload images to a server, create a thumbnail version of those images, and display the thumbnail versions of the uploaded image. The example includes a couple of examples of our client-side event functionality, some JavaScript, and a little GDI+ mojo to round out the blog. I hope you have fun tinkering with the code.

    Constructing the ASPX Bits

    The Web page was constructed with an HTML table for layout, an <img> element for the uploaded graphic and version 9.2 of our ASPxUploadControl and ASPxButton. The HTML table uses the table cell <td> rowspan to allow room for the image and colspan to center the upload button. The ASPX is in Listing 1, and the design time view is shown Figure 1.

    Listing 1: The ASPX describing the simple layout using an HTML table and the Web controls.

    <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
    <%@ Register Assembly="DevExpress.Web.v9.2, Version=9.2.4.0, Culture=neutral,
    PublicKeyToken=b88d1754d700e49a"
    Namespace="DevExpress.Web.ASPxCallbackPanel" TagPrefix="dxcp" %>
    <%@ Register Assembly="DevExpress.Web.v9.2, Version=9.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a"    Namespace="DevExpress.Web.ASPxCallback" TagPrefix="dxcb" %>
    <%@ Register assembly="DevExpress.Web.ASPxEditors.v9.2, Version=9.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" namespace="DevExpress.Web.ASPxEditors" tagprefix="dxe" %>
    <%@ Register assembly="DevExpress.Web.v9.2, Version=9.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" namespace="DevExpress.Web.ASPxUploadControl" tagprefix="dxuc" %>
    <%@ Register assembly="DevExpress.Web.v9.2, Version=9.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" namespace="DevExpress.Web.ASPxPanel" tagprefix="dxp" %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
     
        <div>
          <table width="50%">
            <tr>
                <td>
                    <dxuc:ASPxUploadControl ID="ASPxUploadControl1" runat="server" 
                        ClientInstanceName="uploader" 
                        onfileuploadcomplete="ASPxUploadControl1_FileUploadComplete">
                        <ClientSideEvents FileUploadComplete="function(s, e) {
                    
         debugger;
                     
        _aspxGetElementById('PreviewImage').src = e.callbackData;
                       
    }" />
                    </dxuc:ASPxUploadControl>
                </td>
                <td rowspan="2">
                    <img alt="" src="" id="PreviewImage"/></td>
            </tr>
           
    <tr>
         
        <td>
     
              <dxe:ASPxButton ID="ASPxButton1" runat="server" Text="Upload"
                      AutoPostBack="False">
     
                 <ClientSideEvents Click="function(s, e) {
     
                  uploader.UploadFile();
                 
    }" />
               
    </dxe:ASPxButton>
             
    </td>
           
    </tr>
         
    </table>
         
    </div>
       
    </form>
    </body>
    </html>

    image
    Figure 1: The HTML table layout, <img>, and the ASPxButton and ASPxUploadControl as laid out at design time.

    You don’t necessarily have to use an HTML table for layout. You could use a style sheet and div tags for example. Also, the design time layout can be pretty basic if you use a style sheet and skins again to manage the appearance. (A good place to learn how to learn more about style sheets is chapter 10 of the Professional DevExpress ASP.NET Controls and some of the other great blogs and articles on the devexpress web site. Mehul Harry and Jeff in production do a great job with some of the video demos.)

    Implementing the Client-Side Events

    A great feature of DevExpress ASP.NET controls is the client-side script functionality. With DevExpress controls there is an analogous client-side control for each server-side control. The convention is ASPxClientControlName. For example, the ASPxButtonControl has its paired ASPxClientButtonControl. So, if you set the ClientInstance name for the ASPxButtonControl to uploader then when you are interacting with the control in client script you are invoking behaviors and managing properties via an instance of the ASPxClientButtonControl.

    To implement client-side functions for DevExpress controls click the ClientSideEvents property of a particular control and use the Client-Side Events Editor to implement a specific event (see Figure 2). To initiate the file upload a Click function was associated with the ASPxButton, and a FileUploadComplete was implemented—see Listing 1 for both functions—to respond when the upload has completed.

    image
    Figure 2: The Client-Side Events Editor makes it easy to associate client-side event functions with a particular ASPx control.

    Client-side events are defined as strings and attached on the client through an AddHandler call. You don’t have to manage this plumbing; its all managed for you. However, if you want to know how client-side events are wired up at runtime then here you go. The controls emit some script that obtains a reference to the relevant control. For instance when an event needs to be wired for the client-side version of an ASPxUploadControl a reference is obtained to its paired ASPxClientUploadControl. The reference is used to refer to the particular client event property and AddHandler is called. AddHandler gets the inline code that you associated with event as text using the Client-Side Event Editor. Here is a chunk of the generated script showing you how the event handler for the ASPxUploadControl’s Click event is wired.

    var dxo = new ASPxClientUploadControl('ASPxUploadControl1');
    window['uploader'] = dxo;
    aspxAddDisabledItems('ASPxUploadControl1',[[['dxucDisabled dxucDisabledButton'],[''],['Add','Upload','Cancel','Remove_0']]]);
    dxo.FileUploadComplete.AddHandler(function(s, e) {
     
    debugger;
     
    _aspxGetElementById('PreviewImage').src = e.callbackData;
    });

    Keep in mind that there is all kinds of background processing going on when a ASP.NET Web page is actually pushed out to the client, so this approach is not unique. And, of course, all of this plumbing is automatic. You don’t have to worry about the how; just implement client-side code using the Client-Side Event Editor and the rest is managed for you.

    The ASPxButtonClick on the client-side calls UploadFile which will result in the ASPxUploadControl.FileUploadComplete being fired on the server and then the client-side FileUploadComplete being called. The client-side FileUploadComplete handler obtains a reference to the <img> element and sets it’s src property to the data return from the server-side FileUploadComplete. The src is an URL to the image to display. What has to happen in between is that the uploaded file needs to be saved, and for our example a thumbnail image of the control needs to be created.

    Implementing the Code-Behind

    As implemented in Listing 2 the code-behind saves the uploaded image and creates a thumbnail version of the image to display. On the server FileUploadComplete is called first—in this scenario. FileUploadComplete calls SavePostedFile and assigns a predetermined path and filename format to the FileUploadCompleteEventArgs.CallbackData property. The original filename with a “thumbnail_” prefix is designated as the return value—the thumbnail to display.

    SavePostedFile checks to make sure that the uploadedFile is valid. If UploadedFile.IsValid then UploadedFile.SaveAs is called saving a copy of the uploaded file to a folder on the server; in this instance the virtual path ~/Images/. MapPath is called to map the virtual folder to a physical folder for the SaveAs method. CreateThumbnail is called to create a thumb-image of the uploaded file.

    CreateThumbnail creates an in-memory instance of the image and assigns it to a GDI+ image. (You can pass the bytes as I did and use FromStream and create a MemoryStream or use the UploadedFile.FileContent property, which is a stream.) The GDI+ Image calls GetThumbnailImage to create a thumbnail image version of the uploaded image. GetThumbnailImage makes a call into unmanaged code, which is why the delegate for errors and the IntPtr.Zero arguments are used. The delegate and IntPtr arguments are unused but have to be provided. (You can use Reflector to see the call into unmanaged code under the hood.) Finally, the thumbnail is saved and the client-side FileUploadComplete event takes over displaying the thumbnail image (see Figure 3).

    Listing 2: The code-behind that

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using GDI=System.Drawing;
    using System.Drawing.Drawing2D;
    using System.IO;
    using System.Drawing.Imaging;
    using DevExpress.Web.ASPxUploadControl;
    using System.Drawing;

    public partial class _Default : System.Web.UI.Page
    {
        private string path = "~/Images/";
        private string current = "thumbnail_{0}";
        private void CreateThumbnail(byte[] data, string target)
        {
          GDI.Image image = GDI.Image.FromStream(new MemoryStream(data));
          GDI.Image thumbnail =
            image.GetThumbnailImage(100, 100,
            delegate { return false; },IntPtr.Zero);
          thumbnail.Save(GetUploadedTargetName(target));
        }

        private string GetUploadedTargetName(string filename)
        {
          return MapPath(path) + string.Format(current, filename);
        }

         protected void SavePostedFile(UploadedFile uploadedFile)
         {
           if (!uploadedFile.IsValid) return;
           uploadedFile.SaveAs(MapPath(path) + uploadedFile.FileName);
           CreateThumbnail(uploadedFile.FileBytes, uploadedFile.FileName);
         }

        protected void  ASPxUploadControl1_FileUploadComplete(object sender,
          DevExpress.Web.ASPxUploadControl.FileUploadCompleteEventArgs e)
        {
          SavePostedFile(e.UploadedFile);
          e.CallbackData = "Images/" + string.Format(current, e.UploadedFile.FileName);
        }
    }

    image

    Figure 3: The uploaded image as a thumbnail  to the right of the ASPxUploadControl.

    The basic orchestration of the upload, save image, create thumbnail, and display thumbnail is:

    • call ASPxUploadControl.UploadFile from the client. You can use your own button or set ASPxUploadControl.ShowUploadButton to true
    • implement a server-side ASPxUploadControl.FileUploadComplete method to save the uploaded file and create the thumbnail
    • implement a client-side ASPxUploadControl.FileUploadComplete to update the image element’s src property. Alternatively, you could set the runat=”server” attribute of the <img> element and set the src property on the server side, which eliminates the need for the client-side FileUploadComplete method

    You can play around with variations of my implementation. For example, set the <img> element’s runat=”server” attribute and try setting the image’s src property on the server. Some things to try, include using the same filename for the thumbnail each time. Does it effect whether or not the image is updated on the client? What if you use the ASPxBinaryImage or ASPxImage: do you need to change any of the client or server code?

    I like to play with implementation variations. The main objective is to fine tune the results and ultimately get a solution as simple and short as possible.

    Enjoy.

  • This is Your Brain on CodeRush

         

    I wrote a blog post called Functional Construction with LINQ to XML. I wrote a book entitled LINQ Unleashed: for C# and have written several blogs, dozens of articles, and the book Professional DevExpress ASP.NET Controls, which has several LINQ queries in it. Having done all of that and having used LINQ in applications and presentations, unfortunately there are just too many intricate details to remember everything. Fortunately, one thing that helps me remember details is the Internet, my own blogs, articles, and books. Another thing that helps me remember is CodeRush. CodeRush is a useful extension of my memory.

    In the last blog I wrote about Functional Construction. Functional construction is roughly constructing something from function calls. The blog employed LINQ to XML and the System.Xml.Linq namespace. The classes in that namespace construct individual elements of an XML document. All of this happens with an embedded LINQ query. The upshot is that all of this requires a meticulous attention to detail when constructing LINQ to XML queries and those queries construct XML documents. When I need to rely on meticulous details one of the things I rely on is CodeRush. If you use a meticulous feature occasionally—like LINQ to XML and Functional Construction—then create a CodeRush template to “remember” it for you.

    The example that follows will walk you through, step-by-step, in creating a CodeRush template for the LINQ query from Functional Construction with LINQ to XML. (Mark Miller could probably give you a better solution, but he is a pretty busy guy and I don’t mind muddling through.)

    If you are reading this blog then I hope you have heard of CodeRush and are using it. If not, in my own words CodeRush is a meta-programming tool or perhaps a code accelerator. CodeRush has templates that contain code stubs with replaceable elements. You type the short command name for the template and the IDE spits out the code for you. With CodeRush and its underlying DXCore engine the parts you need to change like an actual property name for the property template have visual cues and interact with the IDE to facilitate your changing them. The net result is that you get all of the code you need with a whole lot less typing and time. Everyone has heard about the mythological programmers that are twenty times more productive than every other programmer. Well, with CodeRush we can all be that guy, we can all be part of the myth.

    Now, Mark and the DevExpress developers that work on CodeRush have thought of a lot of templates, and have done a great job with the common templates. However, what they have accomplished in addition to that is to make CodeRush extensible. This means if you define a template that you need then you can add the template right in Visual Studio. Here are the steps I used to define the template in Listing 1:

    1. In Visual Studio select the DevExpress menu; click on the Options menu
    2. In the navigator expand the Editor node and click on the Templates item
    3. A list of predefined templates will be displayed
    4. Click the New Category—it has the red starburst on a folder
    5. When the New Category dialog is displayed enter LINQ and click OK
    6. Select the LINQ category and click the New Template button (just to the right of the New Category button)
    7. Enter a name (Functional Construction) for the new template
    8. Define the template as shown in Listing 1
    9. Plain text is just typed in the way you want it generated and the special elements like <<Caret>> are commands and they are added from the toolbar or Command drop down just below the Expansion window
    10. Use window check select where the expansion will be activated. (Expand the and check InMethod and InMethodBlock, and expand Line and check On Empty Line)
    11. Finally at the bottom enter in the Dependent Namespaces box enter the LINQ to XML namespaces System.Linq and System.Xml.Linq
    12. Click OK when you are done editing the expansion

    The explanatory comments for the expansion are provided after the code listing.

    Listing 1: The CodeRush template that generates the code for a LINQ to XML functional construction of an XML document.

    XDocument doc = new XDocument(
    new XDeclaration("1.0", "utf-8", "true"),
    new XElement("Root",
    from «Caret»«Link(Range)»«BlockAnchor» in
    orderby «Link(Range)»
    select new XElement("",
    new XAttribute("CustomerID", «Link(Range)»),
    new XElement("CompanyName", «Link(Range)»)
    )));«Target»

    The «Caret» command indicates where the caret will be after the expansion is initiated. When you follow the «Caret» with «BlockAnchor» this indicates the block of the expansion that will be selected. The «Link» command links some text to all other appearances of the text in the Link. In the example, «Link(Range)» will link all occurrences of Range, so when you change the text Range all other instances of Range will be automagically changed when the text is changed. Finally, «Target» is where the cursor stops when the user has modified the elements of the expansion.

    image
    Figure 1: Add a new Category for your custom template.

    image 
    Figure 2: The Options dialog roughly as it will appear after the expansion is defined and the configuration settings have been made.

    image
    Listing 3: The expansion right after it has been added ; you can see that the first instance of Range is selected and the cyan color indicates that all occurrences of Range are linked.

    Now, CodeRush isn’t going to be very snappy with expansions named Functional Construction; that’s too many keystrokes. You create a new expansion—steps 6 and 7 above—and give it a shorter name; I used fc, for the new expansion. In the expansion window enter the name—Functional Construction—of the first template/expansion.  The proper input for referring to the other expansion is «:Functional Construction».

    Mark and company have gone to a lot of trouble to create some great CodeRush videos. You can check out these videos on the our website at http://www.devexpress.com/Products/Visual_Studio_Add-in/Coding_Assistance/training.xml.

  • Functional Construction with LINQ to XML

         

    XML is everywhere. XHTML is XML rules applied applied to HTML. XAML (eXtensible Application Markup Language) is an implementation of XML. You can use XML for controls like our ASPxMenu. Sometimes the only challenge is to transmogrify data you have, maybe database data, into data you want instead, XML. LINQ supports a concept called function construction of XML documents. The System.Xml.Linq namespaces contains classes that support constructing an XML document. These classes like XDocument, XElement, and XAttribute each construct parts of an XML document from the arguments you provide. (Conceptually LINQ to XML and functional construction work a lot like the CodeDom namespace, which supports code generation in a similar manner.)

    To use LINQ to construct an XML document you need some enumerable data. A DataTable, DataSet, Collection, or objects created from LINQ to SQL will all work as the source data. The next step is to write a LINQ query that enumerates over the data and invokes the constructors for the various XDocument, XElement, XAttribute, XDeclaration and other classes that represent elements of an XML document. Listing 1 contains some code that reads the Customers table from the database using vanilla ADO.NET and a LINQ to XML query that constructs the XML document. the output from the LINQ query is provided in Listing 2.

    Listing 1: ADO.NET is used to read the Northwind Customers table and construct an XML document.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data.SqlClient;
    using System.Data;
    using System.Xml.Linq;

    namespace FunctionalConstructionDemo
    {
      class Program
      {
        [STAThread]
        static void Main(string[] args)
        {
          string connectionString =
            @"Data Source=WYOMING\SQLEXPRESS;" +
            "Initial Catalog=Northwind;Integrated Security=True";

          string sql = "SELECT TOP 10 * FROM Customers";
          DataTable table = new DataTable();

          using (SqlConnection connection = new SqlConnection(connectionString))
          {
            connection.Open();
            SqlCommand command = new SqlCommand(sql, connection);
            SqlDataAdapter adapter = new SqlDataAdapter(command);
            adapter.Fill(table);
          }
          XDocument doc = new XDocument(
            new XDeclaration("1.0", "utf-8", "true"),
            new XElement("Customers",
            from DataRow cust in table.Rows
            orderby cust["CompanyName"]
            select new XElement("Customer",
                  new XAttribute("CustomerID", cust["CustomerID"]),
                  new XElement("CompanyName", cust["CompanyName"]),
                  new XElement("ContactName", cust["ContactName"]),
                  new XElement("ContactTitle", cust["ContactTitle"]),
                  new XElement("Address", cust["Address"]),
                  new XElement("City", cust["City"]),
                  new XElement("Region", cust["Region"]),
                  new XElement("PostalCode", cust["PostalCode"]),
                  new XElement("Country", cust["Country"]),
                  new XElement("Phone", cust["Phone"]),
                  new XElement("Fax", cust["Fax"])
                  )));

          System.Windows.Forms.Clipboard.SetData("Text", doc);
          Console.WriteLine(doc);
          Console.ReadLine();
        }
      }
    }

    Listing 2: The constructed XML document from the LINQ query in Listing 1.

    <Customers>
      <Customer CustomerID="ALFKI">
        <CompanyName>Alfreds Futterkiste</CompanyName>
        <ContactName>Maria Anders</ContactName>
        <ContactTitle>Sales Representative</ContactTitle>
        <Address>Obere Str. 57</Address>
        <City>Berlin</City>
        <Region></Region>
        <PostalCode>12209</PostalCode>
        <Country>Germany</Country>
        <Phone>030-0074321</Phone>
        <Fax>030-0076545</Fax>
      </Customer>
      <Customer CustomerID="ANATR">
        <CompanyName>Ana Trujillo Emparedados y helados</CompanyName>
        <ContactName>Ana Trujillo</ContactName>
        <ContactTitle>Owner</ContactTitle>
        <Address>Avda. de la Constitución 2222</Address>
        <City>México D.F.</City>
        <Region></Region>
        <PostalCode>05021</PostalCode>
        <Country>Mexico</Country>
        <Phone>(5) 555-4729</Phone>
        <Fax>(5) 555-3745</Fax>
      </Customer>
      <Customer CustomerID="ANTON">
        <CompanyName>Antonio Moreno Taquería</CompanyName>
        <ContactName>Antonio Moreno</ContactName>
        <ContactTitle>Owner</ContactTitle>
        <Address>Mataderos  2312</Address>
        <City>México D.F.</City>
        <Region></Region>
        <PostalCode>05023</PostalCode>
        <Country>Mexico</Country>
        <Phone>(5) 555-3932</Phone>
        <Fax></Fax>
      </Customer>
      <Customer CustomerID="AROUT">
        <CompanyName>Around the Horn</CompanyName>
        <ContactName>Thomas Hardy</ContactName>
        <ContactTitle>Sales Representative</ContactTitle>
        <Address>120 Hanover Sq.</Address>
        <City>London</City>
        <Region></Region>
        <PostalCode>WA1 1DP</PostalCode>
        <Country>UK</Country>
        <Phone>(171) 555-7788</Phone>
        <Fax>(171) 555-6750</Fax>
      </Customer>
      <Customer CustomerID="BERGS">
        <CompanyName>Berglunds snabbköp</CompanyName>
        <ContactName>Christina Berglund</ContactName>
        <ContactTitle>Order Administrator</ContactTitle>
        <Address>Berguvsvägen  8</Address>
        <City>Luleå</City>
        <Region></Region>
        <PostalCode>S-958 22</PostalCode>
        <Country>Sweden</Country>
        <Phone>0921-12 34 65</Phone>
        <Fax>0921-12 34 67</Fax>
      </Customer>
      <Customer CustomerID="BLAUS">
        <CompanyName>Blauer See Delikatessen</CompanyName>
        <ContactName>Hanna Moos</ContactName>
        <ContactTitle>Sales Representative</ContactTitle>
        <Address>Forsterstr. 57</Address>
        <City>Mannheim</City>
        <Region></Region>
        <PostalCode>68306</PostalCode>
        <Country>Germany</Country>
        <Phone>0621-08460</Phone>
        <Fax>0621-08924</Fax>
      </Customer>
      <Customer CustomerID="BLONP">
        <CompanyName>Blondesddsl père et fils</CompanyName>
        <ContactName>Frédérique Citeaux</ContactName>
        <ContactTitle>Marketing Manager</ContactTitle>
        <Address>24, place Kléber</Address>
        <City>Strasbourg</City>
        <Region></Region>
        <PostalCode>67000</PostalCode>
        <Country>France</Country>
        <Phone>88.60.15.31</Phone>
        <Fax>88.60.15.32</Fax>
      </Customer>
      <Customer CustomerID="BOLID">
        <CompanyName>Bólido Comidas preparadas</CompanyName>
        <ContactName>Martín Sommer</ContactName>
        <ContactTitle>Owner</ContactTitle>
        <Address>C/ Araquil, 67</Address>
        <City>Madrid</City>
        <Region></Region>
        <PostalCode>28023</PostalCode>
        <Country>Spain</Country>
        <Phone>(91) 555 22 82</Phone>
        <Fax>(91) 555 91 99</Fax>
      </Customer>
      <Customer CustomerID="BONAP">
        <CompanyName>Bon app'</CompanyName>
        <ContactName>Laurence Lebihan</ContactName>
        <ContactTitle>Owner</ContactTitle>
        <Address>12, rue des Bouchers</Address>
        <City>Marseille</City>
        <Region></Region>
        <PostalCode>13008</PostalCode>
        <Country>France</Country>
        <Phone>91.24.45.40</Phone>
        <Fax>91.24.45.41</Fax>
      </Customer>
      <Customer CustomerID="BOTTM">
        <CompanyName>Bottom-Dollar Markets</CompanyName>
        <ContactName>Elizabeth Lincoln</ContactName>
        <ContactTitle>Accounting Manager</ContactTitle>
        <Address>23 Tsawassen Blvd.</Address>
        <City>Tsawassen</City>
        <Region>BC</Region>
        <PostalCode>T2F 8M4</PostalCode>
        <Country>Canada</Country>
        <Phone>(604) 555-4729</Phone>
        <Fax>(604) 555-3745</Fax>
      </Customer>
    </Customers>

    I added the code to copy the output to the clipboard to make it easy to get the XML output into this blog post, but you could just as easily use a FileStream to write the XML output to a file. TOP 10 was used to keep the size of the XML output manageable.

    You can decompose the LINQ to XML query that constructs the document in the following way:

    • The actual type of the output object is an XDocument. XDocument is defined to accept an indeterminate number params object[] arguments, which is consistent with an unknown number of XML nodes
    • The first argument, an XDeclaration, represents the <xml> element node
    • The second argument is an XElement and it represents the root node, in this case <Customers>, only nodes that are repeated need to be in the LINQ query
    • The LINQ query is produces the results for the first and subsequent XML child elements of the Customers root beginning with the from DataRow cust in table.Rows part of the statement
    • The orderby clause will sort the results by CompanyName
    • and, the select uses projection to construct each node for each custom, filling in the details of a customer record

    In the sample XDocument has two arguments: XDeclaration and XElement. The first XElement defines the Customers root node. The Customers element will contain a single child for each Customer, a Customer element. Each Customer element will contain an XAttribute representing containing the CustomerID, and a child element for every column in a Customer row.

    Checkout the System.Linq.Xml namespace for more classes for constructing XML documents and examples that show you how to add CDATA.

     

  • Professional DevExpress ASP.NET Controls Book

         

    I have finished writing the book. Thanks in large part to the tremendous DevExpress team, especially Julian Bucknall, Joe Kunk, and Gary Short for help with content. Now there is an extensive editing and review process that has to take place to get it ready for PDC 2009. See Julian, Me, and some of the great DevExpress guys at PDC.

    I would like to thank everyone at Wiley and DevExpress. DevExpress is a great place to work, and the process of writing 592 pages was a tremendous effort on everyone’s part. One person who I can’t thank enough is Kevin White. Kevin really nurse-maided the whole process from beginning to end.

    While I can’t tell you exactly what’s in the book because it would spoil the surprise, I will take blog requests on topics you’d like covered in this blog.

More from DevExpress
Live Chat
Have a pre-sales question?
Need assistance with your evaluation?
We are here to help.
Chat is one of the many ways you can contact members of the DevExpress Team. We are available Monday-Friday between 8:30am and 5:00pm Pacific Time.
If you need additional product information, require pre-sales assistance, or want help with your order, write to us at info@devexpress.com or call us at
+1 (818) 844-3383.