Passing and Accessing DataBinder Container DataItems

When fielding a few questions on the ASP.Net Forums I ran across a question that I’d recently read about going through the ASP.Net 2.0 Wrox book. The question was how do I access the row values from a databound grid without having access to the original data source. The person then went on to ask whether they’d be able to pass the DataBinder class object to the code behind to have access to the static Eval() method for the entire row of data.

Normally in the markup you see most of the databound code examples will have a function that accepts an input value that is called from the markup, passed to the code-behind, and then the code behind will output a formatted value back to the markup. It works well for situations where you need to calculate values quickly without the original data source, or to quickly format values for display purposes on databinding the control to a datasource.

 

Passing a Single Eval DataItem

ASPX

<%# GetTotalValue(Eval("ColumnName")) %>

CS

protected int GetTotalValue(object total)
{
     int value = 0;

     int.TryParse(Convert.ToString(total), out value);

     return value;
}
 

In cases where multiple row values need to be accessible without having to pass each value directly one could simply access the databound row from the code-behind during the binding of the data control. In this case we still have the markup call to the code-behind as seen in the ASPX section below. This time we’re not passing any value(s), but instead we’ll just call them as we need them on the code-behind. Yes, it’s that simple. As you can see below we simply call to the DataBinder.Eval static function, pass in the data container (exposed by the Page,) and then simply supply the name of the column from the datasource we want. This is not limited to a single column, but only to a single row of data at a time.

 

Accessing Multiple DataItems 

ASPX

<%# GetTotalValue() %>

CS

protected int GetTotalValue()
{
      int value = 0;

      int.TryParse(Convert.ToString(DataBinder.Eval(Page.GetDataItem(), "ColumnName")), out value);

      return value;
}
 

The reason this is limited to a single row is that we’re only able to access these values during data binding event, which is indcated per the ‘<%#’ on the markup side indicating that this function will only be called when the form is binding. Each row will call the same function outputting the unique formatting of the columns or calculations being performed on the code-behind calls. There is no need to try to pass the DataBinder, pass the datacontainer, or anything of the sort because it’s already available to us. Now keep in mind that you can’t call the GetTotalValue() anytime you’d like as this function will only work during the the databound event of the control.

6. January 2009 13:14 by Rampidbyter | Comments (0) | Permalink

Windows Remote Desktop Port Number Changer

I was setting up my new laptop this morning and I then started to get into configuring port forwarding on my router. Because this computer is becoming another ad-hoc development machine i decided to add it to the list of PC's i have that are able to be used remotely. To do this i needed to change the default port from 3389 to a custom port number. I again went through the hassle of looking on-line for a site that had the registry path to the terminal services RDP port number setting. It was at this point that either my lazy bone or my uber programming sense kicked in and i made a quick utility to use whenever i need to set the port number again. Thus saving me the hassle of again looking up the registry path, and then skimming through the registry hive looking for the setting using RegEdit.

Here is the code to a quick Console application program i wrote that can be used through command line argument or via standard command line interface.

   1:  using System;
   2:  using Microsoft.Win32;
   3:   
   4:  namespace RemotePortChanger
   5:  {
   6:      class Program
   7:      {
   8:          static void Main(string[] args)
   9:          {
  10:              int portNumber = 3389;
  11:   
  12:              try
  13:              {
  14:                  if (args.Length > 0)
  15:                  {
  16:                      int.TryParse(args[0], out portNumber);
  17:   
  18:                      SetPort(portNumber);
  19:                  }
  20:                  else
  21:                  {
  22:                      string input = string.Empty;
  23:   
  24:                      Console.WriteLine("Remote Desktop Port: " + GetPort());
  25:                      Console.Write("Enter the new port number: ");
  26:                      
  27:                      input = Console.ReadLine();
  28:   
  29:                      int.TryParse(input, out portNumber);
  30:   
  31:                      SetPort(portNumber);
  32:   
  33:                      Console.WriteLine("Port is now " + GetPort() + " press any key to exit.");
  34:                      Console.Read();
  35:                  }
  36:              }
  37:              catch (Exception ex)
  38:              {
  39:                  Console.WriteLine("Error has occured - " + ex.Message);
  40:              }
  41:          }
  42:   
  43:          private static void SetPort(object portNumber)
  44:          {
  45:              RegistryKey key;
  46:   
  47:              key = Registry.LocalMachine;
  48:              key = key.OpenSubKey(@"System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp", true);
  49:              key.SetValue("PortNumber", portNumber);
  50:              key.Close();
  51:          }
  52:   
  53:          private static int GetPort()
  54:          {
  55:              RegistryKey key;
  56:              int portNumber = 0;
  57:   
  58:              key = Registry.LocalMachine;
  59:              key = key.OpenSubKey(@"System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp");
  60:              portNumber = Convert.ToInt32(key.GetValue("PortNumber"));
  61:   
  62:              return portNumber;
  63:          }
  64:      }
  65:  }
