Posts Tagged ASP.Net

ASP.Net MVC: Single Page Application (SPA) from Scratch; A How To Step by Step

During my presentation to the Denver Visual Studio Users Group on Asp.net SPA on March 25, 2013, I created an example SPA application from scratch using Visual Studio 2012 with Asp.Net and MVC. The intent was to provide an understanding of the tools and technologies needed to build an Asp.net spa. The following are the steps I used to create the basic SPA entitled UserGroupSPA in VS2012.

The following technologies and templates were used or provided inspiration in creating the example:

Pre Setup

  1. Using Microsoft Web Platform Installer 4.5, install  Asp.Net and Web Tools 2012.2 Update.
    1. Note that as of this writing that update will be included in the future Visual Studio 2012 Update #2.
    2. In the Microsoft Web Platform installer it is listed as Asp.net and Web Tools 2012.2

Visual Studio Project

  1. Create new project
    1. ASP.Net MVC 4 Web Application named UserGroupSPA
      1. Choose Basic Asp.net MVC4 Project Template with Razor view engine
  2. Package Manager Console (NUGET)
    1. Get-Package –Update
      1. Update-Package jQuery
      2. … (update all packages which can be updated as reported)
      3. Update-Package knockoutjs
    2. Install-Package Breeze.Webapi

Create Viewable Web Page in MVC at Root

  1. In the Views Folder
    1. Delete Shared folder and all of its contents
    2. Delete the view _View Start.cshtml
    3. Create DVSUG directory in the Views folde
    4. Add the view index.cshtml into the DVSUG directory
  2. This is the code for index.cshtml
    @using System.Web
    @using System.Web.Optimization
    <!DOCTYPE html>
    <html>
    <head>
        <title>Denver Visual Studio Users Group</title>
    
        @Styles.Render("~/Content/css")
    </head>
    <body>
        <h1>Denver Visual Studio Users Group Main</h1>
    </body>
    </html>
  3. Global.asax
    1. Comment out the line RegisterBundles such as:
      WebApiConfig.Register(GlobalConfiguration.Configuration);
      FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
      RouteConfig.RegisterRoutes(RouteTable.Routes);
      //BundleConfig.RegisterBundles(BundleTable.Bundles);
  4. App_Start folder
    1. Add C# class DVSUGConfig
      using System.Web.Optimization;
      
      [assembly: WebActivator.PostApplicationStartMethod(
          typeof(UserGroupSPA.App_Start.DVSUGConfig), "PreStart")]
      
      namespace UserGroupSPA.App_Start
      {
          public class DVSUGConfig
          {
              public static void PreStart()
              {
                  BundleConfig.RegisterBundles(BundleTable.Bundles);
              }
          }
      
      }
    2. Add C# class DVSUGRouteConfig
      using System.Web.Mvc;
      
      [assembly: WebActivator.PreApplicationStartMethod(
          typeof(UserGroupSPA.App_Start.DVSUGRouteConfig), "RegisterDVSUGPreStart", Order = 2)]
      
      namespace UserGroupSPA.App_Start
      {
          ///<summary>
          /// Inserts the DVSUGRouteConfig SPA sample view controller to the front of all MVC routes
          /// so that the DVSUGRouteConfig SPA sample becomes the default page.
          ///</summary>
          ///<remarks>
          /// This class is discovered and run during startup
          /// http://blogs.msdn.com/b/davidebb/archive/2010/10/11/light-up-your-nupacks-with-startup-code-and-webactivator.aspx
          ///</remarks>
          public static class DVSUGRouteConfig
          {
      
              public static void RegisterDVSUGPreStart()
              {
      
                  // Preempt standard default MVC page routing to go to DVSUG 
                  System.Web.Routing.RouteTable.Routes.MapRoute(
                      name: "DVSUGMvc",
                      url: "{controller}/{action}/{id}",
                      defaults: new
                      {
                          controller = "DVSUG",
                          action = "Index",
                          id = UrlParameter.Optional
                      }
                  );
              }
          }
      }
  5. Controllers directory
    1. Add controller DVSUGController (Empty MVC Controller)
  6. Run the application in IE (not chrome) in debug (F5)

