Friday, 9 November 2007

A CheckBoxListValidator By ME!!!!!



I had a requirement for such on a project I am doing and searching through the NET revealed few, and those that came up were not good at all. You may not find this any good, but I can tell you that it works, and that is good enough for me lol. Any bugs or hiccups you may find please be so kind as to leave a comment. Even better ROB it off me, correct it and pass it off as your own lol.





OK so the class which inherits from the base validator is as follows:




using System;
using System.Data;
using System.Configuration;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace MyNamespace.CheckBoxListValidator
{
public class CheckBoxListValidator : BaseValidator
{
public Int16 MinimumNumberOfSelections
{
get
{
object o = ViewState["MinimumNumberOfSelections"];
if (o == null)
return 0;
return (Int16)ViewState["MinimumNumberOfSelections"];
}
set
{
ViewState["MinimumNumberOfSelections"] = value;
}
}
protected override bool ControlPropertiesValid()
{
return true;
}
protected override bool EvaluateIsValid()
{
CheckBoxList cbl = (CheckBoxList)FindControl(ControlToValidate);
if (cbl == null)
throw new Exception("cbl is null");
if (MinimumNumberOfSelections == 0)
{
foreach (ListItem li in cbl.Items)
{
if (li.Selected)
return true;
}
return false;
}
else
{
int noSelected = 0;
foreach (ListItem li in cbl.Items)
{
if (li.Selected)
noSelected++;
}
if (noSelected >= MinimumNumberOfSelections)
return true;
else
return false;
}
}
protected bool EvaluateIsChecked()
{

CheckBoxList _cbl = ((CheckBoxList)this.FindControl(this.ControlToValidate));

foreach (ListItem li in _cbl.Items)
{

if (li.Selected == true)
{

return true;

}

}
return false;

}

protected override void OnPreRender(EventArgs e)
{

if (this.EnableClientScript) { this.ClientScript(); }
base.OnPreRender(e);

}

protected void ClientScript()
{
this.Attributes["evaluationfunction"] = "cblv_clientVal";

StringBuilder validationScript = new StringBuilder();
if (MinimumNumberOfSelections == 0)
{
validationScript.AppendLine("function cblv_clientVal(val)");
validationScript.AppendLine("{");
validationScript.AppendFormat("var controlToValidate = document.getElementById('{0}').controltovalidate;", this.ClientID);
validationScript.AppendLine("var controlToValidate = document.getElementById(controlToValidate);");
validationScript.AppendLine("for(var i = 0; i < controlToValidate.getElementsByTagName(\"INPUT\").length;i++)");
validationScript.AppendLine("{");
validationScript.AppendLine(" var currentItem = controlToValidate.getElementsByTagName(\"INPUT\")[i];");
validationScript.AppendLine(" if(currentItem.type == \"checkbox\" && currentItem.checked)");
validationScript.AppendLine(" return true;");
validationScript.AppendLine("}");
validationScript.AppendLine("return false;");
validationScript.AppendLine("}");
}
else
{
validationScript.AppendLine("function cblv_clientVal(val)");
validationScript.AppendLine("{");
validationScript.AppendFormat("var controlToValidate = document.getElementById('{0}').controltovalidate;", this.ClientID);
validationScript.AppendLine();
validationScript.AppendLine("var controlToValidate = document.getElementById(controlToValidate);");
validationScript.AppendFormat("var currentCount = 0, targetCount = {0}", MinimumNumberOfSelections.ToString());
validationScript.AppendLine();
validationScript.AppendLine("for(var i = 0; i < controlToValidate.getElementsByTagName(\"INPUT\").length;i++)");
validationScript.AppendLine("{");
validationScript.AppendLine(" var currentItem = controlToValidate.getElementsByTagName(\"INPUT\")[i];");
validationScript.AppendLine(" if(currentItem.type == \"checkbox\" && currentItem.checked)");
validationScript.AppendLine(" {");
validationScript.AppendLine(" currentCount++;");
validationScript.AppendLine(" }");
validationScript.AppendLine("}");
validationScript.AppendLine(" if(currentCount >= targetCount)");
validationScript.AppendLine(" {");
validationScript.AppendLine(" return true;");
validationScript.AppendLine(" }else{");
validationScript.AppendLine(" return false;");
validationScript.AppendLine(" }");
validationScript.AppendLine("}");
}

this.Page.ClientScript.RegisterClientScriptBlock(typeof(string), "CheckBoxValidationScript", validationScript.ToString(), true);

}

}
}




To test this simply create a class in your App_Code folder and paste this in. To enable it so you can add it in, go into your web config in the system.web section and add the following. Called the TagPrefix whatever you want, make your the namespace ties in though



<pages>



<controls>



