1. String.Compare() versus String.Equals(): http://www.willasrari.com/blog/stringcompare-versus-stringequals/000189.aspx
2. String.Equals Performance Comparison: http://blogs.msdn.com/noahc/archive/2007/06/29/string-equals-performance-comparison.aspx
3. String.Compare() != String.Equals() : http://blogs.msdn.com/bclteam/archive/2007/05/31/string-compare-string-equals-josh-free.aspx
4. The real cost of performance : http://www.codinghorror.com/blog/archives/000181.html
5. Performance Considerations for strings in C#: http://www.codeproject.com/KB/cs/stringperf.aspx
6. Not all string comparisons created equal : http://geekswithblogs.net/michelotti/archive/2005/12/11/62841.aspx
7. And last but not the least: http://msdn.microsoft.com/en-us/library/fbh501kz(VS.80).aspx
Software Development : A dizzy job...keeping abreast and being competitive is a 24X7 involvement
Jun 7, 2008
May 29, 2008
Customized SqlServer Project Type
This is 'bout a C# projectype which Niels has created to help facilitate SQLServer projects.
Link: http://nielsb.wordpress.com/sqlclrproject/sqlclrdl/
Link: http://nielsb.wordpress.com/sqlclrproject/sqlclrdl/
| Feature | SQLCLRProject | Built-in |
|---|---|---|
| Specific VS project type and item templates | Yes | Yes |
| Automatic deployment of assemblies and creation of T-SQL objects | Yes | Yes |
| Debugging support objects | Yes | Yes |
| Automatic creation of T-SQL deployment scripts | Yes | - |
| Automatic creation of T-SQL DML scripts for testing of the created objects | Yes | - |
| Create objects in a non-default schema | Yes | - |
| Define parameters in the .NET methods to have default values in T-SQL | Yes | - |
| Define parameters in .NET to be created with different names in T-SQL | Yes | - |
| Redeploying an UDT without manually dropping tables/columns depending on the UDT | Yes | - |
May 25, 2008
Vs.Net IDE Designer view Error : Object of Type "Xcannot be converted to type "X""
If this error occurs the Designer won't be able to show the controls of the form but will be able to show them at runtime, to eradicate this problem, close the designer view from the IDE, delete the .resx file associated with the .cs file of the form, then clean and rebuild the project.
The designer view will now be able to be loaded in the IDE.
Sometimes, even after the designer loads the UI, the resx file is missing, to correct this, just change any value of any control in the designer view and then change it back to the original value (like the text of a label)
Apr 22, 2008
Event Bubbling
1. http://www.osix.net/modules/article/?id=685 (using Delegates and Custom Eventargs)
2. http://www.dotnetadvisor.com/Blog/CustomEvent.aspx (using Delegates and Custom Eventargs)
2. http://www.dotnetadvisor.com/Blog/CustomEvent.aspx (using Delegates and Custom Eventargs)
Mar 6, 2008
New INTERSECT and EXCEPT operators in Sql Server 2005 T-SQL
INTERSECT
Let say you have a products table. I’m going to use the products table from the AdventureWorks database. Now let’s say you imported a list of products into the database into a table called productduplicates. Just for a reason, let’s say you manufacturer sent you a full list of products, and you need to see which products you already have in your database.
Normally, if you didn’t have matching primary keys on both tables, like a productId, you would do an inner join on some columns that uniquely identify the rows, as such:
INNER JOINselect a.[name], a.productnumber
from production.product a
inner join production.productduplicates b
on a.[name] = b.[name]
and a.productnumber = b.productnumber
Execution plan for inner join
Hash Match(Inner Join, HASH:([b].[Name], [b].[ProductNumber])=([a].[Name], [a].[ProductNumber]), RESIDUAL:([AdventureWorks].[Production].[Product].[Name] as [a].[Name]=[AdventureWorks].[Production].[productduplicates].[Name] as [b].[Name] AND [AdventureWorks].[Production].[Product].[ProductNumber] as [a].[ProductNumber]=[AdventureWorks].[Production].[productduplicates].[ProductNumber] as [b].[ProductNumber]))
--Table Scan(OBJECT:([AdventureWorks].[Production].[productduplicates] AS [b]))
--Clustered Index Scan(OBJECT:([AdventureWorks].[Production].[Product].[PK_Product_ProductID] AS [a]))
Now you can replace this with a simple INTERSECT statement like the following:
INTERSECTselect [name], productnumber from production.product
intersect
select [name], productnumber from production.productduplicates
Execution plan for INTERSECT
Hash Match(Right Semi Join, HASH:([AdventureWorks].[Production].[productduplicates].[Name], [AdventureWorks].[Production].[productduplicates].[ProductNumber])=([AdventureWorks].[Production].[Product].[Name], [AdventureWorks].[Production].[Product].[ProductNumber]), RESIDUAL:([AdventureWorks].[Production].[Product].[Name]=[AdventureWorks].[Production].[productduplicates].[Name] AND [AdventureWorks].[Production].[Product].[ProductNumber]=[AdventureWorks].[Production].[productduplicates].[ProductNumber]))
--Table Scan(OBJECT:([AdventureWorks].[Production].[productduplicates]))
--Clustered Index Scan(OBJECT:([AdventureWorks].[Production].[Product].[PK_Product_ProductID]))
Just like if you were using a UNION for two select statements, the same number of columns must exist in both select statements, and they must be of the same datatype. In both above examples, you get a list of products that exist in both tables, so you know which products from the manufacturer you already have listed.
I haven’t seen any performance difference in the two, but I’ve only played with this on small tables. The execution plan does show that while you are doing a hash match inner join on the first query, the second query performs a hash match right semi join. Both hash matches perform 50% of the work in the query. The other 50% is split evenly between the table scan and index scan in both queries. So what does the fact that a right semi match is performed when using INTERSECT? I tells me its doing the same thing as if we were to use the EXISTS, like so:
EXISTS
select a.[name], a.productnumber
from production.product a
where exists(select b.[name], b.productnumber from production.productduplicates b
where a.[name] = b.[name]
and a.productnumber = b.productnumber)
EXCEPT
Same scenario, if you wanted to know which products you have that do not exist in the duplicates table, you would normally do a NOT EXISTS like so:
NOT EXISTS
select a.[name], a.productnumber
from production.product a
where not exists(select b.[name], b.productnumber from production.productduplicates b where a.[name] = b.[name]
and a.productnumber = b.productnumber)
Execution plan for NOT EXISTS
Hash Match(Right Anti Semi Join, HASH:([b].[Name], [b].[ProductNumber])=([a].[Name], [a].[ProductNumber]), RESIDUAL:([AdventureWorks].[Production].[Product].[Name] as [a].[Name]=[AdventureWorks].[Production].[productduplicates].[Name] as [b].[Name] AND [AdventureWorks].[Production].[Product].[ProductNumber] as [a].[ProductNumber]=[AdventureWorks].[Production].[productduplicates].[ProductNumber] as [b].[ProductNumber]))
--Table Scan(OBJECT:([AdventureWorks].[Production].[productduplicates] AS [b]))
--Clustered Index Scan(OBJECT:([AdventureWorks].[Production].[Product].[PK_Product_ProductID] AS [a]))
And you get back the list of products that you have that aren’t in the duplicates list. You can flip this around to figure out which products are in the duplicates that you don’t have in your products.
Let’s simply the code a little bit by using the EXCEPT operator. This looks identical to the INTERSECTS query:
EXCEPT
select [name], productnumber from production.product
except
select [name], productnumber from production.productduplicates
Execution plan for except
Hash Match(Right Anti Semi Join, HASH:([AdventureWorks].[Production].[productduplicates].[Name], [AdventureWorks].[Production].[productduplicates].[ProductNumber])=([AdventureWorks].[Production].[Product].[Name], [AdventureWorks].[Production].[Product].[ProductNumber]), RESIDUAL:([AdventureWorks].[Production].[Product].[Name]=[AdventureWorks].[Production].[productduplicates].[Name] AND [AdventureWorks].[Production].[Product].[ProductNumber]=[AdventureWorks].[Production].[productduplicates].[ProductNumber]))
--Table Scan(OBJECT:([AdventureWorks].[Production].[productduplicates]))
--Clustered Index Scan(OBJECT:([AdventureWorks].[Production].[Product].[PK_Product_ProductID]))
Again, can’t find a performance difference. In all queries shows, the reads and duration all average out to be virtually identical. You’d have to test this on some large tables (high number of rows) to figure out if there is a performance difference at all.
Looking at the execution plans for everything, it doesn’t seem that there is a any gain from using INTERSECT and EXCEPT over JOINS or EXISTS/NOT EXISTS except for one big thing: Much simpler code!
Let say you have a products table. I’m going to use the products table from the AdventureWorks database. Now let’s say you imported a list of products into the database into a table called productduplicates. Just for a reason, let’s say you manufacturer sent you a full list of products, and you need to see which products you already have in your database.
Normally, if you didn’t have matching primary keys on both tables, like a productId, you would do an inner join on some columns that uniquely identify the rows, as such:
INNER JOINselect a.[name], a.productnumber
from production.product a
inner join production.productduplicates b
on a.[name] = b.[name]
and a.productnumber = b.productnumber
Execution plan for inner join
Hash Match(Inner Join, HASH:([b].[Name], [b].[ProductNumber])=([a].[Name], [a].[ProductNumber]), RESIDUAL:([AdventureWorks].[Production].[Product].[Name] as [a].[Name]=[AdventureWorks].[Production].[productduplicates].[Name] as [b].[Name] AND [AdventureWorks].[Production].[Product].[ProductNumber] as [a].[ProductNumber]=[AdventureWorks].[Production].[productduplicates].[ProductNumber] as [b].[ProductNumber]))
--Table Scan(OBJECT:([AdventureWorks].[Production].[productduplicates] AS [b]))
--Clustered Index Scan(OBJECT:([AdventureWorks].[Production].[Product].[PK_Product_ProductID] AS [a]))
Now you can replace this with a simple INTERSECT statement like the following:
INTERSECTselect [name], productnumber from production.product
intersect
select [name], productnumber from production.productduplicates
Execution plan for INTERSECT
Hash Match(Right Semi Join, HASH:([AdventureWorks].[Production].[productduplicates].[Name], [AdventureWorks].[Production].[productduplicates].[ProductNumber])=([AdventureWorks].[Production].[Product].[Name], [AdventureWorks].[Production].[Product].[ProductNumber]), RESIDUAL:([AdventureWorks].[Production].[Product].[Name]=[AdventureWorks].[Production].[productduplicates].[Name] AND [AdventureWorks].[Production].[Product].[ProductNumber]=[AdventureWorks].[Production].[productduplicates].[ProductNumber]))
--Table Scan(OBJECT:([AdventureWorks].[Production].[productduplicates]))
--Clustered Index Scan(OBJECT:([AdventureWorks].[Production].[Product].[PK_Product_ProductID]))
Just like if you were using a UNION for two select statements, the same number of columns must exist in both select statements, and they must be of the same datatype. In both above examples, you get a list of products that exist in both tables, so you know which products from the manufacturer you already have listed.
I haven’t seen any performance difference in the two, but I’ve only played with this on small tables. The execution plan does show that while you are doing a hash match inner join on the first query, the second query performs a hash match right semi join. Both hash matches perform 50% of the work in the query. The other 50% is split evenly between the table scan and index scan in both queries. So what does the fact that a right semi match is performed when using INTERSECT? I tells me its doing the same thing as if we were to use the EXISTS, like so:
EXISTS
select a.[name], a.productnumber
from production.product a
where exists(select b.[name], b.productnumber from production.productduplicates b
where a.[name] = b.[name]
and a.productnumber = b.productnumber)
EXCEPT
Same scenario, if you wanted to know which products you have that do not exist in the duplicates table, you would normally do a NOT EXISTS like so:
NOT EXISTS
select a.[name], a.productnumber
from production.product a
where not exists(select b.[name], b.productnumber from production.productduplicates b where a.[name] = b.[name]
and a.productnumber = b.productnumber)
Execution plan for NOT EXISTS
Hash Match(Right Anti Semi Join, HASH:([b].[Name], [b].[ProductNumber])=([a].[Name], [a].[ProductNumber]), RESIDUAL:([AdventureWorks].[Production].[Product].[Name] as [a].[Name]=[AdventureWorks].[Production].[productduplicates].[Name] as [b].[Name] AND [AdventureWorks].[Production].[Product].[ProductNumber] as [a].[ProductNumber]=[AdventureWorks].[Production].[productduplicates].[ProductNumber] as [b].[ProductNumber]))
--Table Scan(OBJECT:([AdventureWorks].[Production].[productduplicates] AS [b]))
--Clustered Index Scan(OBJECT:([AdventureWorks].[Production].[Product].[PK_Product_ProductID] AS [a]))
And you get back the list of products that you have that aren’t in the duplicates list. You can flip this around to figure out which products are in the duplicates that you don’t have in your products.
Let’s simply the code a little bit by using the EXCEPT operator. This looks identical to the INTERSECTS query:
EXCEPT
select [name], productnumber from production.product
except
select [name], productnumber from production.productduplicates
Execution plan for except
Hash Match(Right Anti Semi Join, HASH:([AdventureWorks].[Production].[productduplicates].[Name], [AdventureWorks].[Production].[productduplicates].[ProductNumber])=([AdventureWorks].[Production].[Product].[Name], [AdventureWorks].[Production].[Product].[ProductNumber]), RESIDUAL:([AdventureWorks].[Production].[Product].[Name]=[AdventureWorks].[Production].[productduplicates].[Name] AND [AdventureWorks].[Production].[Product].[ProductNumber]=[AdventureWorks].[Production].[productduplicates].[ProductNumber]))
--Table Scan(OBJECT:([AdventureWorks].[Production].[productduplicates]))
--Clustered Index Scan(OBJECT:([AdventureWorks].[Production].[Product].[PK_Product_ProductID]))
Again, can’t find a performance difference. In all queries shows, the reads and duration all average out to be virtually identical. You’d have to test this on some large tables (high number of rows) to figure out if there is a performance difference at all.
Looking at the execution plans for everything, it doesn’t seem that there is a any gain from using INTERSECT and EXCEPT over JOINS or EXISTS/NOT EXISTS except for one big thing: Much simpler code!
Feb 8, 2008
Feb 7, 2008
Give permissions to your apps to write to custom event log source
1. Create your Log source by code (You may not see it reflected in the event viewer)
2. Run Regedit
3. Travel to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\[your created Log source]
4. Right click and select properties
5. Give the access rights
6. Close the reg hive
7. Refresh the event viewer
8. The newly added log source will appear
2. Run Regedit
3. Travel to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\[your created Log source]
4. Right click and select properties
5. Give the access rights
6. Close the reg hive
7. Refresh the event viewer
8. The newly added log source will appear
Feb 6, 2008
Windows Services, services.msc and the "This Service is marked for deletion" error.
In my current project, we have a windows service that we are developing and debugging, which involves a lot of installing/uninstalling the service. One common problem when uninstalling a service is that while the uninstallation is successful, you still see the service listed in the Services console(services.msc). If you try to start it, stop it or uninstall it again (using installutil.exe or sc delete) you get an uninformative "This service has been marked for deletion".
The KB article (http://support.microsoft.com/kb/823942) about this problem suggests you restart the computer, which is pretty much overkill. Sure, it'll work, but you'll never find out what caused it in the first place. Turns out it's a pretty simple affair: just make sure you close the Services console, which apparently holds a handle of some sort to it. You don't have to do it before you uninstall. The minute you close the console, all services marked for deletion will be deleted, and all will be well.
When doing it on a server, it's important to make sure you've closed all Services consoles on all active sessions. I've seen this error happen when no console was open, and it was fixed by running Task Manager and killing all instances of mmc.exe. I could have logged on to the other sessions and closed it gracefully, but I was lazy. Did the trick.
The KB article (http://support.microsoft.com/kb/823942) about this problem suggests you restart the computer, which is pretty much overkill. Sure, it'll work, but you'll never find out what caused it in the first place. Turns out it's a pretty simple affair: just make sure you close the Services console, which apparently holds a handle of some sort to it. You don't have to do it before you uninstall. The minute you close the console, all services marked for deletion will be deleted, and all will be well.
When doing it on a server, it's important to make sure you've closed all Services consoles on all active sessions. I've seen this error happen when no console was open, and it was fixed by running Task Manager and killing all instances of mmc.exe. I could have logged on to the other sessions and closed it gracefully, but I was lazy. Did the trick.
Jan 3, 2008
A MSMQ Listener
The 2 following classes are used to get the desired effect.
The MSMQListener Class as the name suggests is the main class, while the Form1.cs is a windows forms which invokes this class and shows a popup when a message is queued. Additionally, this form also is used to post messages to the queue
----------------------------------------------------
1. MSMQListener Class
----------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Messaging;
namespace MyQueue
{
public delegate void MessageReceivedEventHandler(object sender, MessageEventArgs args);
public class MSMQListener
{
private bool _listen;
private Type[] _types;
private MessageQueue _queue;
public event MessageReceivedEventHandler MessageReceived;
public Type[] FormatterTypes
{
get { return _types; }
set { _types = value; }
}
public MSMQListener(string queuePath)
{
this.ConstructorCommon(queuePath);
}
public MSMQListener(string queuePath, System.Messaging.IMessageFormatter formatter)
{
this.ConstructorCommon(queuePath);
this._queue.Formatter = formatter; // Customize the formatter type
}
private void ConstructorCommon(string queuePath)
{
_queue = new MessageQueue(queuePath);
}
public void Start()
{
_listen = true;
if (_types != null && _types.Length > 0)
{
// Using only the XmlMessageFormatter. You can use other formatters as well
_queue.Formatter = new XmlMessageFormatter(_types);
}
_queue.PeekCompleted += new PeekCompletedEventHandler(OnPeekCompleted);
_queue.ReceiveCompleted += new ReceiveCompletedEventHandler(OnReceiveCompleted);
StartListening();
}
public void Stop()
{
_listen = false;
_queue.PeekCompleted -= new PeekCompletedEventHandler(OnPeekCompleted);
_queue.ReceiveCompleted -= new ReceiveCompletedEventHandler(OnReceiveCompleted);
}
private void StartListening()
{
if (!_listen)
{
return;
}
// The MSMQ class does not have a BeginRecieve method that can take in a
// MSMQ transaction object. This is a workaround - we do a BeginPeek and then
// recieve the message synchronously in a transaction.
// Check documentation for more details
if (_queue.Transactional)
{
_queue.BeginPeek();
}
else
{
_queue.BeginReceive();
}
}
private void OnPeekCompleted(object sender, PeekCompletedEventArgs e)
{
_queue.EndPeek(e.AsyncResult);
MessageQueueTransaction trans = new MessageQueueTransaction();
Message msg = null;
try
{
trans.Begin();
msg = _queue.Receive(trans);
trans.Commit();
StartListening();
FireRecieveEvent(msg.Body);
}
catch
{
trans.Abort();
}
}
private void FireRecieveEvent(object body)
{
if (MessageReceived != null)
{
MessageReceived(this, new MessageEventArgs(body));
}
}
private void OnReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
Message msg = _queue.EndReceive(e.AsyncResult);
StartListening();
FireRecieveEvent(msg.Body);
}
}
public class MessageEventArgs : EventArgs
{
private object _messageBody;
public object MessageBody
{
get { return _messageBody; }
}
public MessageEventArgs(object body)
{
_messageBody = body;
}
}
}
-----------------------------------------------------------------------------
2. Form1.cs
-----------------------------------------------------------------------------
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Messaging;
using System.Threading;
namespace MyQueue
{
///
/// Summary description for Form1.
///
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.TextBox txtMsg;
private System.Windows.Forms.Button btnMsg;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ListBox MsgBox;
private System.Windows.Forms.Label Messages;
private System.Windows.Forms.Button btnRcv;
///
/// Required designer variable.
///
private System.ComponentModel.Container components = null;
public System.Messaging.MessageQueue mq;
public static Int32 j=0;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
//Q Creation
if(MessageQueue.Exists(@".\Private$\MyQueue"))
mq = new System.Messaging.MessageQueue(@".\Private$\MyQueue");
else
mq = MessageQueue.Create(@".\Private$\MyQueue");
Queue2 q2 = new Queue2();
q2.Show();
///////
MSMQListener msmq = new MSMQListener(@".\Private$\MyQueue", new System.Messaging.XmlMessageFormatter(new string[] {"System.String"}));
msmq.MessageReceived += new MessageReceivedEventHandler(msmq_MessageReceived);
msmq.Start();
}
void msmq_MessageReceived(object sender, MessageEventArgs args)
{
MessageBox.Show(args.MessageBody.ToString());
}
///
/// Clean up any resources being used.
///
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.txtMsg = new System.Windows.Forms.TextBox();
this.btnMsg = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.MsgBox = new System.Windows.Forms.ListBox();
this.Messages = new System.Windows.Forms.Label();
this.btnRcv = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// txtMsg
//
this.txtMsg.Location = new System.Drawing.Point(112, 16);
this.txtMsg.Name = "txtMsg";
this.txtMsg.Size = new System.Drawing.Size(280, 20);
this.txtMsg.TabIndex = 0;
this.txtMsg.Text = "";
//
// btnMsg
//
this.btnMsg.Location = new System.Drawing.Point(200, 48);
this.btnMsg.Name = "btnMsg";
this.btnMsg.TabIndex = 1;
this.btnMsg.Text = "&Send";
this.btnMsg.Click += new System.EventHandler(this.btnMsg_Click);
//
// label1
//
this.label1.Location = new System.Drawing.Point(8, 16);
this.label1.Name = "label1";
this.label1.TabIndex = 4;
this.label1.Text = "Enter Message :";
//
// MsgBox
//
this.MsgBox.Location = new System.Drawing.Point(8, 136);
this.MsgBox.Name = "MsgBox";
this.MsgBox.Size = new System.Drawing.Size(392, 173);
this.MsgBox.TabIndex = 2;
//
// Messages
//
this.Messages.Location = new System.Drawing.Point(16, 104);
this.Messages.Name = "Messages";
this.Messages.Size = new System.Drawing.Size(160, 23);
this.Messages.TabIndex = 3;
this.Messages.Text = "Messages : ";
//
// btnRcv
//
this.btnRcv.Location = new System.Drawing.Point(200, 88);
this.btnRcv.Name = "btnRcv";
this.btnRcv.TabIndex = 5;
this.btnRcv.Text = "&Receive";
this.btnRcv.Click += new System.EventHandler(this.btnRcv_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(408, 317);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.btnRcv,
this.Messages,
this.MsgBox,
this.label1,
this.btnMsg,
this.txtMsg});
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Queue1";
this.ResumeLayout(false);
}
#endregion
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void btnMsg_Click(object sender, System.EventArgs e)
{
// SendMessage(Handle, 1, 0, IntPtr.Zero);
System.Messaging.Message mm = new System.Messaging.Message();
mm.Body = txtMsg.Text;
mm.Label = "Msg" + j.ToString();
j++;
mq.Send(mm);
}
private void btnRcv_Click(object sender, System.EventArgs e)
{
System.Messaging.Message mes;
string m;
try
{
mes = mq.Receive(new TimeSpan(0, 0, 3));
mes.Formatter = new XmlMessageFormatter(new String[] {"System.String,mscorlib"});
m = mes.Body.ToString();
}
catch
{
m = "No Message";
}
MsgBox.Items.Add(m.ToString());
}
}
}
-----------------------------------------------------------------------------
The MSMQListener Class as the name suggests is the main class, while the Form1.cs is a windows forms which invokes this class and shows a popup when a message is queued. Additionally, this form also is used to post messages to the queue
----------------------------------------------------
1. MSMQListener Class
----------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Messaging;
namespace MyQueue
{
public delegate void MessageReceivedEventHandler(object sender, MessageEventArgs args);
public class MSMQListener
{
private bool _listen;
private Type[] _types;
private MessageQueue _queue;
public event MessageReceivedEventHandler MessageReceived;
public Type[] FormatterTypes
{
get { return _types; }
set { _types = value; }
}
public MSMQListener(string queuePath)
{
this.ConstructorCommon(queuePath);
}
public MSMQListener(string queuePath, System.Messaging.IMessageFormatter formatter)
{
this.ConstructorCommon(queuePath);
this._queue.Formatter = formatter; // Customize the formatter type
}
private void ConstructorCommon(string queuePath)
{
_queue = new MessageQueue(queuePath);
}
public void Start()
{
_listen = true;
if (_types != null && _types.Length > 0)
{
// Using only the XmlMessageFormatter. You can use other formatters as well
_queue.Formatter = new XmlMessageFormatter(_types);
}
_queue.PeekCompleted += new PeekCompletedEventHandler(OnPeekCompleted);
_queue.ReceiveCompleted += new ReceiveCompletedEventHandler(OnReceiveCompleted);
StartListening();
}
public void Stop()
{
_listen = false;
_queue.PeekCompleted -= new PeekCompletedEventHandler(OnPeekCompleted);
_queue.ReceiveCompleted -= new ReceiveCompletedEventHandler(OnReceiveCompleted);
}
private void StartListening()
{
if (!_listen)
{
return;
}
// The MSMQ class does not have a BeginRecieve method that can take in a
// MSMQ transaction object. This is a workaround - we do a BeginPeek and then
// recieve the message synchronously in a transaction.
// Check documentation for more details
if (_queue.Transactional)
{
_queue.BeginPeek();
}
else
{
_queue.BeginReceive();
}
}
private void OnPeekCompleted(object sender, PeekCompletedEventArgs e)
{
_queue.EndPeek(e.AsyncResult);
MessageQueueTransaction trans = new MessageQueueTransaction();
Message msg = null;
try
{
trans.Begin();
msg = _queue.Receive(trans);
trans.Commit();
StartListening();
FireRecieveEvent(msg.Body);
}
catch
{
trans.Abort();
}
}
private void FireRecieveEvent(object body)
{
if (MessageReceived != null)
{
MessageReceived(this, new MessageEventArgs(body));
}
}
private void OnReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
Message msg = _queue.EndReceive(e.AsyncResult);
StartListening();
FireRecieveEvent(msg.Body);
}
}
public class MessageEventArgs : EventArgs
{
private object _messageBody;
public object MessageBody
{
get { return _messageBody; }
}
public MessageEventArgs(object body)
{
_messageBody = body;
}
}
}
-----------------------------------------------------------------------------
2. Form1.cs
-----------------------------------------------------------------------------
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Messaging;
using System.Threading;
namespace MyQueue
{
///
/// Summary description for Form1.
///
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.TextBox txtMsg;
private System.Windows.Forms.Button btnMsg;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ListBox MsgBox;
private System.Windows.Forms.Label Messages;
private System.Windows.Forms.Button btnRcv;
///
/// Required designer variable.
///
private System.ComponentModel.Container components = null;
public System.Messaging.MessageQueue mq;
public static Int32 j=0;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
//Q Creation
if(MessageQueue.Exists(@".\Private$\MyQueue"))
mq = new System.Messaging.MessageQueue(@".\Private$\MyQueue");
else
mq = MessageQueue.Create(@".\Private$\MyQueue");
Queue2 q2 = new Queue2();
q2.Show();
///////
MSMQListener msmq = new MSMQListener(@".\Private$\MyQueue", new System.Messaging.XmlMessageFormatter(new string[] {"System.String"}));
msmq.MessageReceived += new MessageReceivedEventHandler(msmq_MessageReceived);
msmq.Start();
}
void msmq_MessageReceived(object sender, MessageEventArgs args)
{
MessageBox.Show(args.MessageBody.ToString());
}
///
/// Clean up any resources being used.
///
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.txtMsg = new System.Windows.Forms.TextBox();
this.btnMsg = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.MsgBox = new System.Windows.Forms.ListBox();
this.Messages = new System.Windows.Forms.Label();
this.btnRcv = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// txtMsg
//
this.txtMsg.Location = new System.Drawing.Point(112, 16);
this.txtMsg.Name = "txtMsg";
this.txtMsg.Size = new System.Drawing.Size(280, 20);
this.txtMsg.TabIndex = 0;
this.txtMsg.Text = "";
//
// btnMsg
//
this.btnMsg.Location = new System.Drawing.Point(200, 48);
this.btnMsg.Name = "btnMsg";
this.btnMsg.TabIndex = 1;
this.btnMsg.Text = "&Send";
this.btnMsg.Click += new System.EventHandler(this.btnMsg_Click);
//
// label1
//
this.label1.Location = new System.Drawing.Point(8, 16);
this.label1.Name = "label1";
this.label1.TabIndex = 4;
this.label1.Text = "Enter Message :";
//
// MsgBox
//
this.MsgBox.Location = new System.Drawing.Point(8, 136);
this.MsgBox.Name = "MsgBox";
this.MsgBox.Size = new System.Drawing.Size(392, 173);
this.MsgBox.TabIndex = 2;
//
// Messages
//
this.Messages.Location = new System.Drawing.Point(16, 104);
this.Messages.Name = "Messages";
this.Messages.Size = new System.Drawing.Size(160, 23);
this.Messages.TabIndex = 3;
this.Messages.Text = "Messages : ";
//
// btnRcv
//
this.btnRcv.Location = new System.Drawing.Point(200, 88);
this.btnRcv.Name = "btnRcv";
this.btnRcv.TabIndex = 5;
this.btnRcv.Text = "&Receive";
this.btnRcv.Click += new System.EventHandler(this.btnRcv_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(408, 317);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.btnRcv,
this.Messages,
this.MsgBox,
this.label1,
this.btnMsg,
this.txtMsg});
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Queue1";
this.ResumeLayout(false);
}
#endregion
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void btnMsg_Click(object sender, System.EventArgs e)
{
// SendMessage(Handle, 1, 0, IntPtr.Zero);
System.Messaging.Message mm = new System.Messaging.Message();
mm.Body = txtMsg.Text;
mm.Label = "Msg" + j.ToString();
j++;
mq.Send(mm);
}
private void btnRcv_Click(object sender, System.EventArgs e)
{
System.Messaging.Message mes;
string m;
try
{
mes = mq.Receive(new TimeSpan(0, 0, 3));
mes.Formatter = new XmlMessageFormatter(new String[] {"System.String,mscorlib"});
m = mes.Body.ToString();
}
catch
{
m = "No Message";
}
MsgBox.Items.Add(m.ToString());
}
}
}
-----------------------------------------------------------------------------
Oct 15, 2007
How to select a random value from an array
// Initialize the string array
string[] strStrings = { "Random string", "Another random value from the array", "Randomly selected index" };
// Choose a random slogan
Random RandString = new Random();
// Display the random slogan
txtRandom.Text = strStrings[RandString.Next(0, strStrings.Length-1)];
string[] strStrings = { "Random string", "Another random value from the array", "Randomly selected index" };
// Choose a random slogan
Random RandString = new Random();
// Display the random slogan
txtRandom.Text = strStrings[RandString.Next(0, strStrings.Length-1)];
Oct 5, 2007
SQL Bulk Copy with C#.Net
The simplest way to copy lots of data from any resources to SQL Server is BulkCopying.
.NET Framework 2.0 contains a class in ADO.NET "System.Data.SqlClient" Class: SqlBulkCopy.
In the first phase you get the source data. The source could be various data platforms such as Access, Excel, SQL.. You must get the source data in your code wrapping it in a DataTable, or any DataReader class which implements IDataReader. After that, in the second phase, you must connect the target SQL Database and perform the bulk copy operation.
The bulk copy operation in .Net is a very fast way to copy large amount of data somewhere to SQL Server. The reason for that is the Bulkcopy Sql Server mechanism. Inserting all data row by row, one after the other is a very time and system resources consuming. But the bulkcopy mechanism process all data at once. So the data inserting becomes very fast.
Sample Code:
//Establishing connection
SqlConnectionStringBuilder cb = new SqlConnectionStringBuilder();
cb.DataSource = "SQLProduction";
cb.InitialCatalog = "Sales";
cb.IntegratedSecurity = true;
SqlConnection cnn = new SqlConnection(cb.ConnectionString);
// Getting source data
SqlCommand cmd = new SqlCommand("SELECT * FROM PendingOrders",cnn);
cnn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
// Initializing an SqlBulkCopy object
SqlBulkCopy sbc = new SqlBulkCopy("server=.;database=ProductionTest;" +
"Integrated Security=SSPI");
// Copying data to destination
sbc.DestinationTableName = "Temp";
sbc.WriteToServer(rdr);
// Closing connection and the others
sbc.Close();
rdr.Close();
cnn.Close();
.NET Framework 2.0 contains a class in ADO.NET "System.Data.SqlClient" Class: SqlBulkCopy.
In the first phase you get the source data. The source could be various data platforms such as Access, Excel, SQL.. You must get the source data in your code wrapping it in a DataTable, or any DataReader class which implements IDataReader. After that, in the second phase, you must connect the target SQL Database and perform the bulk copy operation.
The bulk copy operation in .Net is a very fast way to copy large amount of data somewhere to SQL Server. The reason for that is the Bulkcopy Sql Server mechanism. Inserting all data row by row, one after the other is a very time and system resources consuming. But the bulkcopy mechanism process all data at once. So the data inserting becomes very fast.
Sample Code:
//Establishing connection
SqlConnectionStringBuilder cb = new SqlConnectionStringBuilder();
cb.DataSource = "SQLProduction";
cb.InitialCatalog = "Sales";
cb.IntegratedSecurity = true;
SqlConnection cnn = new SqlConnection(cb.ConnectionString);
// Getting source data
SqlCommand cmd = new SqlCommand("SELECT * FROM PendingOrders",cnn);
cnn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
// Initializing an SqlBulkCopy object
SqlBulkCopy sbc = new SqlBulkCopy("server=.;database=ProductionTest;" +
"Integrated Security=SSPI");
// Copying data to destination
sbc.DestinationTableName = "Temp";
sbc.WriteToServer(rdr);
// Closing connection and the others
sbc.Close();
rdr.Close();
cnn.Close();
Get table Schema using the sqlreader
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataReader reader = cmd.ExecuteReader();
DataTable schema = reader.GetSchemaTable();
foreach (DataRow row in schema.Rows)
{
foreach (DataColumn col in schema.Columns){
Console.WriteLine(col.ColumnName + " = " + row[col]);
Console.WriteLine("Null value allowed: " + col.AllowDBNull);
}
}
reader.Close();
SqlCommand cmd = new SqlCommand(sql, conn);
SqlDataReader reader = cmd.ExecuteReader();
DataTable schema = reader.GetSchemaTable();
foreach (DataRow row in schema.Rows)
{
foreach (DataColumn col in schema.Columns){
Console.WriteLine(col.ColumnName + " = " + row[col]);
Console.WriteLine("Null value allowed: " + col.AllowDBNull);
}
}
reader.Close();
Sep 20, 2007
Issues with Restarting IIS
As per MSDN:
Restarting or stopping IIS, or rebooting your Web server, is a severe action. When you restart the Internet service, all sessions connected to your Web server (including Internet, FTP, SMTP, and NNTP) are dropped. Any data held in Web applications is lost. All Internet sites are unavailable until Internet services are restarted. For this reason, you should avoid restarting, stopping, or rebooting your server if at all possible. IIS 6.0 includes application pool recycling and several other features that provide alternatives to restarting IIS.
For more details chk this link - http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/003ed2fe-6339-4919-b577-6aa965994a9b.mspx?mfr=true
Restarting or stopping IIS, or rebooting your Web server, is a severe action. When you restart the Internet service, all sessions connected to your Web server (including Internet, FTP, SMTP, and NNTP) are dropped. Any data held in Web applications is lost. All Internet sites are unavailable until Internet services are restarted. For this reason, you should avoid restarting, stopping, or rebooting your server if at all possible. IIS 6.0 includes application pool recycling and several other features that provide alternatives to restarting IIS.
For more details chk this link - http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/003ed2fe-6339-4919-b577-6aa965994a9b.mspx?mfr=true
Sep 18, 2007
Work around to the "Cross Thread Error"
We can't perform operation on a control, if that control was created by another thread. While doing this kind of operations, we get "Cross Thread is not valid" errors
Workaround: http://www.codeproject.com/useritems/Cross_Thread.asp
Workaround: http://www.codeproject.com/useritems/Cross_Thread.asp
Jul 30, 2007
Connecting to a VS Team Foundation Server and fetching Work Item Details
- Download the VS TFS SDK (http://msdn2.microsoft.com/en-us/library/bb130146%28VS.80%29.aspx) or install the Visual Studio Team Suite. This will install the necessary assemblies required to access the VS TFS.
- Create a new VS 2005 Project.
- Browse to the following path (
\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies) and add the following references
-using Microsoft.TeamFoundation;
-using Microsoft.TeamFoundation.Common;
-using Microsoft.TeamFoundation.Client;
-using Microsoft.TeamFoundation.WorkItemTracking.Client; - Use the following code to access the VS TFS:
TeamFoundationServer tfs = null;
WorkItemStore wis = null;
tfs = new TeamFoundationServer(tfsName, CredentialCache.DefaultCredentials);
tfs.Authenticate();
// Display the details about the TeamFoundationServer.
richTextBox1.Text = "Team Foundation Server details:";
richTextBox1.Text += " \n Server Name: " + tfs.Name;
richTextBox1.Text += " \n Uri: " + tfs.Uri;
richTextBox1.Text += " \n AuthenticatedUserDisplayName: " + tfs.AuthenticatedUserDisplayName;
richTextBox1.Text += " \n AuthenticatedUserName: " + tfs.AuthenticatedUserName; - To Access the Projects inside the TeamFoundationServer:
wis = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
//Iterate Through Projects
foreach (Project tfs_project in wis.Projects)
{
treeView2.Nodes.Add(tfs_project.Name);
} - To Access the Workitems in the Projects:
private void treeView2_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
{
string tfs_projectName = e.Node.Text.Trim(); //The project name
//Perform WIQL Query
WorkItemCollection wic = wis.Query(
" SELECT [System.Id], [System.WorkItemType]," +
" [System.State], [System.AssignedTo], [System.Title] " +
" FROM WorkItems " +
" WHERE [System.TeamProject] = '" + tfs_projectName +
"' ORDER BY [System.WorkItemType], [System.Id]");
foreach (WorkItem wi in wic)
{
TreeNode newnode = new TreeNode();
newnode.Text = wi.Id + wi.Title + "-" + wi.Description;
newnode.Tag = wi;
treeView1.Nodes.Add(newnode);
//treeView1.Nodes.Add(wi.Title + "[" + wi.Type.Name + "]" + wi.Description );
}
Issues: While connecting from home I found that it takes really long, or sometimes times out during performing the following:
wis = (WorkItemStore)tfs.GetService(typeof(WorkItemStore))
The solution that I found in the net was :
Go to Internet Exploreer> Connections> LAN Settings
Instead of having a "Detect Proxy Automatically", put in a definite "Proxy setting"
Jul 5, 2007
Show a context menu when right clicking on a treeview
private void tvwMenu_MouseUp(object sender, MouseEventArgs e)
{
//Select Node When Right Clicked & Set Context Menu To Use
if( e.Button == MouseButtons.Right )
{
TreeNode node = tvwMenu.GetNodeAt( new Point( e.X, e.Y ) );
if( node != null )
{
TreeNodeMenuTag tag = (TreeNodeMenuTag)node.Tag;
tvwMenu.SelectedNode = node;
tvwMenu.ContextMenuStrip = (tag.isMenu) ? cmnuMenuNode :
cmnuProgramNode;
}
}
}
{
//Select Node When Right Clicked & Set Context Menu To Use
if( e.Button == MouseButtons.Right )
{
TreeNode node = tvwMenu.GetNodeAt( new Point( e.X, e.Y ) );
if( node != null )
{
TreeNodeMenuTag tag = (TreeNodeMenuTag)node.Tag;
tvwMenu.SelectedNode = node;
tvwMenu.ContextMenuStrip = (tag.isMenu) ? cmnuMenuNode :
cmnuProgramNode;
}
}
}
Enum Functions
- Iterating through an Enum:
foreach (enmResponseInterval value in Enum.GetValues(typeof(enmResponseInterval)))
{
cmbXXX.Items.Add(value.ToString());
} - Conditional Switch Statement with Enumeration String Value
public enum Product
{
Word,
Outlook,
Excel
}
public void Process(string productName)
{
switch ((Product)Enum.Parse(typeof(Product), productName.ToString()))
{
case Product.Excel:
// Do something
break;
case Product.Outlook:
// Do Something
break;
case Product.Word:
// Do something
break;
}
}
Jun 26, 2007
SQL Server Projects in C# - Some important links
Jun 20, 2007
C# : Drawing a Pie Chart and saving as jpeg
////Namespace:
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Text;
////Create canvas and fill the background
Bitmap objBitmap;
Graphics objGraphics;
objBitmap = new Bitmap(400, 440);
objGraphics = Graphics.FromImage(objBitmap);
objGraphics.Clear(Color.White);
////Draw the pie and fill
Pen p=new Pen(Color.Yellow,0);
Rectangle rect=new Rectangle(10,10,280,280);
objGraphics.DrawEllipse(p,rect);
Brush b1=new SolidBrush(Color.Red);
Brush b2=new SolidBrush(Color.Green);
Brush b3=new SolidBrush(Color.Blue);
objGraphics.FillPie(b1, rect, 0f, 60f);
objGraphics.FillPie(b2, rect, 60f, 150f);
objGraphics.FillPie(b3, rect, 210f, 150f);
////Draw font
FontFamily fontfml = new FontFamily(GenericFontFamilies.Serif);
Font font = new Font(fontfml, 16);
SolidBrush brush = new SolidBrush(Color.Blue);
objGraphics.DrawString("Drawing Graphics", font, brush, 70, 300);
////Export and save to picture
objBitmap.Save(Response.OutputStream, ImageFormat.Gif);
objBitmap.Save(Server.MapPath("x.jpg"), ImageFormat.Jpeg);
////End drawing
objBitmap.Dispose();
objGraphics.Dispose();
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Text;
////Create canvas and fill the background
Bitmap objBitmap;
Graphics objGraphics;
objBitmap = new Bitmap(400, 440);
objGraphics = Graphics.FromImage(objBitmap);
objGraphics.Clear(Color.White);
////Draw the pie and fill
Pen p=new Pen(Color.Yellow,0);
Rectangle rect=new Rectangle(10,10,280,280);
objGraphics.DrawEllipse(p,rect);
Brush b1=new SolidBrush(Color.Red);
Brush b2=new SolidBrush(Color.Green);
Brush b3=new SolidBrush(Color.Blue);
objGraphics.FillPie(b1, rect, 0f, 60f);
objGraphics.FillPie(b2, rect, 60f, 150f);
objGraphics.FillPie(b3, rect, 210f, 150f);
////Draw font
FontFamily fontfml = new FontFamily(GenericFontFamilies.Serif);
Font font = new Font(fontfml, 16);
SolidBrush brush = new SolidBrush(Color.Blue);
objGraphics.DrawString("Drawing Graphics", font, brush, 70, 300);
////Export and save to picture
objBitmap.Save(Response.OutputStream, ImageFormat.Gif);
objBitmap.Save(Server.MapPath("x.jpg"), ImageFormat.Jpeg);
////End drawing
objBitmap.Dispose();
objGraphics.Dispose();
TableLayoutPanel in C#
The Tablelayoutpanel is a easy way to add Controls in a Tabular format.
////--------Sample code-------
TextBox questionText = new TextBox();
questionText.Text = questionName;
questionText.MouseHover += new EventHandler(Question_MouseHover);
questionText.Width = 200;
questionText.BorderStyle = BorderStyle.FixedSingle;
questionText.BackColor = Color.Black;
questionText.ForeColor = Color.White;
GroupBox grRadios = new GroupBox();
grRadios.Height = 25;
grRadios.Width = 100;
grRadios.Padding = new Padding(2);
grRadios.Tag = questionId.ToString();
grRadios.Text = string.Empty;
RadioButton[] radios = new RadioButton[3];
radios[0] = new RadioButton();
radios[0].Tag = "Yes";
radios[1] = new RadioButton();
radios[1].Tag = "No";
radios[2] = new RadioButton();
radios[2].Tag = "Not Applicable";
////Add a event handler to the radio buttons
for (int i = 0; i < radios.Length; i++)
{
radios[i].Width = 20;
radios[i].MouseHover += new EventHandler(Radio_MouseHover);
if (i == checkedRadio)
{
radios[i].Checked = true;
}
}
grRadios.Controls.AddRange(radios);
radios[0].Left = 0;
radios[0].Top = radios[0].Top;
radios[1].Left = radios[1].Left + 20;
radios[1].Top = radios[0].Top;
radios[2].Left = radios[2].Left + 20;
radios[2].Top = radios[0].Top;
tblQuestions.Controls.Add(questionText);
tblQuestions.Controls.Add(grRadios);
////--------Sample code-------
TextBox questionText = new TextBox();
questionText.Text = questionName;
questionText.MouseHover += new EventHandler(Question_MouseHover);
questionText.Width = 200;
questionText.BorderStyle = BorderStyle.FixedSingle;
questionText.BackColor = Color.Black;
questionText.ForeColor = Color.White;
GroupBox grRadios = new GroupBox();
grRadios.Height = 25;
grRadios.Width = 100;
grRadios.Padding = new Padding(2);
grRadios.Tag = questionId.ToString();
grRadios.Text = string.Empty;
RadioButton[] radios = new RadioButton[3];
radios[0] = new RadioButton();
radios[0].Tag = "Yes";
radios[1] = new RadioButton();
radios[1].Tag = "No";
radios[2] = new RadioButton();
radios[2].Tag = "Not Applicable";
////Add a event handler to the radio buttons
for (int i = 0; i < radios.Length; i++)
{
radios[i].Width = 20;
radios[i].MouseHover += new EventHandler(Radio_MouseHover);
if (i == checkedRadio)
{
radios[i].Checked = true;
}
}
grRadios.Controls.AddRange(radios);
radios[0].Left = 0;
radios[0].Top = radios[0].Top;
radios[1].Left = radios[1].Left + 20;
radios[1].Top = radios[0].Top;
radios[2].Left = radios[2].Left + 20;
radios[2].Top = radios[0].Top;
tblQuestions.Controls.Add(questionText);
tblQuestions.Controls.Add(grRadios);
Subscribe to:
Posts (Atom)