28. December 2008 16:44 by Rampidbyter | Comments (0) | Permalink

Microsoft JScript runtime error: 'document.body' is null or not an object

I was working on a project recently working on the master page of a .Net 2.0 Web Application and I encountered the most ambiguous error message. I was removing style sheet controls that were going to be added to a dynamic Page style mechanism when I first ran into the error. I had been going through the tags removing the trailing ASP control tags with the /> tag to end the control markup.

I did this on a JavaScript tag changing from this:

<script type="text/javascript" language="javascript" src="../scripts/vkboards.js”></script>

To this:

<script type="text/javascript" language="javascript" src="../scripts/vkboards.js"/>

Everything compiled fine but when I ran the project I kept getting this error message:

Microsoft JScript runtime error: 'document.body' is null or not an object.

Code Segment:

var _b=document.createElement("div");

var _c=document.createElement("div");

_b.style.visibility="hidden";

_b.style.position="absolute";

_b.style.fontSize="1px";

_c.style.height="0px";

_c.style.overflow="hidden";

document.body.appendChild(_b).appendChild(_c);

It was really strange and i took a look again at my code and the only thing I could think was that all the JavaScript included file gets inserted on the page rendering in-between where the beginning script markup and the end tag markup is located. I didn’t see this happening on the page markup when the exception was thrown, but that’s my best guess for now. If you’ve run into this error it’s easy enough to fix just add an ending tag, </script> in this case, and the exception will be diverted.

20. November 2008 07:07 by Administrator | Comments (0) | Permalink

ASP.Net Gridview using JavaScript Confirm("") dialog

I inherited an ASP.Net 2.0 web application project that was in desperate need of repair. One thing I quickly noticed was the amount of JavaScript scripts that were added on the Page_Load to the click event of LinkButton controls within a template column in a GridView control.

The scripts would add the JavaScript Confirm(“”) function to the click event of each control to prompt a user with a hard-coded message on whether to continue the action or cancel. The problem with this approach was that on clicking cancel the post-back would still occur and as a result the delete/edit/insert action would be performed. After spending what seemed like days trying to find the cause of the post-back and why even though the JavaScript function returned the value to the client click it would still carry on it’s server side action.

I searched and searched on the cause of this problem and found everything from creating a page level script to change the 0 and 1 to the respective true and false values that get returned from the JavaScript call. This did the exact same thing as just returning 1 or 0 based on the Ok or Cancel button selection. Nothing seemed to work and the grid wasn’t setup in any special way. That was until I found the ConfirmButtonExtender control as part of the AJAXToolkit.

After including a ConfirmButtonExtender within the template column with the control to validate set to my LinkButton did the JavaScript confirm dialog actually do what it was supposed to. Now when clicking on a LinkButton the confirm dialog appears, displays my ConfirmText property, and then based on the user action of clicking Ok or Cancel will actually stop the post-back from happening. Fantastic, the exact fix I was looking for, and it had the added advantage of exposing a control on the code-behind that could have the displayed confirmation text easily changed without having to consciously worry about JavaScript hooks to the client click event.

Now all I have to do is add my ConfirmButtonExtender to my TemplateField as such:

<asp:TemplateField HeaderText="Delete">
<ItemTemplate>                           
<asp:LinkButton ID="lbtndelete" runat="server" CommandName="Delete" Text="Delete" />
                           
<ajaxToolKit:ConfirmButtonExtender ID="cbeDelete" runat="server" TargetControlID="lbtndelete" />
                       
</ItemTemplate>
</asp:TemplateField>

On the GridView I can simply add an event handler for the OnRowDataBound event to programmatically assign my ConfirmText from say a Resource file or possibly other mechanism.

OnRowDataBound="GrvAdmin_RowDataBound"

protected void GrvAdmin_RowDataBound(object sender, GridViewRowEventArgs e)       
{
           
((AjaxControlToolkit.ConfirmButtonExtender)e.Row.FindControl("cbeDelete")).ConfirmText = Resources.Resource.CONFIRM_DELETE_USER;
}

15. October 2008 05:38 by Administrator | Comments (0) | Permalink

RDLC Main Report Error

Lately I’ve been getting a ton of traffic directed to my log here regarding RDLC main report invalid errors.