Adding Toastr For Notifications

  1. Package Manager Console
    1. install-package toastr
  2. App_Start
    1. BundleConfig.CS change to:
      using System.Web;
      using System.Web.Optimization;
      
      namespace UserGroupSPA
      {
          public class BundleConfig
          {
              // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725
              public static void RegisterBundles(BundleCollection bundles)
              {
                  bundles.IgnoreList.Ignore("*.intellisense.js");
                  bundles.IgnoreList.Ignore("*-vsdoc.js");
      
                  bundles.Add(
                              new ScriptBundle("~/scripts/UGScripts")
                              .Include("~/Scripts/jquery-{version}.js")
                              .Include("~/scripts/knockout-{version}.debug.js")
                              .Include("~/scripts/toastr.js")
                              .Include("~/scripts/Q.js")
                              .Include("~/scripts/breeze.debug.js")
                              );
      
                  bundles.Add(
                              new StyleBundle("~/Content/css")
                             .Include("~/Content/bootstrap.css")
                              .Include("~/Content/toastr.css")
                              );
              }
          }
      }
  3. Views\DVSUG\index.cshtml
    @using System.Web
    @using System.Web.Optimization
    <!DOCTYPE html>
    <html>
    <head>
        <title>Denver Visual Studio Users Group</title>
    
        @Styles.Render("~/Content/css")
    
    </head>
    
    <body onload="toastr.info('Loading Main Body')">
    
        @Scripts.Render("~/scripts/UGScripts")
    
        <h1>Denver Visual Studio Users Group Main</h1>
    
    </body>
    
    </html>
  4. Run in IE again and verify the toast event “Loading Main Body” comes up. such as:DVSUG

Install Durandal

  1. Package Manager Console
    1. install-package Durandal
    2. install-package Durandal.Router
    3. install-package Durandal.Transitions
    4. install-package Twitter.Bootstrap
  2. App_Start\BundleConfig.CS
    using System.Web;
    using System.Web.Optimization;
    
    namespace UserGroupSPA
    {
        public class BundleConfig
        {
            // For more information on Bundling, visit http://go.microsoft.com/fwlink/?LinkId=254725
            public static void RegisterBundles(BundleCollection bundles)
            {
                bundles.IgnoreList.Ignore("*.intellisense.js");
                bundles.IgnoreList.Ignore("*-vsdoc.js");
    
                bundles.Add(
                            new ScriptBundle("~/scripts/UGScripts")
                            .Include("~/Scripts/jquery-{version}.js")
                            .Include("~/scripts/knockout-{version}.debug.js")
                            .Include("~/scripts/sammy-{version}.js")
                            .Include("~/scripts/toastr.js")
                            .Include("~/scripts/Q.js")
                            .Include("~/scripts/breeze.debug.js")
                            .Include("~/scripts/bootstrap.js")
                            .Include("~/scripts/moment.js")
                            );
    
                bundles.Add(
                            new StyleBundle("~/Content/css")
                    .Include("~/Content/ie10mobile.css")
                    .Include("~/Content/bootstrap.css")
                    .Include("~/Content/bootstrap-responsive.css")
                    .Include("~/Content/durandal.css")
                    .Include("~/Content/toastr.css")
                    .Include("~/Content/app.css")
    
                            );
    
            }
        }
    }

