Thursday, July 3, 2014

DevExpress Trees in ASP.NET

Today I figured out how to set up a DevExpress TreeList in ASP.NET in both web forms and MVC. Let's look at MVC first. I made this:

 
 

The first file to dress up to get this is Global.asax.cs. Mine looks like this:

using System;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using DevExpress.Web.Mvc;
namespace DummyDevExpressApplication
{
   public class WebApiApplication : System.Web.HttpApplication
   {
      protected void Application_Start()
      {
         AreaRegistration.RegisterAllAreas();
         GlobalConfiguration.Configure(WebApiConfig.Register);
         FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
         RouteConfig.RegisterRoutes(RouteTable.Routes);
         BundleConfig.RegisterBundles(BundleTable.Bundles);
      }
      
      protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
      {
         DevExpressHelper.Theme = "Aqua";
      }
   }
}

 
 

Here and here, I bemoan struggling with CSS styling in MVC DevExpress implementations. Well, I figured out what I was missing today. The .GetStyleSheets content needs to go in _Layout.html.

<!DOCTYPE html>
<html>
<head>
   <meta charset="utf-8" />
   <meta name="viewport" content="width=device-width" />
   <title>@ViewBag.Title</title>
   @Styles.Render("~/Content/css")
   @Scripts.Render("~/bundles/modernizr")
   @Scripts.Render("~/bundles/jquery")
   @Scripts.Render("~/bundles/bootstrap")
   @RenderSection("scripts", required: false)
   @Html.DevExpress().GetScripts(
      new Script { ExtensionSuite = ExtensionSuite.NavigationAndLayout },
      new Script { ExtensionSuite = ExtensionSuite.HtmlEditor },
      new Script { ExtensionSuite = ExtensionSuite.TreeList },
      new Script { ExtensionSuite = ExtensionSuite.Editors },
      new Script { ExtensionSuite = ExtensionSuite.Scheduler }
   )
   @Html.DevExpress().GetStyleSheets(
      new StyleSheet { ExtensionSuite = ExtensionSuite.TreeList, Theme = "Aqua" }
   )
</head>
   <body>
      <div style="margin: 0 auto; width: 600px;">
         @RenderBody()
      </div>
   </body>
</html>

 
 

Here is the Index.cshtml view that @RenderBody above will resolve to:

@using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
   @Html.Action("TreeListPartial")
   <input type="submit" value="Touch me." />
}

 
 

HomeController.cs summons that view. It follows. Here we see how we get back a list of keys (names of selected items) when submitting the form!

using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using DummyDevExpressApplication.Models;
namespace DummyDevExpressApplication.Controllers
{
   public class HomeController : Controller
   {
      public ActionResult Index()
      {
         return View();
      }
      
      [HttpPost]
      public ActionResult Index(FormCollection stuff)
      {
         List<string> selection = stuff["TreeList$Sel"].Split(' ').ToList();
         Session["selection"] = selection;
         return View();
      }
      
      [ValidateInput(false)]
      public ActionResult TreeListPartial()
      {
         List<HeavenlyBody> dataSource = Sun.Dependents();
         return PartialView("_TreeListPartial", dataSource);
      }
   }
}

 
 

_TreeListPartial.cshtml has the real meat and mechanics of the tree. The KeyFieldName specifies the getsetter on a model to use as the unique key and the ParentFieldName suggests which KeyFieldName value to consider a parent in the name of nesting any one object, otherwise side by side with its parent in a collection, as "of" its parent and within a tier beneath it.

@{
   var treeList = Html.DevExpress().TreeList(settings => {
      settings.Name = "TreeList";
      settings.CallbackRouteValues = new { Controller = "Home",
            Action = "TreeListPartial" };
      settings.AutoGenerateColumns = false;
      settings.KeyFieldName = "Name";
      settings.ParentFieldName = "Orbits";
      settings.Columns.Add("Name");
      settings.Columns.Add("AuInDistance");
      settings.Columns.Add("MilesInDiameter");
      settings.Columns.Add("DiscoveryDate");
      settings.SettingsPager.Visible = true;
      settings.SettingsSelection.Enabled = true;
   });
}
@treeList.Bind(Model).GetHtml()

 
 

Now, in web forms I have:

 
 

Default.aspx, my web form:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master"
      AutoEventWireup="true" CodeBehind="Default.aspx.cs"
      Inherits="DummyDevExpressApplication._Default" %>
<%@ Register Assembly="DevExpress.Web.ASPxTreeList.v13.1, Version=13.1.9.0,
      Culture=neutral, PublicKeyToken=b88d1754d700e49a"
      Namespace="DevExpress.Web.ASPxTreeList" TagPrefix="dx" %>