To simply put verify that the Microsoft ReportViewer control is installed on the server these reports are being deployed to. Microsoft article on ReportViewer control is located here: http://msdn.microsoft.com/en-us/library/ms251671(VS.80).aspx

You can also download the ReportViewer control for use on the production system from the link below.

http://go.microsoft.com/fwlink/?LinkId=49981

The reason for the ‘invalid main report’ error, that is terribly descriptive huh, is due to the lack of the ReportViewer on the deployed system. This can be caused by the lack of Visual Studios (VS) being installed on the machine, as VS automagically installs the ReportViewer dependencies onto the system, and at that point will make the RDLC reports function.

If I can help anyone with RDLC related questions please email me at rob at coderrob dot com. I would like to see what has brought people looking for this answer, or if there is any additional content I should post regarding RDLC.

9. July 2008 01:42 by Administrator | Comments (0) | Permalink

Execute SQL Stored Procedure within a Stored Procedure.

I know anyone who uses a SQL database, or maybe even MySQL does stored procedures at some point. I also know at some point they’re going to want to abstract stored procedures to reduce redundancy. Anyway, if you’re looking to call an existing stored procedure from within a stored procedure it’s as simple as this…

InsertCustomerAddress – stored procedure being built

. . .

@customerID    bigint,
@address1 varchar(120),
@address2 varchar(100) = NULL,

. . .

DECLARE @returnValue smallint

EXECUTE @returnValue = InsertAddress @ address1, @address2

INSERT INTO dbo.CustomerAddress
(
                CustomerID,
                AddressID
)
. . .

You see that I declared a value of @returnValue in the datatype smallint. From there I simply executed another stored procedure that returns the unique ID created by inserting a new Address record. From there I used that return address ID to insert into my customer address reference table along with the customers ID.

That seems to be about it. Just call the Execute function from within the stored procedure; you don’t necessarily need to set a value to capture the return value as many procedures may not return any values. Just call Execute with a space, the name of the stored procedure to call, and the parameters to pass in. It is possible to put the keyword ‘output’ next to each parameter whose values will be altered within the called procedure.

24. June 2008 19:50 by Administrator | Comments (0) | Permalink

Auto-Updater

After the last few releases of applications I’ve been creating for my client it became apparent that we were in need of a more automated process that could guarantee that each employee using the software was aware of, and was made to upgrade to the latest version. This came after a relatively small change to the program to pull more data from a database than trying to dynamically determine the information from disconnected data. The systems around here are a bit on the rustic side of the technology spectrum.

 

Anyway, we’re using Framework 1.1 and desktop deployments are not as user friendly as the ClickOnce of Framework 2.0. There are still the manual processes, and the limitations of not having proper system/network access being a lowly consultant. So, I decided I would write an auto-updating plug-in for the applications, but first I’d check to see what others have done in order to save myself time.

 

That’s when I came across an article by Peter A. Bromber, Ph.D., that addressed building a Framework 1.1 Automatic Application MSI Updater. Pretty swanky, so I decided I’d take a look at his code as obviously he’s run into problems similar to my own. After digesting everything that he had to offer my mouth was left with an unsatisfying flavor of, well, I could do better to say for short.

 

Article for reference: http://www.eggheadcafe.com/articles/20060213.asp

 

Seeing that I could not use a webservice, since I’m not allowed to access the main servers, I was left with a less dynamic alternative. I would just have to use the App.Config file to point my application to an Access database, don’t ask. The access database I’d model similar to Dr. Brombers, but with better column names.

 

I then crafted my own implementation of his code, I noticed early on his recursive lookup for the assembly version was pointless, and also decided to create a typed dataset to return my data values. So I present to you my own implementation, in the works, of the Framework 1.1 Auto-Updater. Of course it’s still in the works as I’m not particularly fond of the fact that while the new installer is running, if you’re installing into the same file directory the running application can not complete until the old application is closed. You are forced to hit the ‘continue’ button twice in order to force the installer to overwrite the running application who spawned the installer via a new process. Anyway, here is my updated code:

using System;
using System.Configuration;
using System.Data;
using System.Data.OleDb;
using System.Diagnostics;
using System.Reflection;
using System.Windows.Forms;
using ClientName;

