Author Archive

Selecting An Old Value While Binding a DropDownList

I had a usual instance where a DropDownList was bound to a table in a database. However, that list of data could change in the database without regard to those values having been previously stored (as text, not IDs, unfortunately) in another table. Meaning that when the DropDownList would now be loaded with the newly updated data, the previously selected value would not have a corresponding choice in the drop down anymore.

The DropDownList doesn’t take too kindly to this and gives an ArgumentOutOfRangeException error. But I needed that old value as a possible choice in the dropdown still, as well as the new choices.

The problem was that I needed to get the saved value from the database (which failed to be the initial SelectedValue). So I just stored it in the ToolTip for the DropDownList, then I could retrieve it and update it from anywhere.

Note: Be sure to use OnDataBinding not OnDataBound to add the new item.

<asp:DropDownList ID=”HotelNameDropDown” runat=”Server” DataSourceID=”ObjectDataSource1″

SelectedValue=’<%# Bind(“HotelName”) %> AppendDataBoundItems=”true”

OnDataBinding=”HotelNameDropDown_OnDataBinding” ToolTip=’<%# Bind(“HotelName”) %>

OnSelectedIndexChanged=”HotelNameDropDown_OnSelectedIndexChanged”

DataTextField=”HotelName” DataValueField=”HotelName” />

Depending on when you postback, you might also need to update the ToolTip when the user changes the DropDownList.

protected void HotelNameDropDown_OnSelectedIndexChanged(object sender, EventArgs e)

{

// Set the tooltip to the selected value onchange, becuase we will use the tooltip below

DropDownList ddl = (DropDownList)sender;

ddl.ToolTip = ddl.SelectedValue;

}

Here I try to bind the DropDownList with the data, if this fails then it creates a new ListItem at the top of the list with a name and value of what we had stored in the ToolTip from the .aspx page.

protected void HotelNameDropDown_OnDataBinding(object sender, EventArgs e)

{

DropDownList ddl = (DropDownList)sender;

ddl.DataBinding -= new EventHandler(HotelNameDropDown_OnDataBinding);

try

{

ddl.AppendDataBoundItems = false;

ddl.DataBind();

ddl.SelectedValue = ddl.ToolTip;

}

catch(ArgumentOutOfRangeException)

{

ddl.Items.Clear();

ddl.AppendDataBoundItems = true;

ListItem li = new ListItem(ddl.ToolTip, ddl.ToolTip);

li.Selected = true;

ddl.Items.Insert(0, li);

}

}

More info about this topic can be found here:

http://www.jeffgaroutte.net/post/2008/07/09/The-DropDownList2c-the-DataBind-and-the-Missing-Value.aspx

Dynamically Loading External Controls from a DropDownList

Displaying a specific web user control (.ascx) from a dropdown selection is a fairly straightforward process.

Create an asp:DropDownList with OnSelectedIndexChanged set to a function. This function will load a user control file based on the selected value of the dropdown. Also, create an asp:PlaceHolder where the control will be placed.

 

       <asp:DropDownList ID=”ddDataTables” runat=”server” AutoPostBack=”true”

OnSelectedIndexChanged=”ddDataTables_Changed” >

         <asp:ListItem Text=”" Value=”"></asp:ListItem>

         <asp:ListItem Text=”More Options” Value=”more_options”></asp:ListItem>

         <asp:ListItem Text=”Address” Value=”address”></asp:ListItem>

 

    <asp:PlaceHolder ID=”phDataTable” EnableViewState=”false” runat=”server” />  

 

And the code behind file looks for a file which is named the same as the selected value (e.g. address.ascx), then adds it to the place holder in the aspx file.

 

    protected void ddDataTables_Changed(object sender, EventArgs e)

    {

        LoadUserControl(ddDataTables.SelectedValue);

    }

   

    protected void LoadUserControl(string strSelectedTable)

    {

        phDataTable.Controls.Clear();

 

        if (strSelectedTable != “”)

        {

            UserControl ucDataTable = (UserControl)LoadControl(strSelectedTable + “.ascx”);

            phDataTable.Controls.Add(ucDataTable);

        }

    }

 

That’s it. A simple way to keep functionality separated in web user controls but be able to still pull them in cleanly when desired.

 

Triggering a Specific GridView Row Command When Page Loads

