Jon's Blog

.NET Development & More

ASP.NET AJAX Web Service Call

So I was working on a project where I needed to have some checkboxes in a GridView.  When checked they needed to update the underlying business object.  My first idea was the just wrap the whole thing in an UpdatePanel, but that would of course require a partial postback with the full contents of the grid being posted back to the server.  The better solution is to call a web service method to do the update.

First, add a new Web Service class to your project.  You need to add the [ScriptService] attribute to this class.  This attribute is from the System.Web.Script.Services namespace.  Then create your WebMethod, including whatever parameters you will need to pass in.

[WebMethod]
public void UpdateFlag(int id, bool isChecked)
{
// Logic to update business object
}

Next you need to add a ServiceReference that points to the web service you just created.  You can add this to your ScriptManager instance.  In my scenario the ScriptManager was in the Master page and I just wanted to include the ServiceReference in this one ASPX page.  Here you can use the ScripManagerProxy object like so (assuming the WebService file is in the same directory as the ASPX file):

<asp:ScriptManagerProxy ID="scriptManProxy" runat="server">
    <Services>
        <asp:ServiceReference Path="MyWebService.asmx" />
    </Services>
</asp:ScriptManagerProxy>

 

Then add the following code to your GridView's RowDataBound event.  This will set the onclick events for the individual checkboxes you are binding to the GridView.

if (e.Row.RowType == DataControlRowType.DataRow)
{
    BusinessObject obj = (BusinessObject)e.Row.DataItem;
    CheckBox myCB = (CheckBox)e.Row.FindControl("myCB");

    string eventText = string.Format("myCB_Checked({0}, this);", obj.SomeID);
    myCB.Attributes["onclick"] = eventText;
}

 

Now you need to actually write the JavaScript method that will call your web service.  Here it is:

<script type="text/javascript">
    function myCB_Checked(id, ctrl) {
        var isChecked = ctrl.checked;
        Namespace.MyWebService.UpdateFlag(id, isChecked);
    }
</script>

 

Make sure that you use the fully qualified name of your class here. 

ASP.NET: Add New Error Message to Validation Summary Control

You can use this method to add a new error to an existing validation summary control from your code-behind page.  Don't forget to use the proper ValidationGroup that your validation summary is using.

protected void AddErrorToValidationSummary(string errorMessage)
{
CustomValidator custVal = new CustomValidator();
custVal.IsValid = false;
custVal.ErrorMessage = errorMessage;
custVal.EnableClientScript = false;
custVal.Display = ValidatorDisplay.None;
custVal.ValidationGroup = "MyValidationGroup";
this.Page.Form.Controls.Add(custVal);
}

That Pesky Enter Key: JavaScript to the Rescue

OK, this solution was put together Frankenstein style from multiple sources.  Basically I wanted to only allow the user to use the Enter key in specific circumstances.  If they were typing their query in the search box, for example.  This solution uses a combination of JavaScript and the ASP.NET Panel control.  The following JavaScript is placed in the MasterPage:

<script type="text/javascript">
 var allowEnterKey = false;
 window.document.onkeydown = CheckEnter;

 function CheckEnter()
 {
  var keyID = (window.event) ? event.keyCode : e.keyCode;

  if (!allowEnterKey && keyID == 13)
   return false;
  else
   return true;
 }
</script> 

 

Then my search box (or whatever) can be wrapped in a Panel control like so:

<asp:Panel ID="pnlSearch" runat="server" DefaultButton="btnSearch">
    <div id="SearchDiv">
        <asp:TextBox ID="txtSearch" runat="server" Columns="60" 
            onfocus="allowEnterKey=true" onblur="allowEnterKey=false" />
        <asp:Button ID="btnSearch" runat="server" Text="Search" 
            onclick="btnSearch_Click" onfocus="allowEnterKey=true" onblur="allowEnterKey=false" />
    </div>
</asp:Panel>

 

Notice the DefaultButton property set on the Panel as well as the onfocus and oblur properties of the TextBox.

AJAX Control Toolkit: Strange CSS Bug with HTML Editor control and IE 8

Today I was adding the new HTML Editor control (newly added to the AJAX Control Toolkit) to an Intranet page.  Whenever I would mouse click into the HTML Editor it would continue to expand.  This would only occur in IE 8.  When using Firefox or IE 8 in compatibility mode it wouldn't happen.  I tracked it down to the following declaration in my CSS file:

 .white td
{
    padding: 3px;
}

I removed this declaration and instead used the cellpadding attribute for the table.  This solved the issue.  Very strange.

Visual Studio: Build failed due to validation errors in dbml file

Today, while attempting to build a class library on our build box I received the following error in Visual Studio 2008:

"Build failed due to validation errors in [FileName].dbml.  Open the file and resolve the issues in the Error List, then try rebuilding the project."

However, when I went to the dbml file no errors were shown in the error list.  To resolve this I deleted the .designer.cs file associated with the dbml file.  Then in Solution Explorer I right-clicked on the dbml file and selected "Run Custom Tool."  This regenerated the .cs file and I was then able to see the error, which was the following:

"DBML1005: Mapping between DbType 'Date' and Type 'System.DateTime' in Column '[ColumnName]' of Type '[TypeName]' is not supported."

This was easy enough to fix.  The Server Data Type just needed to be changed to DateTime.  Strangely enough having just Date on my development machine did not break the build.

I believed the root of the problem may be that the version of Visual Studio on my development machine was 9.0.30729.1 SP and the build machine was 9.0.21022.8 RTM.

LINQ, Visual Studio, and Stored Procedure Mapping

So the other day while attempting to drag a stored procedure onto the LINQ Designer in Visual Studio I received the following error:

VS_LINQ_Proc_Error

The stored procedure was rather complex including a call to FREETEXT and for some reason the LINQ Designer would not accept it, so I manually mapped the stored procedure for the DataContext.  For future reference, here is some sample code:

public partial class MyDataContext
{
[Function(Name = "dbo.MyStoredProc")]
public ISingleResult<MyClass> MyProcName(
[Parameter(Name = "Parameter1")] int? parameter1,
[Parameter(Name = "Parameter2")] ProductCategory? parameter2,
[Parameter(Name = "Parameter3")] bool? parameter3)
{
IExecuteResult result = this.ExecuteMethodCall(this,
((MethodInfo)(MethodInfo.GetCurrentMethod())),
parameter1, parameter2, parameter3);

return ((ISingleResult<MyClass>)(result.ReturnValue));
}
}

 

Then you can call the stored procedure in code like so:

var results = myDC.MyProcName(parameter1, parameter2, parameter3);

My Selfish Blog

I don't expect anyone will read this blog.  It is being created for completely selfish reasons.  As a Web developer I frequently run into issues that require research in order to solve.  I hope to document my findings here, so that I can return to them as needed.  Who knows, maybe I'll even blog about other things too.  We shall see...