Work With Views as a SPA using Durandal

  1. UserGroupSPA\App directory (created by Durandal)
    1. Add the folders
      1. viewmodels
      2. views
    2. Add the javascript file main.js
      require.config({
          paths: { "text": "durandal/amd/text" }
      });
      
      define(['durandal/app', 'durandal/viewLocator', 'durandal/system', 'durandal/plugins/router'],
          function (app, viewLocator, system, router) {
      
             system.debug(true); // Outputs to the console the process, turn off for production
      
             app.start().then(function () {
                 toastr.options.positionClass = 'toast-bottom-right';
                 toastr.options.backgroundpositionClass = 'toast-bottom-right';
      
                 router.handleInvalidRoute = function (route, params) {
                     toastr.info('No Route Found: ' + route);
                 };
      
                 router.useConvention();
                 viewLocator.useConvention();
      
                 // Our three views
                 router.mapNav('home');
                 router.mapNav('speakers');
                 router.mapNav('events');
      
                 app.adaptToDevice(); // Touch devices to adapt to
      
                 app.setRoot('viewmodels/shell', 'entrance'); //Show the SPA at its root
             });
      
        });
  2. Views\DVSUG\index.cshtml changed to
    @using System.Web
    @using System.Web.Optimization
    <!DOCTYPE html>
    <html>
    <head>
        <title>Denver Visual Studio Users Group</title>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
        <meta name="apple-mobile-web-app-capable" content="yes" />
        <meta name="apple-mobile-web-app-status-bar-style" content="black" />
        <meta name="format-detection" content="telephone=no"/>
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    
        @Styles.Render("~/Content/css")
    </head>
    
        <body onload="toastr.info('Loading Main Body')">
    
            <div id="applicationHost">
            </div>
    
            @Scripts.Render("~/scripts/UGScripts")
    
            @if(HttpContext.Current.IsDebuggingEnabled) {
                <script type="text/javascript" src="~/App/durandal/amd/require.js" data-main="@Url.Content("~/App/main")"></script>
            } else 
            {
                <script type="text/javascript" src="~/App/main-built.js"></script>
            }
    
        </body>
    </html>
  3. App\viewmodels
    1. add event.js
      define(function () {
          var vm = {
              activate: activate,
              title: 'Events View'
          };
      
          return vm;
      
          function activate() {
              toastr.info('Events View Activated');
              return true;
          }
      });
    2. add home.js
      define(function () {
          var vm = {
              activate: activate,
              title: 'Home View'
          };
      
          return vm;
      
          function activate() {
              toastr.info('Home View Activated');
              return true;
          }
      });
    3. add shell.js
      define(['durandal/system', 'durandal/plugins/router'],
          function (system, router) {
              var shell = {
                  activate: activate,
                  router: router
              };
      
              return shell;
      
              function activate() {
                  return boot();
              }
      
              function boot() {
      
                  toastr.info('DVSUG Boot Loaded!');
                  return router.activate('home');
              }
      
          });
    4. add speakers.js
      define(function () {
          var vm = {
              activate: activate,
              title: 'Speakers View'
          };
      
          return vm;
      
          function activate() {
              toastr.info('Speakers View Activated');
              return true;
          }
      });
  4. App\views
    1. add events.html
      <section>
          <h2 class="page-title" data-bind="text: title"></h2>
      </section>
    2. add footer.html
      <nav class="navbar navbar-fixed-bottom">
          <div class="navbar-inner navbar-content-center">
              <span class="pull-left"><a href="http://omegacoder.com" target="_blank">OmegaCoder.com </a></span>
              <span class="pull-right"><a href="http://www.denvervisualstudio.net/" target="_blank">Denver Visual Studio User Group</a></span>
          </div>
      </nav>
    3. add home.html
      <section>
      
          <table>
              <tr><td><h2 class="page-title" data-bind="text: title"></h2></td></tr>
      
              <tr><td><h3>Next: Asp.Net SPA</h3></td></tr>
      
                    <tr><td><p>Come and find out all about it in this introduction to building Single Page Applications (SPA) which allow for rich client side interactions using JavaScript, HTML 5, and CSS in the ASP.NET world.</p>
                      <p>This introduction will familiarize you, the developer, to the templates available as well as an overview of the components which make up SPAs and how to put them together. This talk is a general how-to on being able to come up to speed on the technology and will focus on actually creating a page and cover the interactions of ASP.Net MVC with basic data transport.</p>
                      <p>You will see how ASP.NET Single-Page Applications (SPA) enable cutting-edge web developers to deliver rich, engaging web applications that surface information and interactivity in fresh and exciting new ways.</p>
            </td></tr>        
      
          </table>
      
      </section>
    4. add nav.html
      <nav class="navbar navbar-fixed-top">
          <div class="navbar-inner">
              <a class="brand" href="/">
                  <span class="title">Denver Visual Studio Users Group</span> 
              </a>
              <div class="btn-group" data-bind="foreach: router.visibleRoutes">
                  <a data-bind="css: { active: isActive }, attr: { href: hash }, text: name" 
                      class="btn btn-info" href="#"></a>
              </div>
      
          </div>
      </nav>
    5. add shell.html
      <div>
          <header>
              <!--ko compose: {view: 'nav'} --><!--/ko-->
          </header>
          <section id="content" class="main container-fluid">
              <!--ko compose: {model: router.activeItem, 
                  afterCompose: router.afterCompose, 
                  transition: 'entrance'} -->
              <!--/ko-->
          </section>
          <footer>
              <!--ko compose: {view: 'footer'} --><!--/ko-->
          </footer>
      </div>
    6. add speakers.html
      <section>
      
          <table>
              <tr><td><h2 class="page-title" data-bind="text: title"></h2></td></tr>
      
              <tr><td><h3>William Wegerson</h3></td></tr>
      
              <tr><td>
                      <p>William Wegerson is an Architect Developer who has been working here in Denver for over 20 years.</p>
                      <p>He has presented to the group before on such topics as Silverlight and Visual Studio releases (VS 2010 and 2012) as well as teaching labs to the members.</p>
                      <p>He has been awarded Microsoft MVP status since 2009 as a result of his community work such as this presentation as well as his blog and as an active resource on the MSDN forums and StackOverflow, answering questions of all types.</p>
             </td></tr>        
      
          </table>
      
      </section>