I have an asp.net page with a gridview and each row uses a TemplateField to make a LinkButton to select the row. In my case, the action of clicking the text link triggers a FormView to appear in order to edit the data.

 

I needed a way to open the editing form automatically for the first item in the gridview when the page loads. After using combinations of different .NET page events (Page_Render(), Page_Unload(), etc.), I found myself going around and around because I was never at the right point in the execution order for getting the data bound , knowing the correct CommandArgument and having access to all the data in the row at the same time. I was setting session variables and checking IsPostBack and it was becoming more complicated than it seemed like it needed to be.

 

It was time to rethink the whole issue. I ended up writing 1 line of javascript with a little prep C# code which finds the correct LinkButton, transforms its .NET generated ID into something useful, and then stores it for the javascript to use. The javascript executes a postback after the page loads so it mimics a user clicking on the “Edit” link, just like I wanted.

 

The code for the edit link as a column in my gridview:

 

<asp:TemplateField ShowHeader=”False”>

<ItemTemplate>

<asp:LinkButton ID=”LinkButtonSelect” runat=”server” CausesValidation=”False”

                CommandName=”Select” Text=”EDIT”

    CommandArgument=’<%# Bind(“ID”)%>‘>

</asp:LinkButton>

</ItemTemplate>

</asp:TemplateField>

 

In my C# code I check if there are any rows in my grid before I attempt to postback on anything and I’m choosing row 0 because I want the first row. The parameter for __doPostBack needs to have dollar signs instead of underscores like the ID has, so I replace them accordingly.

 

At the bottom of my.aspx page I have this javascript code (which could also be added into the onload event):

 

<script type=”text/javascript”>

 

<%

    // Get and format the the ID of the Edit link in the first row

    if (GridView1.Rows.Count > 0)

    {

        LinkButton lnkEdit = (LinkButton)GridView1.Rows[0].FindControl(“LinkButtonSelect”);

        string strEditID = lnkEdit.ClientID.ToString().Replace(“_”,“$”);

%>

         // trigger a postback like someone clicked “Edit”

         __doPostBack(‘<%= strEditID %>’, );

 

<%

    }

%>

 

</script>

 

So in the end, the javascript line has the same value as the href attribute that is generated for the LinkButton. View the source code of your page and check it out!

Display a Nested List Inside Another Repeater

A simple way to display a list of data is to use an asp:Repeater. If the data also needs to show a nested list of related data for each main item, one can place another Repeater inside the first. In the code behind, the queries used for each Repeater can be linked in a dataset as a parent-child relationship via a Data Relation.

In the example below we make the multiple queries in only one SQL command statement, then link the result tables together by making a new DataRelation. The link uses key and foreign key ID columns from each result set.

This C# example shows how you can have a list of phone numbers as an area inside a larger list of contacts.

             In the Page_Load function…
             …

        // Create and fill a DataSet
SqlDataAdapter myCommand = new SqlDataAdapter(

            "SELECT DISTINCT MemberID, Address, FirstName, LastName " +
            " FROM MemberNames M; " +

            "SELECT MemID, phonetype, Number " +
            " FROM MemberNames M " +
            " INNER JOIN Phone P ON M.MemberID = P.MemID;" +
             , myConnection);

         DataSet ds = new DataSet();
        myCommand.Fill(ds);

         // Relate the two tables from the query together
        ds.Relations.Add(new DataRelation("MemberID_Phone", ds.Tables[0].Columns["MemberID"], ds.Tables[1].Columns["MemID"]));

        // Bind the outer Repeater to the DataSet.
        rptMember.DataSource = ds.Tables[0];
        rptMember.DataBind();

 When we bind the data for each item in the outer Repeater, we will create a child view using the relation we linked previously.

     protected void rptMember_ItemDataBound(object sender, RepeaterItemEventArgs e)
    {
        DataRowView drv = e.Item.DataItem as DataRowView;
         Repeater rptPhone = e.Item.FindControl("rptPhone") as Repeater;

        rptPhone.DataSource = drv.CreateChildView("MemberID_Phone");
        rptPhone.DataBind();
    }

 This snippet from the .aspx files shows the nested repeaters.