<add tagPrefix="aebs" namespace="MyNamespace.CheckBoxListValidator"/>



</controls>



</pages>






Finally below I have done two examples of it in action. One uses a property I have added called MinimumNumberOfSelections and the other doesn't. That simply means if you need the user to select more than one then this work.





With the MinimumNumberOfSelections included



<form id="form1" runat="server">



<div>



<aebs:CheckBoxListValidator ID="CheckBoxListVal1" runat="server" MinimumNumberOfSelections="2" ControlToValidate="CheckBoxList1" ErrorMessage="Please select at least one check item" Display="Dynamic" EnableClientScript="true"></aebs:CheckBoxListValidator>



<asp:CheckBoxList ID="CheckBoxList1" runat="server">



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



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



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



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



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



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



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



</asp:CheckBoxList>



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



</div>



</form>






WithOUT the MinimumNumberOfSelections included



<form id="form1" runat="server">



<div>



<aebs:CheckBoxListValidator ID="CheckBoxListVal1" runat="server" ControlToValidate="CheckBoxList1" ErrorMessage="Please select at least one check item" Display="Dynamic" EnableClientScript="true"></aebs:CheckBoxListValidator>



<asp:CheckBoxList ID="CheckBoxList1" runat="server">



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



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



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



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



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



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



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



</asp:CheckBoxList>



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



</div>



</form>



Tuesday, 30 October 2007

ASP.NET DropDownList Appending Data Items

I am making a short post about this because I see so many questions and get asked so many times about this. When you have a databound DropDownList you will probably require an option which asks for the users selection.

A lot of the time people will use some code if not a postback and insert the items manually like so:


protected void Page_Load(object sender, EventArgs e)

{

if (!IsPostBack)

{

ddlProfBody1.Items.Insert(0, new ListItem("Please Select", "0"));

}

}

BUT, I use the following to reduce code in the UI Layer:

<asp:DropDownList ID="ddlProfBody5" runat="server" DataSourceID="ProfBodyDS" DataTextField="Field1" DataValueField="Field0" AppendDataBoundItems="true">

<asp:ListItem Text="Please Select" Value="0">asp:ListItem>

:DropDownList>


What happens now is simply that instead of replacing any core items that were hardcoded, it does as the paramter suggests and appends additional items onto the drop downlist.

Tuesday, 18 September 2007

Combining Transactions with Strongly Typed DataSets

I was thinking down the lines of using a transactionScope to achieve what I wanted but it just did not fit my needs. In my projects I create a presentation layer, a Business Object Layer and also a Data Access Layer which is a Strongly Typed DataSet.

In some procedures I need to make three different updates using different table adapters and if one fails say the last, I don't really want the other data to have worked. I want everything to have worked or nothing.

The solution I found to it was here: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=237800&SiteID=1

All I want to do here is give you a C# version of it which I have done and which also solved my problem. Here is the code:


public void AssignTransaction(ref System.Data.SqlClient.SqlTransaction transaction)
{
Adapter.InsertCommand.Transaction = transaction;
Adapter.InsertCommand.Connection = transaction.Connection;
Adapter.UpdateCommand.Transaction = transaction;
Adapter.UpdateCommand.Connection = transaction.Connection;
Adapter.DeleteCommand.Transaction = transaction;
Adapter.DeleteCommand.Connection = transaction.Connection;
}

We pass in the transaction by reference so all use the same copy of the object and in turn committing all the actions to one transaction.

One donwside I see to this is the following. Adapter is private, and also, every times your dataset changes your code disappears, as it recompiles its own code, thus losing yours. And going back to this, the way is simple.

Add a codefile to your project and add the relevant namespace which your TableAdapter resides inside. You then extend the partial class inside this code file to give you the extra functionality. e.g.

namespace DatasetTableAdapters
{
public partial class TableAdapter
{
public void AssignTransaction(ref System.Data.SqlClient.SqlTransaction transaction)
{
Adapter.InsertCommand.Transaction = transaction;
Adapter.InsertCommand.Connection = transaction.Connection;
Adapter.UpdateCommand.Transaction = transaction;
Adapter.UpdateCommand.Connection = transaction.Connection;
Adapter.DeleteCommand.Transaction = transaction;
Adapter.DeleteCommand.Connection = transaction.Connection;
}
}
}

Thursday, 13 September 2007

Cross Thread Safety with anonymous methods

When working with multithreading and async operations you will no doubt get a message that you have tried to execute a cross thread operation which is not allowed. Times like this I would make a delagte reflection of the method I wish to use, and then invoke the target control, passing in the arguments the function requires.

A little easier way which requires only one delegate is the following. Create you delegate for example:


private delegate void InvokeDel();