Share

Tags: , ,

Asp.Net C#: Upgrading Website to Latest Version Gotchas and How to Resolve

iStock_000015438998XSmallOne can get lost in the weeds when upgrading an asp.net .Net 1 website to anything from .Net 2 through .Net 4.  One of the biggest problems after the initial conversion is that when built each page or control throws a build error:

Could not load type ‘MyNamespace.myWebPage’.

The issue stems from the fact that things changed, made life easier for new projects, and namespaces which were required were removed and certain attributes changed. To resolve the above issue follow these steps presented in this article.

In the code behind file

  1. Remove the namespace scope. In the example below remove the highlighted lines:
    namespace MyNamespace
    {
        public class myWebPage : System.Web.UI.Page {}
    }
  2. Add the modifier partial to the class definition to make it look like this
    public partial class myWebPage : System.Web.UI.Page { ... }

In the aspx File

Which initially looks like this:

<%@ Page language="c#" AutoEventWireup="false"
                       Codebehind="myWebPage.aspx.cs"
                       Inherits="MyNamespace.myWebPage" %>
  1. Change the attribute Codebehind to CodeFile.
  2. Remove the namespace from the value found in the attribute Inherits.

The result should look like this:

<%@ Page language="c#" AutoEventWireup="false"
                       Codefile="myWebPage.aspx.cs"
                       Inherits="myWebPage" %>
Share

Tags: , ,

Asp.Net C# Creating an Excel Document From Data without using Office Interops

Excel It is a common misconception that one needs the office interops to create Excel documents for the user to download when dealing with Asp.net on a server. Well this article shows one how to create an Excel document from just the data at hand, say from Linq entities, without being tied to any control nor having to use office interops!

How Does one Send the Data to the User?

Here is the shell which will encompass the code which creates the document. Basically one uses the response class to send the data back to the user, say on a button click or some other relevant event. By specifying that this object will be a ms-excel file and it has an .xls extension, that is half the battle right there.

Response.Clear();
Response.Buffer      = true;
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader( "Content-Disposition", "attachment;filename=registrationData.xls" );
this.EnableViewState = false;

//  Code here to generate the xls document.
...

HttpContext.Current.Response.Write( /* String Buffer to Here */ );
HttpContext.Current.Response.End();

That was pretty easy to send the information to the user using a few C# classes which are globally exposed to the code-behind of our web page.

Generate an Excel document from Data in C#

Our goal is not to be tied to any control on the web page, though some controls such as the GridView have the ability to easily export a table which can be passed on. But for our purposes we want to simply extract the data from a linq query and generate the document. By keeping this example generic, one can adapt it to many different situations.

// We will be creating html on the fly via the
// string and html writers to create a table on the fly.
using ( StringWriter sw = new StringWriter() )
    using ( HtmlTextWriter htw = new HtmlTextWriter( sw ) )
    {
        //  Create a table to contain the grid
        Table table = new Table();

        //  Gridlines to box the cells
        table.GridLines = System.Web.UI.WebControls.GridLines.Both;

        // We are going to add the header row to the data first.
        List columns = new List() {
        "Sent", "Sent Date", "User Name", "Last Name", "First Name",
        "Work Phone", "Work Email",    "Number of Tickets", "Street Address 1",
        "Street Address 2",    "City", "State", "Zip Code" };

        // Each row will need to be declared upfront and cells added later.
        TableRow tRow = new TableRow();
        string value;

        foreach ( string name in columns )
            tRow.Cells.Add( new TableCell() { Text = name } );

        table.Rows.Add( tRow ); // Done! Header row added.


        // Note TableCell has a property BackColor. Once can set the
        // that within the cell such as BackColor = System.Drawing.Color.Blue
        // and that will carry into the Excel Document!

        // UserData is our Linq entity list and we will enumerate it to fill the into cells of the row
        // and subsequently into the table.
        foreach ( var usr in UserData )
        {
            tRow = new TableRow();

            value = ( usr.ticketsSent == null ) ? "N" : usr.ticketsSent.Value.ToString();
            tRow.Cells.Add( new TableCell() { Text = value } );

            value = ( usr.ticketsSentDate == null ) ? string.Empty : usr.ticketsSentDate.Value.ToShortDateString();

            tRow.Cells.Add( new TableCell() { Text = value } );
            tRow.Cells.Add( new TableCell() { Text = usr.userName } );
            tRow.Cells.Add( new TableCell() { Text = usr.lastName } );
            tRow.Cells.Add( new TableCell() { Text = usr.firstName } );
            tRow.Cells.Add( new TableCell() { Text = usr.workNumber } );
            tRow.Cells.Add( new TableCell() { Text = usr.workEmail } );
            tRow.Cells.Add( new TableCell() { Text = usr.ticketsRequested.Value.ToString() } );
            tRow.Cells.Add( new TableCell() { Text = usr.address1 } );
            tRow.Cells.Add( new TableCell() { Text = usr.address2 } );
            tRow.Cells.Add( new TableCell() { Text = usr.city } );
            tRow.Cells.Add( new TableCell() { Text = usr.state } );
            tRow.Cells.Add( new TableCell() { Text = usr.zipCode } );

            table.Rows.Add( tRow ); // We add each row to the table.
        }

        //  Translate/Render the table into the htmlwriter
        table.RenderControl( htw );

        //  Response needs the Htmlwriter
        HttpContext.Current.Response.Write( sw.ToString() );
        HttpContext.Current.Response.End();
       }