namespace ClientName
{

/// <summary>
///
/// </summary>
public class AutoUpdater
{
private static OleDbConnection connUpgrade;

/// <summary>
/// Opens the Upgrade databases OLE DB connection.
/// </summary>
private static void OpenDbConnection()
{
string connString = string.Empty;

try
{
connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + ConfigurationSettings.AppSettings.Get("UpgradeDbPath");
connUpgrade =
new OleDbConnection(connString);
connUpgrade.Open();
}
catch(Exception err)
{
CloseDbConnection();
}
}


/// <summary>
/// Closes the Upgrade databases OLE DB connection.
/// </summary>
private static void CloseDbConnection()
{
if(connUpgrade != null)
{
if(connUpgrade.State != ConnectionState.Closed)
{
connUpgrade.Close();
connUpgrade.Dispose();
connUpgrade =
null;
}
}
}

/// <summary>
///
/// </summary>
/// <returns></returns>
public static bool CheckForUpdate()
{
bool result = false;
string appName = string.Empty;
string lastVersion = string.Empty;
string currentVersion = string.Empty;
string appExeName = string.Empty;
UpdateDataset.AppVersionsRow appRow = null;

try
{
// Get the current assemblies Product Name
appName = Assembly.GetEntryAssembly().GetName().Name;
appRow = GetAppVersionInfo(appName);

if(appRow != null)
{
lastVersion = Application.ProductVersion;

if
(appRow.CurrentVersion != lastVersion)
{
UpdateForm frmUpdate =
new UpdateForm();
frmUpdate.BringToFront();
frmUpdate.StartPosition = FormStartPosition.CenterScreen;
DialogResult dlgResult = frmUpdate.ShowDialog();

if (frmUpdate.UserAccept == true)
{
Process proc =
new Process();
proc.StartInfo.FileName = appRow.AppExeName;
proc.StartInfo.WorkingDirectory = appRow.InstallerPath;
proc.Start();
proc.WaitForExit();
Process.Start(Application.ExecutablePath);
Environment.Exit(0);
}
else if (dlgResult == DialogResult.Cancel)
{
result =
false;
}
}
}
}
catch(Exception err)
{
Environment.Exit(0);
}

return result;
}

/// <summary>
/// Gets the Application Version record for the supplied
/// application product name.
/// </summary>
/// <param name="appName"></param>
/// <returns></returns>
private static UpdateDataset.AppVersionsRow GetAppVersionInfo(string appName)
{
string sqlSelect = string.Empty;
UpdateDataset dsUpdate = null;
OleDbDataAdapter adapter = null;
OleDbParameter param = null;
UpdateDataset.AppVersionsRow appRow =
null;

try
{
dsUpdate =
new UpdateDataset();

sqlSelect = @"SELECT AppName, AppExeName, InstallerPath, CurrentVersion FROM AppVersions WHERE AppName = @appName";

OpenDbConnection();

adapter =
new OleDbDataAdapter(sqlSelect, connUpgrade);

param = new OleDbParameter("@appName", OleDbType.VarChar);
param.Value = appName;

adapter.SelectCommand.Parameters.Add(param);
adapter.Fill(dsUpdate.AppVersions);

CloseDbConnection();

appRow = dsUpdate.AppVersions.FindByAppName(appName);
}
catch(Exception err)
{
string message = err.Message;
}
finally
{
CloseDbConnection();
}

return appRow;
}
}
}

26. March 2008 00:48 by Rampidbyter | Comments (0) | Permalink

Wire vs .Net

Had an interesting talk today with the father in law of one of my good friends during his sons 3 year birthday party. The guy is a self employed microchip designer/developer who for the past thirty years has been selling his product. Up until recently he’d been releasing his product for the parallel port, but as we all know this port is going the way of the floppy disk. So in order to keep up with changes he started asking me what new technology he could use to interact with the USB port. Considering I’ve been reading “USB Design by Example” along with a few other choice USB books I gave him what I knew. We started talking about .Net, and to much my surprise he seemed pretty confused on why anyone would use .Net. We talked for a good three hours on current trends, what the .Net framework really was, and then voiced his opinions about how if you’re not programming on the wire then you’re leaving your code in a state where if it breaks you can’t fix it because you’re building on someone else’s stuff. It sounded like your typical embedded programmer trying to stay embedded in the opinion that reinventing the wheel was in the best interests of everyone as you can be sure that it will function correctly. I heard what he said, but I had my opposition that if everyone kept reinventing the wheel then productivity would be limited in either time or expertise of the developers. Still it’s hard telling who is right, and I sometimes wonder whether what the future of computing will hold. Either way it goes I feel like I took home a new perspective, and maybe I helped answer some of his questions.

26. January 2008 11:39 by Rampidbyter | Comments (1) | Permalink

Calendar

<<  January 2009  >>
MoTuWeThFrSaSu
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar

RecentPosts