Then in my sample project for example, I have a small network app and when a client connects I add the remote end point or IPAddress:PortNo to the list view. Because I am doing this with Async this needs to be cross thread safe so I did the following:



private void AddClient(Socket _client)
{

this.Invoke(new InvokeDel(delegate()
{
listView1.Items.Add(new ListViewItem(new string[] { _client.RemoteEndPoint.ToString(), _client.SocketType.ToString() }));
}));
}

This works find and uses anonymous methods.

Tuesday, 4 September 2007

ADO.NET & "Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints."

I realise you may find other solutions for this on other blogposts but I feel I have out a bit more how to debug this very unhelpgul error. Yes it does involve check the DataTable or DataRow HasErrors. If true you then drill down the the Rows in Error and further to the columns in error through the row.

When I was debuging a certain block of my code I founf that the HasErrors did not trigger if I tried to populate my DataTable with the GetDataBy() method. BTW I am using Strongly Typed Datasets here. So for example, I declared a datatable at the top of the code:


private YourDataset.EmployeesDataTable EmployeeDT;

Then in the block where I will fill the datatable I did the following. I instantiated the datatable outside of the try catch statement. Inside the try block I attempt to populate the DataTable with the FillBy() method and then in the catch block I read whether or not the DataTable HasErrors. If it does I display the information in the exception which will then give me more direction in debugging the problem.


EmployeeDT = new YourDataset.EmployeesDataTable();
try
{
EmployeeTableAdapter.FillById(EmployeeDT,23456);




}
catch
{
String s = null;
if (EmployeeDT.HasErrors)
{
foreach (DataRow dr in EmployeeDT.GetErrors())
{
foreach (DataColumn dc in dr.GetColumnsInError())
{
s += dc.ColumnName + ",";
}
}
throw new Exception("Yes Errors Encountered, Columns in error: " + s);
}
}

Another thing on this, on my last encounter with this error it was due to me overlooking the fact that the TableAdapter field length of the a field was not long enough to accomodate a certain value which was i the database. I had stored the field length in the database as nvarchar(MAX) yet I must have neglected to update the DataSet which for that field had a MAX length of 50.

When you have your DataSet in design view or if you want to do this in code view, you can set it to AllowDBNull and when it encounters a nnull value, depending on the datatype to do one of three things: Throw and Exception, Insert Null, Or insert an empty string.

Cheers

Andrew

Sunday, 22 July 2007

Introduction

About Me...

Welcome to my Blog, my first blog. I have wanted to create a real blog now for a while to share difficulties I come across whilst developing in the hope that it helps others overcome these similar problems.

My name is Andy or as I go by on the "t"internet, REA_ANDREW. I am from Wigan Engalnd, and have been coding now for over 4 years. I started out trying to get good with the basics of HTML but the major breakthroughs came when I walked out of my firsy job.

I went to work for the NHS and in this time I was in a position where the work demanded, some IT knowledge but not a great deal. I got bored. Whilst in this state of boredom I was also restricted to the programs I could work with on my workstation. It was because of this that I took a closer look at Excel, and also why I still feel Excel was the root of all my learning. Please do not get me wrong, I did go to University and have a degree, but ask me something about what i learnt there, lol NADA!!!!! I learnt how much ale I could drink that is for sure. It was only after university when I realised a few things:

1) I enjoy programming
2) I need money to live and pay bills
3) Programming can pay for bills and most importantly.......I enjoy it.

OK, so going back to the programming. I quit a job as a web developer for a small firm as I was not happy with a few things. I then took this Job at the NHS. As I said before I got bored so I started to learn VBA in Excel. This gave me a basic understanding of variables, methods, classes, boxing etc... I managed to develop in time quite a few number of interesting and useful functions for use in excel. My first was a function which checked for duplicates in a column.

Following on from this and in keeping with the VB language I moved on to ASP using VB. I was working on the side for a development company making small ASP sites now and then but all the time learning. After a while, a junction appeared where I was asked whether I would like to take on a .NET project. Ofcourse I said yes, but then realised that I had a few options with regards to my langauge of choice. My first instinct was VB.NET, but after thinking and deliberation I chose C# and learnt from the bottom up, and I mean the BOTTOM.

Since then I have read book and book after book an applied all the knowledge I have gained and continue to gain. I now focus on design principals and thoery, in the hope that I continually code smarter and not harder lol .

The blogs which I want to write I feel will have a wide scope. I want to write about topics which I feel I have had trouble in understanding and any real pitfalls I have come across, I will share.

I am a regular contributor to experts exchange (http://www.experts-exchange.com/Programming/Languages/C_Sharp/) . Great site. I am also a new comer to the ASP.NET web forums, so I have now started posting my ideas there to.

Please posy any questions you may have about any topics which I post.

Cheers for now,

Andy
(REA_ANDREW)