By simply creating a mock table we can load it and ship it out to the user as an automatic download.

Full Code

Response.Clear();
Response.Buffer = true;
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader( "Content-Disposition", "attachment;filename=registrationData.xls" );
this.EnableViewState = false;

using ( StringWriter sw = new StringWriter() )
    using ( HtmlTextWriter htw = new HtmlTextWriter( sw ) )
    {
        //  Create a table to contain the grid
        Table table = new Table();

        //  Gridline to box the cells
        table.GridLines = System.Web.UI.WebControls.GridLines.Both;

        List columns = new List() {
        "Sent", "Sent Date", "User Name", "Last Name", "First Name",
        "Work Phone", "Work Email",    "Number of Tickets", "Street Address 1",
        "Street Address 2",    "City", "State", "Zip Code" };

        TableRow tRow = new TableRow();
        string value;

        foreach ( string name in columns )
            tRow.Cells.Add( new TableCell() { Text = name } );

        table.Rows.Add( tRow );


        // BackColor = System.Drawing.Color.Blue
        foreach ( var usr in UserData )
        {
            tRow = new TableRow();

            value = ( usr.ticketsSent == null ) ? "N" : usr.ticketsSent.Value.ToString();
            tRow.Cells.Add( new TableCell() { Text = value } );

            value = ( usr.ticketsSentDate == null ) ? string.Empty : usr.ticketsSentDate.Value.ToShortDateString();

            tRow.Cells.Add( new TableCell() { Text = value } );
            tRow.Cells.Add( new TableCell() { Text = usr.userName } );
            tRow.Cells.Add( new TableCell() { Text = usr.lastName } );
            tRow.Cells.Add( new TableCell() { Text = usr.firstName } );
            tRow.Cells.Add( new TableCell() { Text = usr.workNumber } );
            tRow.Cells.Add( new TableCell() { Text = usr.workEmail } );
            tRow.Cells.Add( new TableCell() { Text = usr.ticketsRequested.Value.ToString() } );
            tRow.Cells.Add( new TableCell() { Text = usr.address1 } );
            tRow.Cells.Add( new TableCell() { Text = usr.address2 } );
            tRow.Cells.Add( new TableCell() { Text = usr.city } );
            tRow.Cells.Add( new TableCell() { Text = usr.state } );
            tRow.Cells.Add( new TableCell() { Text = usr.zipCode } );

            table.Rows.Add( tRow );
        }

        //  Htmlwriter into the table
        table.RenderControl( htw );

        //  Htmlwriter into the response
        HttpContext.Current.Response.Write( sw.ToString() );
        HttpContext.Current.Response.End();
   }
Share

Tags: ,

Tribal Knowledge: Asp.net ListView Template Which Contains a CheckBox. How to Get an ID from its OnChange Event in C#

TribalKnowledge

This article discusses the use of the attribute DataKeyNames of the ListView which can hold individual IDs for each row and how when using a CheckBox and processing an individual click, to get that info during the OnChange event. That ID is not directly supplied to the OnChange event as easily as done when directly working with ListView events. That ID, specific to the actual data is needed so an can update  of status can be sent to the target database item which it represents.

Setup

In setting up the ListView’s HTML I provide a quick example from a previous article here (Quick Asp.Net ListView Template). The item to take out of it is the property DataKeyNames.  For this article I have a Nationalities (USA, France, Argentina…) table which has two boolean fields of Archive and Exempt which are represented as checkboxes within each row of the ListView. The ListView will know that each row’s ID maps to the column NatID field which is the primary key id of the data item. Here is the html which specifies “NatID” as the id column in the data during the databind:

<asp:ListView ID="lvNationalities"
              DataKeyNames="NatID"
              runat="server"
              OnPagePropertiesChanged="UpdateNationalities"
              ItemPlaceholderID="PlaceHolder1">

In the code behind my dynamic Linq entity looks like this and the dynamic entity contains a NatID which is the items primary key id and it has our properties for the checkbox states for archived and exempt.

var natgeos = from nat in _gtdc.Nationalities
              select new
              {
                  NatID    = nat.Nationality_ID,
                  Archived = nat.Archived,
                  Exempt   = nat.Exempt,
                  Name     = nat.Text
              };

lvNationalities.DataSource = natgeos;
lvNationalities.DataBind();

So NatID is pulled from the database item as shown above. Visually we will have to CheckBoxes for Archived and Exempt as mentioned for the user to change. Each change needs to be handled by the checkbox and the database immediately updated.  Here is a screen shot:

NationalitiesListView

CheckBox

Below is the code which specifies the specific CheckBox event. Looking at the archive CheckBox we handle an OnCheckedChanged event:

<asp:CheckBox ID="cbArchived"
              runat="server"
              AutoPostBack="true"
              Checked='<%# Eval("Archived") %>'
              OnCheckedChanged="ArchiveChanged"
              Text="Archived"/>

Because we are not using the command methodology of the ListView, when we handle the event of the checkbox we don’t have direct access to which row data has been checked. To do that we will dereference some items which will get us to the NatID of row item which was clicked. Here is the code to do that:

protected void ArchiveChanged( object sender, EventArgs e )
{

CheckBox target = sender as CheckBox;

if ( target != null )
{
    ListViewDataItem di = target.NamingContainer as ListViewDataItem;

    if ( di != null )
    {
        int id = (int)lvNationalities.DataKeys[di.DataItemIndex]["NatID"];

        _gtdc = new GTCDataContext( Utilities.GetConnectionString() );

        var item = _gtdc.Nationalities.Where( it => it.Nationality_ID == id ).FirstOrDefault();

        if ( item != null )
        {
            item.Archived = target.Checked;
            _gtdc.SubmitChanges();
        }
    }
}

}

The first step is to convert the sender object to a CheckBox. Once that is successful we use the NamingContainer property off of the CheckBox. That property allows us to access the parent item which is the ListViewDataItem. That is our link back to the ListView. With that we can divine the ID needed from the ListViewDataItem’s index into the DataKeys cache for that row’s ID. Once gotten we can update the database as shown by setting the Archive attribute for the Nationalities for the user selected item.

Share

Tags: , ,

Quick Asp.Net ListView Template

I find that I seem to make the same Asp.Net ListView and internal table html code over and over. The below code contains that table where each row of data corresponds will be bound to each row of data in a database. Here is that template with blank values which will need to be filled in:

<asp:ListView ID="lvXXXXX"              
              DataKeyNames=""              
              runat="server"              
              ItemPlaceholderID="PlaceHolder1">
    <LayoutTemplate>    
        <table class="">        
            <thead>            
                <tr>                
                    <th>Header 1</th>            
                </tr>        
            </thead>        
            <tbody>
                <asp:PlaceHolder runat="server" ID="PlaceHolder1" />
            </tbody>    
        </table>
    </LayoutTemplate>
    <ItemTemplate>    
        <tr>        
            <td><asp:Label ID="lblYYYY"                
                     runat="server"                
                     Text='<%# Eval("") %>'/>        
            </td>    
        </tr>
    </ItemTemplate>
</asp:ListView>
Share

Tags: ,

Asp.Net DropDownList bound with Linq Data Example

I recently answered a post where the user was using ASP .Net 3.5 but not binding data to a DropDownList but instead using hard coded data to load the drop down in the HTML. So I created this quick example to show Linq-To-Xml (Linq) loading of an Asp.Net DropDownList and handling the automatic postback selection changes.

As mentioned example shows how to bind data to a dropdown list using Linq, specifically Linq-To-Xml, but you could use any other of the Linq methodologies because we are using the anonymous types to work with the needs of the DropDownList.

First we will place the Asp.Net DropDownListon our page along with a label which will used to show state changes.

<asp:DropDownList ID="ddlMain"
      runat="server"
      AutoPostBack="true"
      OnSelectedIndexChanged="SelectionMade" />