<asp:Repeater id="rptMember" OnItemDataBound="rptMember_ItemDataBound" runat="server">

         <ItemTemplate>

          <!– Tags to display the bound data (name, address, etc.) –>  

          <!– Make a repeater for all phone numbers for each person –>

            <asp:Repeater id="rptPhone" runat="server">
              <ItemTemplate>
                <%# DataBinder.Eval(Container.DataItem, "PhoneType")%>:
                <%# DataBinder.Eval(Container.DataItem, "Number")%>

              </ItemTemplate>
            </asp:Repeater>

            …

 To sum it all up, we implemented several technical elements here. 

  • Nested Repeaters
  • Using a multi-result query
  • Using DataSet Relations

 Our example displays a list of Contacts with a sub-list for multiple phone numbers.

Importing Mixed ZIP Codes into SQL Server from Excel

I had a spreadsheet with tens of thousands of mailing addresses. One of the columns was  the ZIP code for each address row.  Some of those ZIP codes were in the ZIP + 4 format (12345-6789) and others were not.  Those others were 3, 4 or 5 digit numbers.  When the data was put into the spreadsheet, Excel removed the leading zeroes from some ZIP codes (like “00345” truncated to “345”).

I used the Import functionality in SQL Server Management Studio 2005 to put the data from the Excel spreadsheet into a table.  Without modifying the spreadsheet data the import would place a NULL into each row that had a 3,4 or 5 digit ZIP code, while keeping the ZIP + 4 codes correctly.

To get both “5-Digit” and “Zip Plus Four” ZIP codes into the same database column I needed to make Excel see them as text. To do this I made a new column next to my ZIP Codes with this style of formula:                =TEXT(B2,”00000″)

zipcode-excel-as-text

This causes the data to have at least 5 digits and leading zeroes if less than five  digits. Next I copied this new column and then used “Paste Special” with the “Values” option to replace my original ZIP code column. Saving the spreadsheet and executing a SQL Server import of the XLS file, all ZIP codes were then correct.

zipcode-excel-paste-special

I also found that using the “Format Cells” functionality with the Special “Zip Code” setting only changes how the data appears. It does not change the underlying data. For example “345” shows as “00345” but if you look at the actual data, it remains unchanged. So just doing Excel formating did not work when importing in to a SQL Server database.

zipcode-excel-formatted

Using A Data Container Column as an Inline IF Condition

I find myself using .net data containers in many web applications.  Binding controls such as asp:Repeater and asp:DataList to data sources can make displaying your data more manageable.  In a few of those instances I need to have some of the data display in a little different manner depending on that particular info.

For example, a “sold” image could be shown if the status of a data item warrants it.  If the status is anything else no extra HTML is rendered.

<%# (DataBinder.Eval(Container.DataItem, "Status").ToString() == "Sold") ?
<img src='/images/sold.gif' />" : "" %>

Instead of making a server-side control in my .aspx page then having my code behind find it in some sort of databound function, I find it cleaner to use an inline C# IF statement for simple display changes such as these.

In the sample code below, we are making an anchor link. The data in the “Type” column from the database describes if the data is a URL or an email address.  Our inline IF statement has this structure:

If the Type equals “Website” then add nothing to the data.  Otherwise, the data is an email address, so make a “mailto:” link out if it.

<asp:Repeater id="rptAddress" runat="server">
<ItemTemplate>

<a href="<%# (DataBinder.Eval(Container.DataItem, "Type").ToString() == "Website") ?
 "" : "mailto:" %>   <%# DataBinder.Eval(Container.DataItem, "Address")%>" >
<%# DataBinder.Eval(Container.DataItem, "Address")%>
</a>
</ItemTemplate>
</asp:Repeater>
Just remember, the C# syntax for an inline If uses the question mark and a colon:
<% (condition) ? "true" : "false" %>

Saving Web Contact Info to a Downloadable Spreadsheet

Usually a website owner has the data from their contact forms emailed to them.  But sometimes it can be useful for the site to automatically add that info to an ongoing list of contacts.  One way that most people like to be able to see and sort such data is in a spreadsheet.  It is quite easy to make a “fake” spreadsheet using an html table that Excel will open like any other .xls file.

 

Here are the basic steps:

  • Create and save a “spreadsheet” which defines the header row
  • Upon each contact form submittal, write an html row to that file 

Read the rest of this entry »

sql transactions in c# .net

I recently needed to update an existing C# solution of multiple projects to add transactions around two different data updates.  I wanted to have this pattern for each one:

 

  • Start transaction
  • Delete all existing data
  • Insert all new data
  • Commit transaction

Read the rest of this entry »