<%@ Register assembly="DevExpress.Web.v13.1, Version=13.1.9.0, Culture=neutral,
      PublicKeyToken=b88d1754d700e49a" namespace="DevExpress.Web.ASPxEditors"
      tagprefix="dx" %>
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
   <style type="text/css" media="all">
      #Tree {
         width: 600px !important;
      }
      #Tree_U div {
         width: 600px !important;
      }
      #Tree_U div:nth-child(2) {
         height: 300px !important;
      }
   </style>
   <dx:ASPxTreeList ID="Tree" ClientIDMode="Static" runat="server"
         AutoGenerateColumns="False" KeyFieldName="Name"
         ParentFieldName="Orbits">
      <Styles AlternatingNode-Enabled="True">
         <AlternatingNode Enabled="True">
         </AlternatingNode>
         <PopupEditFormWindowCloseButton CssClass="Hide" />
      </Styles>
      <Settings GridLines="Both" VerticalScrollBarMode="Auto"
            HorizontalScrollBarMode="Auto"/>
      <SettingsBehavior AllowSort="true" AutoExpandAllNodes="False" />
      <SettingsPager Mode="ShowPager" AlwaysShowPager="true" PageSize="13" />
      <SettingsSelection Enabled="True" />
      <Columns>
         <dx:TreeListTextColumn FieldName="Name" VisibleIndex="0">
         </dx:TreeListTextColumn>
         <dx:TreeListTextColumn FieldName="AuInDistance" VisibleIndex="1">
         </dx:TreeListTextColumn>
         <dx:TreeListTextColumn FieldName="MilesInDiameter" VisibleIndex="2">
         </dx:TreeListTextColumn>
         <dx:TreeListDataColumn FieldName="DiscoveryDate" VisibleIndex="3"
               Width="150">
         </dx:TreeListDataColumn>
      </Columns>
   </dx:ASPxTreeList>
   <asp:Button ID="Button1" runat="server" Text="Touch me." OnClick="Button1_Click" />
</asp:Content>

 
 

Default.aspx.cs, which is the code behind for Default.aspx:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;
using DummyDevExpressApplication.Models;
namespace DummyDevExpressApplication
{
   public partial class _Default : Page
   {
      protected void Page_Load(object sender, EventArgs e)
      {
         Tree.DataSource = Sun.Dependents();
         Tree.DataBind();
      }
      
      protected void Button1_Click(object sender, EventArgs e)
      {
         List<string> selection = Tree.GetSelectedNodes().Select(node =>
               node.Key).ToList();
         Session["selection"] = selection;
      }
   }
}

 
 

In case you are wondering what Sun.Dependents() coughs up, here it is:

using System;
using System.Collections.Generic;
namespace DummyDevExpressApplication.Models
{
   public class Sun
   {
      public static List<HeavenlyBody> Dependents()
      {
         return new List<HeavenlyBody>()
         {
            new HeavenlyBody()
            {
               Name = "Mercury",
               AuInDistance = 0.4m,
               MilesInDiameter = 3032
            },
            new HeavenlyBody()
            {
               Name = "Venus",
               AuInDistance = 0.7m,
               MilesInDiameter = 7521
            },
            new HeavenlyBody()
            {
               Name = "Earth",
               AuInDistance = 1m,
               MilesInDiameter = 7926
            },
            new HeavenlyBody()
            {
               Name = "Luna",
               AuInDistance = 0.0025m,
               MilesInDiameter = 2159,
               Orbits = "Earth"
            },
            new HeavenlyBody()
            {
               Name = "Mars",
               AuInDistance = 1.5m,
               MilesInDiameter = 4222
            },
            new HeavenlyBody()
            {
               Name = "Phobos",
               AuInDistance = 0.00006m,
               MilesInDiameter = 14,
               DiscoveryDate = new DateTime(1877,8,18),
               Orbits = "Mars"
            },
            new HeavenlyBody()
            {
               Name = "Deimos",
               AuInDistance = 0.00016m,
               MilesInDiameter = 8,
               DiscoveryDate = new DateTime(1877,8,12),
               Orbits = "Mars"
            },
            new HeavenlyBody()
            {
               Name = "Ceres",
               AuInDistance = 2.77m,
               MilesInDiameter = 590,
               DiscoveryDate = new DateTime(1801,1,1)
            },
            new HeavenlyBody()
            {
               Name = "Jupiter",
               AuInDistance = 5.2m,
               MilesInDiameter = 88846
            },
            new HeavenlyBody()
            {
               Name = "Saturn",
               AuInDistance = 9.5m,
               MilesInDiameter = 74898
            },
            new HeavenlyBody()
            {
               Name = "Uranus",
               AuInDistance = 19.2m,
               MilesInDiameter = 31763,
               DiscoveryDate = new DateTime(1781,3,13)
            },
            new HeavenlyBody()
            {
               Name = "Neptune",
               AuInDistance = 30.1m,
               MilesInDiameter = 30778,
               DiscoveryDate = new DateTime(1846,9,23)
            },
            new HeavenlyBody()
            {
               Name = "Pluto",
               AuInDistance = 39.5m,
               MilesInDiameter = 1430,
               DiscoveryDate = new DateTime(1930,2,18)
            },
            new HeavenlyBody()
            {
               Name = "Haumea",
               AuInDistance = 43.1m,
               MilesInDiameter = 217,
               DiscoveryDate = new DateTime(2003,3,7)
            },
            new HeavenlyBody()
            {
               Name = "Makemake",
               AuInDistance = 45.3m,
               MilesInDiameter = 882,
               DiscoveryDate = new DateTime(2005,3,31)
            },
            new HeavenlyBody()
            {
               Name = "Eris",
               AuInDistance = 68m,
               MilesInDiameter = 1445,
               DiscoveryDate = new DateTime(2003,10,21)
            }
         };
      }
   }
}

 
 

Finally, here is my model. This file and the one above existing in both the web forms and MVC implementations.

using System;
namespace DummyDevExpressApplication.Models
{
   public class HeavenlyBody
   {
      public string Name { get; set; }
      public decimal AuInDistance { get; set; }
      public int MilesInDiameter { get; set; }
      public DateTime? DiscoveryDate { get; set; }
      public string Orbits { get; set; }
   }
}

No comments:

Post a Comment