<asp:Label ID="lblWhat" runat="server"/>

Nothing earth shattering here, we have AutoPostBack because we want the control to tell our code behind on the server when a selection has been made. Following that we have the method which will be called for that event of SelectionMade.

The next thing is to load the DropDownList with values to choose from. We will use an XElement loaded dynamically to show how to do do this in Linq. The other thing of note is that we only want load this once, so we check the postback status. If its a postback, we do not reload.

protected void Page_Load( object sender, EventArgs e )
{

if ( Page.IsPostBack == false ) // Only do this once
{
   // Simulate an Linq-To-SQL call with an Linq-To-SQL
   // So anyone can use this demo.
   XElement dataForList
       = new XElement(
           "DropDownData",
             new XElement( "Node",
                 new XElement( "Text", "Selection 1"  ),
                 new XElement( "Data", "1Selection" ) ),
             new XElement( "Node",
                 new XElement( "Text", "Selection 2" ),
                 new XElement( "Data", "2Selection"  ) ));


   var toTheScreen = from x in dataForList.Descendants( "Node" )
                 select new
                 {
                     Text = x.Descendants( "Text" ).First().Value,
                     Value = x.Descendants( "Data" ).First().Value
                 };

    ddlMain.DataTextField = "Text";
    ddlMain.DataValueField = "Value";
    ddlMain.DataSource = toTheScreen;
    ddlMain.DataBind();
}

}

As shown above we work through all the elements named Node. For each of those nodes we will create a new entity with two properties Text and Value. Text will be shown to the user and value is what is associated with the selection. In the binding operations we specify the Text and Value field for the DropDownList to use and simply bind it to our anonymous projection.

Now all we have to do is handle the selection change event

protected void SelectionMade( object sender, EventArgs e )
{
    DropDownList target = sender as DropDownList;

    if ( target != null )
        lblWhat.Text =
            string.Format(
                "Item {0} selected with Value of {1}",
                target.SelectedItem.Text,
                target.SelectedValue );
}

Nothing magical here, we get the DropDownList from the sender argument, divine the selection and update the label. Here is what it should look like after a change:

ddl

Share

Tags: , , ,

ASP.NET Ajax C# Example: AutoCompleteExtender With Progress Indicator

Waiting

This article demonstrates in a step by step fashion how to use the Ajax Control Toolkit’s AutoCompleteExtender control with an animated gif ajax-loader progress indicator while the target dropdown of the AutoCompleteExtender is waiting to be loaded.

This article relies on the fact that you, the developer, already have the toolkit loaded and that a medium level of knowledge of Asp.net, C# and Visual Studio operations are understood. This targets VS2008 SP1, .Net/Asp.net 3.5 SP1,  Ajax Control Toolkit 3.0.20820.

Steps

  1. Create the  animated GIF which will be used. Go to the site AjaxLoad.Infowhere one can create animated loading gifs and download them for free. Use firefox to view the site because one can see the types of icons in the dropdown, on the site, where IE does not. Once done save your the icon to your project.
  2. The Ajax extender will need to call a webservice to get the data. Create a webservice (.asmx oldstyle type), in this example named AjaxServices.asmx. Within that service add, or uncomment out,  the following attribute declaration to allow the service to have communication from the page to the service in a scriptable manner.
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
    [System.Web.Script.Services.ScriptService]
    public class AjaxServices : System.Web.Services.WebService
    {
  3. Create a web method, the actual method name can be anything, but it must have the exactinput parameters and return value as shown below. Note we introduce a delay for this demonstration effect (highlighted line) you will not need to do that. Right. :-)
    [WebMethod]
    public string[] GetUsers( string prefixText, int count )
    {
        List<string> names
       = new List<string>()
        { "Alpha", "Beta", "Gamma", "Delta", "Omega" };
    
        // Fake delay to see the update gif
        System.Threading.Thread.Sleep( 5000 );
    
        return names.ToArray();
    }
  4. On the web page where the controls will be, add the asp:ScriptManager control. Within the manager we need to let it know our web service we have created and it will be using.
    <asp:ScriptManager ID="ScriptManager1"
        runat="server"
        EnablePartialRendering="true">
    
     <Services>
       <asp:ServiceReference Path="~/AjaxServices.asmx" />
     </Services>
    
    </asp:ScriptManager>
  5. Add three more controls, an asp.net textbox  the autoCompleteExtender and the image gif. Here are the controls all added. Note how the extender references the webservice and webmethod, the textbox and calls a javascript function which we will show in step 6. Change the MinimumPrefixLength to two or three if the data list is quite huge. in your system.
    <table>
    <tr>
        <td>User:&nbsp;&nbsp;</td>
        <td><asp:TextBox ID="tbUser" runat="server"></asp:TextBox></td>
        <td>&nbsp;</td>
        <td><img id="processing" style="visibility:hidden" src="ajax-loader.gif" /></td>
        <td>&nbsp;</td>
        <td><cc1:AutoCompleteExtender
       ID="AutoCompleteExtender1"
       runat="server"
       TargetControlID="tbUser"
       ServicePath="AjaxServices.asmx"
       ServiceMethod="GetUsers"
       MinimumPrefixLength="1"
       EnableCaching="true"
       CompletionSetCount="25"
       onclientpopulating="ShowIcon"
       onclientpopulated="ShowIcon"/>
        </td>
    </tr>
    </table>
  6. The image starts off hidden. We will write a javascript method, to swap its state.  Place the code on the page after the <Head> section. The code has to know the name of the img tag. The code should look like this:
<script language ="javascript">

function ShowIcon() {

    var e = document.getElementById("processing");

    e.style.visibility =  (e.style.visibility == 'visible') ? 'hidden' : 'visible';

}

</script>

That is it! When done and the extender calls the webservice the gif gets displayed and the user knows something is happening. When the processing is done the same javascript method is called to turn it off.

Note: If no data is found, the final hook call to onclientpopulated is not done and the icon will still be displayed. Possibly you can send back text like “No data found”, but that will be populated in the textbox and has its drawbacks. That is the monkey’s paw wish caveat of using this methodology.

Share

Tags: , , , ,

Asp.Net ListView: Linq Allows Creation of Dynamic Hyperlinks Example

(Update 03.28.2012 Cleaned up article and verified it  works with Asp.net versions 3.5 and 4.0)

The following ASP.Net article details how to create a ListView, bind it to a Linq query and create a dynamic list of hyperlinks to show on an Asp.net web page in C#. To recreate this, use Visual Studio (VS2008/VS2010/VS 11) and create a default Asp.Net Web Application project all working in the default page setup.

On the screen there will be a button which will cause a refresh to the page when pressed. On that refresh the ListView will be cleared of all data and the button disabled to show that the control has not been rebound to actual data.

Here is what it will look like on its first run with a button and dynamically created html links in a list.

Example showing button and dynamic links

HTML: which has the button and the ListView. We will hand create the LayoutTemplate and the ItemTemplate. Our goal is to have a list of links and dynamically create them. The ItemTemplate is expecting to be bound to Url field and UrlText which Linq will nicely create for us in the code behind.

<asp:Button ID="btnClear" runat="server" Text="Clear" /> 

<br /> 
<asp:ListView ID="lvPanelGroup1" runat="server">     
    <LayoutTemplate>         
        <div>             
            <ul>                 
                <asp:PlaceHolder runat="server" ID="itemPlaceholder" />             
            </ul>         
        </div>     
    </LayoutTemplate>     
    <ItemTemplate>         
        <li>             
            <asp:HyperLink ID="HyperLink1"                            
                           NavigateUrl='<%# Eval("Url") %>'                            
                           runat="server">
                <%# Eval("UrlText") %>
            </asp:HyperLink>         
        </li>     
    </ItemTemplate> 
</asp:ListView>

C#:The following is the code in the PageLoad. Its job is to either bind the data in the ListView using Linq or clear the ListView of all items and disable the control. Notice the Linq code where we create our object to have a Url field and UrlTextField which the ListView will use.

protected void Page_Load(object sender, EventArgs e) 
{ 
    if (IsPostBack == false) 
    {     
        List<string> Titles = new List<string>()        
            { "Title 1", "Title 2", "Title 3", "Fini"};     

        int index = 0;     

        var links = from item in Titles                 
                    select new                 
                            {                     
                                Url = "~Default.aspx?articleid=" + (++index).ToString(),                     
                                UrlText = item                 
                            };     
        lvPanelGroup1.DataSource = links;     
        lvPanelGroup1.DataBind();     
        btnClear.Enabled = true; 
    } 
    else // Clear the ListView 
    {     
        lvPanelGroup1.Items.Clear();     
        lvPanelGroup1.DataSource = null;     
        lvPanelGroup1.DataBind(); 

        // The rebinding will clear the ListView.     
        btnClear.Enabled = false; 
    } 
}

Here is what happens after a button press:

What happens after Clear is pressed.

Hope this helps those learning about the ListView and Linq.

Share

Tags: , , ,