Sunday, August 22, 2010

Determine new PK after an Insert

Today’s blog post will be another excerpt from my .Net Tips column in the April 2008 Issue of the Universal Thread Magazine.

You have a couple of options to get the PK value of a newly inserted record. I am assuming SQL Server database in these examples.

First, if you are not using Stored Procs and simply sending an INSERT INTO statement, just add a "SELECT SCOPE_IDENTITY() at the end of your query and be sure to execute your query by reading the result back (into a datareader or dataset for example).

Your query string should look like this:

string Sql = "INSERT INTO MyTable (ColumnOne) VALUES ('Bob') SELECT SCOPE_IDENTITY() AS MyPK";

And, here's the code that shows how to execute and read the results back using a DataReader:

int MyPK = 0;
SqlCommand sc = new SqlCommand(Sql, new SqlConnection(this.TestConnection));
sc.Connection.Open();
SqlDataReader rd = sc.ExecuteReader(CommandBehavior.CloseConnection);

while (rd.Read())
{
MyPK = Convert.ToInt32(rd["MyPK"]);
}

Alternatively, if you're using a Stored Proc, you'd use an OUTPUT parameter in your Stored Proc, and a ParameterDirection.InputOutput in your code:

-- The Stored Proc
CREATE PROCEDURE MySP
@PK int = NULL OUTPUT,
@ColumnOne char(8) = NULL,
@ColumnTwo char(4) = NULL
AS
INSERT MyTable (ColumnOne, ColumnTwo)
SELECT @ColumnOne, @ColumnTwo

SELECT @PK = SCOPE_IDENTITY()

And here's how you would call it in your code:

Command.CommandText = "MySP";
Command.Parameters.Add("@PK", 0);
Command.Parameters["@PK"].Direction = ParameterDirection.InputOutput;
Command.Parameters.Add("@ColumnOne", OneValue);
Command.Parameters.Add("@ColumnTWo", TwoValue);

Command.ExecuteNonQuery();

MyNewPK = Command.Parameters["@PK"].Value;

Thanks to Éric Moreau (and another post by me) in Messages #1090511 and #930339 on the Universal Thread.

Saturday, July 31, 2010

Security Issues with EventSources in EventLogs

If you rely on the System.Diagnostics.EventLog class to log your server-side errors (such as those that may occur in a web service), you may run into security issues if you try to use an EventSource that doesn’t already exist. Since this is server-side, the easiest thing to do is to use a Web Service web method, which can just be accessed through IE.It only needs to be done once. Here's the web method:

The line containing "Events.EventSources" is simply an Enum containing the names of EventSources you might use in your app. If you only have one, then you can just get rid of that whole foreach loop and just hardcode the name of your source in the if.

[WebMethod(Description = "Set server Event Log sources.")]
public string SetEventLogSources(string Username, string Password, string Domain)
{
//This will keep track of the impersonation token
const int LOGON_TYPE_INTERACTIVE = 2;
const int LOGON_TYPE_PROVIDER_DEFAULT = 0;
string logName = "Application";
IntPtr userToken = IntPtr.Zero;

if (LogonUser(Username, Domain, Password, LOGON_TYPE_INTERACTIVE, LOGON_TYPE_PROVIDER_DEFAULT, ref userToken))
{
//Initialize user token
WindowsIdentity oIdentity = new WindowsIdentity(userToken);
WindowsImpersonationContext oContext = oIdentity.Impersonate();

foreach (string source in Enum.GetNames(typeof(Events.EventSources)))
{
if (EventLog.SourceExists(source) == false)
EventLog.CreateEventSource(source, logName);
}

//Undo impersonation
oContext.Undo();

return "Event source registration successful!";
}
else
{
return "Unable to process user credentials for event source registration.";
}
}

// Using this api to get an accessToken of specific Windows User by its user name and password
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static public extern bool LogonUser(string userName, string domain, string passWord, int logonType, int logonProvider, ref IntPtr accessToken);

Be sure you have included the following “using”s:

using System.Diagnostics;
using System.Security.Principal;
using System.Runtime.InteropServices;

Saturday, June 05, 2010

Program To The Interface

One of the biggest benefits of using Interfaces (in my opinion) is to be able to "program to the Interface", as they say. Let me explain with a real-world example:

Suppose I have created this Interface:

public interface IFillFromFinder
{
void FillListView(DataSet dsList);
void ClearListView();
}

Now, suppose I have a class that contains a ListView and implements the Interface:

public class MySearchClass : MyUserControl, IFillFromFinder
{
#region Declarations

protected ListView oListView;
protected MyFinderForm oFinder;

#endregion

#region Methods

public void Search(ListView listView)
{
this.oListView = listview;
this.ClearListView();

this.oFinder = new MyFinderForm(this);
oFinder.ShowDialog();
}

// Interface methods to implement
public void ClearListView()
{
// code here for clearing listview
}

public void FillListView(DataSet dsList)
{
// code here for filling listview
}

#endregion
}

As you can see, this class calls a Finder dialog Form, that gathers information from the User and performs a query against the backend data. If the Finder Dialog has been called from a control that implements this Interface (as in the above call from the Search() method), then it can also fill that control's ListView object by calling the methods on the Interface.

Here's the relevant part of my Finder Dialog. Note that the oListControl is defined using the Interface. MyFinderForm needs to know absolutely nothing else about what's calling it, other than that it implements the IFillFromFinder interface.

public class MyFinderForm : MyDialogForm    
{
#region Declarations

public MyListDataSet oData = new MyListDataSet();
protected IFillFromFinder oListControl = null;

#endregion

#region Constructors

public MyFinderForm(IFillFromFinder CallingControl)
{
this.oListControl = CallingControl;
InitializeComponent();
}

public MyFinderForm()
{
InitializeComponent();
}

#endregion

#region Events

private void cmdOK_Click(object sender, System.EventArgs e)
{
this.FillDataSet();

// If this dialog form was called by a class that implemented IFillFromFinder,
// then call call the Interface method to fill the ListView.
if (this.oListControl != null)
{
if (this.chkReplace.Checked == true)
this.oListControl.ClearListView();
this.oListControl.FillListView(this.oData);
}
}


#endregion
}

Here's another good example. Suppose I need to perform some kind of action, or access a property, on a Control on my Form, but not all Controls on my Form have the appropriate method or property. Interfaces come in handy for this, as these two examples illustrate:

foreach (IMyControl control in this.Controls)
{
control.MyMethod();
control.MyProperty = "whatever";
}

-or-

if (SomeControl is IMyControl)
{
((IMyControl)SomeControl).MyMethod();
((IMyControl)SomeControl).MyProperty = "whatever";
}

I hope this sort of helps explain interfaces by using a real world example.

Tuesday, May 18, 2010

Inheritance and Constructors

Here's a common scenario: say you have a base class that does some work that relies on the setting of one of its properties. In the example I'll show, I have an abstract class designed to fill a DataSet from SQL, based on the TableName member of the class.
Each sub-class will set TableName, because each sub-class will be filling it's own table.

Our first attempt at creating these two classes looks like this:


public class BizObj
{
protected string TableName="default";
private DataSet oData;

public BizObj()
{
this.LoadData();
}
public void LoadData()
{
SqlConnection oConn = new SqlConnection("...");
SqlDataAdapter oAdapter = new SqlDataAdapter("SELECT * FROM " + this.TableName, oConn);
oAdapter.Fill(this.oData);
}
}
public class AuthorBizObj: BizObj
{
public AuthorBizObj()
{
this.TableName="Authors";
}
}

This does not work. Why? Because when instantiating any class, its base class constructor always fires first. My example used an abstract base class, but the same applies to a non-abstract class. So, in this example, the BizObj (base class) constructor fires before the AuthorBizObj (sub-class) constructor. By then, it's too late to set the TableName (which has already been set in the BizObj base class).

The trick to fixing this is to use a virtual Property, rather than a member, and to override that Property in each sub-class:

public class BizObj
{
protected virtual string TableName { get; set; }
private DataSet oData;

public BizObj()
{
this.LoadData();
}
public void LoadData()
{
SqlConnection oConn = new SqlConnection("...");
SqlDataAdapter oAdapter = new SqlDataAdapter("SELECT * FROM " + this.TableName, oConn);
oAdapter.Fill(this.oData);
}
}
public class AuthorBizObj: BizObj
{
protected override string TableName
{
get {return "Authors;}
}
public AuthorBizObj()
{
// whether or not you have this constructor
// does not affect the how the constructor fires
// I left a non-functional constructor in this example
// simply for illustrative purposes. You can leave it
// out if you have nothing to code in it.
}

}

So, there are two important points to take away from the above illustration:

1) When a class has been sub-classed, the base class constructor always runs before the sub-class constructor.

2) The member variables are instanced  in just the opposite order:  the base class member variables are set after the sub-class member variables (the above examples don’t quite illustrate this point). Keep in mind, I’m talking about member variables (which cannot be virtual and so cannot be overridden in a sub-class). My examples above used virtual properties (with getters/setters), which aren’t set until they’re accessed.

Sunday, April 18, 2010

Create An XSD

In a post I wrote back in September about why I dislike TableAdapters (see TableAdapters Are Crap), I mentioned that the TableAdapter wizard puts a lot of excess stuff in your .xsd that doesn’t belong there. So, how do you avoid that? Well, first you’ve got to have already created an .xsd. I’ll show an easy little utility you can write yourself to use to do this.

Secondly, you’ve got to avoid using the DataSet Designer in such a way that it puts all that excess stuff into your .xsd. How do you do that? That’s pretty easy actually … as long as you don't open an .xsd with the DataSet Designer, but open it with the XML Editor instead, you won't have to worry about getting all the extra stuff for support of TableAdapters generated in your .xsd (it's not the opening, but the saving of changes that generates the code).

So, use the code I’ll show you in a moment to create an .xsd. Then, simply add that .xsd to your DataSet project, right-click on the .xsd and choose "Run Custom Tool". This is what will generate the Typed DataSet for you. If that option doesn't show up in your context menu, choose Properties instead and type "MSDataSetGenerator" in the Custom Tool property. After that, any time you make a change to the .xsd in the XML Editor and save the change, the Typed DataSet gets regenerated.

Now, on to the code … this example is fairly simple but quite usable. You can make it more robust if you want to (for example, add code to find other SQL Servers rather than use only a default) . Create a Form, put 3 textboxes and a button on it. Don’t forget that you need to add a “using System.Data.SqlClient;” in order to use the SQL stuff.

public partial class FormCreateXsd : Form
{
private string TestConnection = "server=(local);uid=sa;pwd=MyPassword";

public FormCreateXsd()
{
InitializeComponent();
}

private void CreateDataSet()
{
// set up the connection with the database name
string connectionString = this.TestConnection + ";database=" + this.txtDatabaseName.Text;

try
{
// set up the Sql Command and DataAdapter with the Stored Proc name
SqlCommand sc = new SqlCommand(this.txtStoredProcName.Text, new SqlConnection(connectionString));
sc.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter(sc);

// set up the DataSet with the DataSet name
DataSet ds = new DataSet();
string[] parts = this.txtDataSetName.Text.Split('.');
ds.DataSetName = parts[0];

// and fill the DataSet
da.Fill(ds);

// set the filename and write out the schema
string filename = this.txtDataSetName.Text;
if (parts[parts.Length - 1].ToLower() != "xsd")
filename += ".xsd";
ds.WriteXmlSchema(filename);
MessageBox.Show(filename + " successfully created");
}
catch (Exception ex)
{
string msg = ex.Message;
if (ex.InnerException != null)
msg += "\r\n" + ex.InnerException.Message;
MessageBox.Show("The following error occurred: " + ex.Message);
}
}
private void button1_Click(object sender, EventArgs e)
{
if (this.txtDatabaseName.Text == "" || this.txtDataSetName.Text == "" || this.txtStoredProcName.Text == "")
return;
else
this.CreateDataSet();
}
}

That’s it. Happy coding!

Sunday, March 28, 2010

Custom Events

UPDATE: I've updated my examples below, and added to some of the text, to take into account tergiver's suggestion, in his comment below, that I should probably use the generic EventHandler delegate (introduced in .NET 2.0) rather than defining custom delegates (which dates back to .NET 1.x). In fact, I've totally taken out the custom delegate code, since I doubt many people are still using .NET 1.1 anymore. If anyone reading this who is not using .NET 2.0 and higher would like to know about the custom delegate declarations and usage, let me know in a comment.

I tend to write introductory topics in my blog. Not always, but typically. And not because I’m a newcomer to .NET (I’ve been using .NET since the beginning of 2002), but because all the complicated topics seem to be covered by everyone else and I think there is still a need to address simpler topics.

Today’s topic is no different. Even though writing custom events isn’t all that complicated, I still see a lot of questions on the Forums asking how to do it. So, let’s get to it.

Say you have a custom UserControl that you need to have raise an event when, for example, a user types "FOO" in a textbox that is on the Control.

Minimally, in your UserControl, you need the following things:

// First you must specify the event that you will be raising:

public event EventHandler MyFooBar;

// Then, when you need to fire the event in your UserControl, do this:
if (this.MyTextBox.Text == "FOO")
this.OnMyFooBar(new EventArgs());

// Lastly, this raises the MyFooBar event:
protected virtual void OnMyFooBar(EventArgs e)
{
if (MyFooBar != null)
MyFooBar(this, e);
}

Then, in your form, you just set up the usual delegates and EventHandlers:

this.oMyControl.MyFooBar += new System.EventHandler(this.oMyControl_MyFooBarHandler);

private void oMyControl_MyFooBarHandler(object sender, System.EventArgs e)
{
// whatever your form code needs to be, such as:
MessageBox.Show("FOO was specified!");
}

Or, the alternative way to do this since anonymous methods were introduced in 2.0:

this.oMyControl.MyFooBar += delegate
{
// whatever your code needs to be, such as
MessageBox.Show("FOO was specified!");
};

You can even get more fancy, creating custom EventArgs and utilizing generic delegates, but the above code is sufficient for simple things, when just the built-in System.EventArgs is all you need. For fancier, custom stuff, try this:

First, custom event args something like this:

public class MyCustomEventArgs : EventArgs 
{
public bool IsBarSpecified { get; set; }
}

Your UserControl code then gets changed to this:

// Change the event so that it can be handled by a generic delegate

public event EventHandler<MyCustomEventArgs> MyFooBar;

// Firing the event gets changed to something like this:
if (this.MyTextBox.Text.ToUpper().Contains("FOO"))
{
MyCustomEventArgs e = new MyCustomEventArgs();
if (this.MyTextBox.Text.ToUpper().Contains("BAR"))
e.IsBarSpecified = true;
else
e.IsBarSpecified = false;
this.OnMyFooBar(e);
}

//And raising the MyFooBar event is the same, other than changing to the custom EventArgs:
protected virtual void OnMyFooBar(MyCustomEventArgs e)
{
if MyFooBar != null)
MyFooBar(this, e);
}

And in your Form, you'd have this instead:

this.oMyControl.MyFooBar += new EventHandler<MyCustomEventArgs>(this.oMyControl_MyFooBarHandler);

private void oMyControl_MyFooBarHandler(object sender, MyCustomEventArgs e)
{
// whatever your code needs to be, such as
string message = "FOO was specified!";

if (e.IsBarSpecified == true)
message += " BAR too!");

MessageBox.Show(message);
}

Or this, if you want to use an anonymous delegate (note that since I'm utilizing the custom MyCustomEventArgs, I'll need to specify them here, whereas I didn't need any of the parameters in the first example):

this.oMyControl.MyFooBar += delegate(object sender, MyCustomEventArgs e)
{
// whatever your code needs to be, such as
string message = "FOO was specified!";

if (e.IsBarSpecified == true)
message += " BAR too!");

MessageBox.Show(message);
};

Sunday, March 07, 2010

Uncommitted Child Table Changes

A few months ago, there was a question on the MSDN forums that reminded me of a similar question quite some time ago that I had answered. The issue crops up with parent/child DataTables using Relations. The symptoms of the problem are that your Child table is often left with uncommitted changes, even if you thought you properly did an .EndEdit() on that Child table. This blog post will explain why that happens and what to do about it.

OK, so let’s get some sample stuff set up first.

// First, let's set the BindingSource using MyRelation
this.bsParent = new BindingSource();
this.bsChild = new BindingSource();

this.bsParent.DataSource = this.MyDataSet;
this.bsParent.DataMember = "MyTable";
this.bsChild.DataSource = this.bsParent;
this.bsChild.DataMember = "MyRelation";

// now bind a grid and a textbox
this.oGrid.DataSource = this.bsParent;
this.txtLastName.DataBindings.Add("Text", this.bsChild, "description");


If you make a change in the TextBox (bound to the Child table), and move to other rows in the Grid (the Parent table), maybe even making other changes in the TextBox for each Grid row, then click on a Save button, when you do this.MyDataSet.GetChanges(), you will be missing some of those changes from your Child table. Here’s why:

1) Data in a DataRow has several different versions, one of which is a “Proposed” version and your changes are still stuck in this Proposed state and the .GetChanges() method only gets those with the “Current” version. See my earlier blog entry for a more in-depth explanation of DataRow versions and one way of handling this issue:  http://geek-goddess-bonnie.blogspot.com/2009/09/fun-with-datasets.html

2) Because you’ve made changes to child records that are related to different parent records, then the bsChild.EndEdit() only commits the Proposed changes for the current relation, even though you've changed other rows with different parents.

At first, I thought a good solution to this was to create a third BindingSource associated with the entire Child table, having nothing whatsoever to do with the Relationship. That way, when you Save, you could call bsChildTable.EndEdit() rather than bsChild.EndEdit(). Sounds good in theory, but unfortunately, it did *NOT* work.

So, are we stuck using the CommitProposedChanges() method I created in the above-mentioned earlier blog post? (You *did* read that post I hope).  Well, it will still work just fine. But, because we are using relationships and BindingSources based on those relationships, we can speed it up a bit as follows:

// defining ParentTable simply for clarity of the example
DataTable ParentTable = this.MyDataSet.Tables["MyTable"];

for (int i = 0; i < ParentTable.Rows.Count; i++)
{
this.bsParent.Position = i;
this.bsParent.EndEdit();
this.bsChild.EndEdit();
}


So, all we’re doing is spinning through the Parent table, moving the “record pointer” (setting the .Position property) to each parent row. This then “re-sets” the current relationship with each iteration through the Parent table’s rows so that the bsChild.EndEdit() applies to each successive relation.

Sunday, February 28, 2010

CheckBox Class Bound to Non-Booleans

Well, it’s been awhile since I’ve posted. I have no excuse, other than I’ve been super-busy, but aren’t we all? So … lousy excuse. One of my kids, who calls frequently, always starts out the conversation with “So, what are you doing?” and I always reply “Working”. That invariably gets a response from him of  “How can an un-employed person always be working?!?” Well, just because I’m not getting paid, doesn’t mean that I’m not busy working on the next latest-and-greatest idea to save humanity … or at least make life easier. ;0)

Anyway, that said, I’m going to post a pretty quick-and-dirty class here, but it addresses an issue I see frequently asked on the forums. As we all know, a CheckBox is typically bound to a boolean value. I mean, it’s either checked or it’s not … true or false. But, sometimes developers  have to deal with legacy data from legacy databases, or maybe just poorly designed databases, where something other than a boolean (or bit in many databases) is used to represent true/false … character strings such as “T”/”F” or “Y”/”N”.

The key point to making this work, is to handle the Format and Parse events of the Binding. This class can be extended to be able to used with other strings, such as “T”/”F”, but I’ll leave that as an exercise for the reader:

public class BBCheckBoxString : System.Windows.Forms.CheckBox
{
protected Binding oBinding = null;

public virtual void DataBind(System.Data.DataTable Data, string Column)
{
this.Checked = false;
this.oBinding = new Binding("Checked", Data, Column);

this.oBinding.Format += new ConvertEventHandler(this.FormatHandler);
this.oBinding.Parse += new ConvertEventHandler(this.ParseHandler);

this.DataBindings.Add(this.oBinding);
}
protected virtual void FormatHandler(object sender, ConvertEventArgs e)
{
if (e.Value.ToString() == "Y")
e.Value = true;
else
e.Value = false;
}
protected virtual void ParseHandler(object sender, ConvertEventArgs e)
{
if ((bool)e.Value == true)
e.Value = "Y";
else
e.Value = "N";
}
}

Pretty easy, right? The Format event takes the value of the column in your DataTable (“Y”/”N”) and converts it to true/false to be displayed as a checkmark (or empty box). The Parse handler does the opposite. It takes the value of the Checked property (true/false) and converts it to “Y”/”N” to be placed back in the data column.

Wednesday, December 30, 2009

Getting Non-Null Data Redux

It has been pointed out to me that my previous post about this topic is a bit out-dated. Yes, it is and I did mention in that post that the code I posted was from an old 1.1 class that I never bothered to update when things like extension methods came along in subsequent .NET versions.

Well, I guess I’ve been chastised enough for it, so I’ll post some new code using extension methods. But first, I do want to say something about extension methods. They are cool, they make some things much easier (as I’ll illustrate at the end of this post) but they can also be over-used and therefore abused (IMHO). When over-using extension methods, it may be very easy to forget that these new methods are not native to .NET, that you (or another developer on your team) has created them. But, I suppose that will be brought home to you when you work on other apps that don’t have the extension method code in them … it just may take you awhile to remember, “Oh yeah, Intellisense isn’t showing this method because it isn’t there natively. Darn!”

One other note about the previously posted code (which I will correct in that post), is that I used code like this:

if (Test != DBNull.Value && Test != null)

When, of course, it should have been the other way around, silly me:

if (Test != null && Test != DBNull.Value)

So, without further ado, here’s the revised version using extension method (and really, all that has to be done is to add “this” to each method signature and I also changed the name of the class):

public static class BBExtensions
{
public static object GetNonNull(this object Test, object Default)
{
if (Test != null && Test != DBNull.Value)
return Test;
else
return Default;
}
public static string GetNonNull(this object Test, string Default)
{
if (Test != null && Test != DBNull.Value)
{
if(Test is DateTime)
{
DateTime TestDT = Convert.ToDateTime(Test);
DateTime SqlNull = new DateTime(1900, 1, 1);

if(TestDT == SqlNull)
return Default;
}
else if (Test is bool)
{
bool YesNo = Convert.ToBoolean(Test);
if (YesNo)
return "Yes";
else
return "No";
}
return Test.ToString().Trim();
}
else
return Default;
}
public static int GetNonNull(this object Test, int Default)
{
if (Test != null && Test != DBNull.Value)
return Convert.ToInt32(Test);
else
return Default;
}
public static DateTime GetNonNull(this object Test, DateTime Default)
{
if (Test != null && Test != DBNull.Value)
{
DateTime TestDT = Convert.ToDateTime(Test);
DateTime SqlNull = new DateTime(1900, 1, 1);
DateTime NetNull = new DateTime(1, 1, 1);
if(TestDT != SqlNull && TestDT != NetNull)
return TestDT;
else
return Default;
}
else
return Default;
}
public static string GetNonNullDate(this object Test, string Default)
{
if (Test != null && Test != DBNull.Value)
{
if(Test is DateTime)
{
DateTime TestDT = Convert.ToDateTime(Test);
DateTime SqlNull = new DateTime(1900, 1, 1);
if(TestDT != SqlNull)
return TestDT.ToShortDateString();
}
return Default;
}
else
return Default;
}
public static DateTime GetNonNullDate(this object Test)
{
if (Test != null && Test != DBNull.Value && Test is DateTime)
return Convert.ToDateTime(Test);
else
return new DateTime(1900, 1, 1);
}
}

So, now why is this better than the old CommonFunctions class I had? Well, here’s how you had to use the old class:

int MyInt = CommonFunctions.GetNonNull(MyDataSet.Tables[0].Rows[0]["MyColumn"], 0);

// -or-

DateTime MyDatetime = CommonFunctions.GetNonNullDate(MyDataSet.Tables[0].Rows[0]["MyDateColumn"])

And here’s the extension method way of doing this, a bit cleaner:

int MyInt = MyDataSet.Tables[0].Rows[0]["MyColumn"].GetNonNull(0);

// -or-

DateTime MyDatetime = MyDataSet.Tables[0].Rows[0]["MyDateColumn"].GetNonNullDate();

Sunday, December 20, 2009

DefaultValue for Properties

When in the Designer for a Form, everyone knows that you can go to the Properties window and change a property on the form or a control. You most likely also know that you can then right-click on any changed property, and choose "Reset" to set it back to its Default Value.

What code do you need in your own controls to get that to work? You need code in two places: in the Constructor to set the value to begin with, and a [DefaultValue] attribute for the Property itself:

public class MyTextBox : TextBox
{
private string m_MyProperty;

public MyTextBox
{
this.m_MyProperty = "";

// As an additional bonus, I'm showing you two ways to do color
this.BackColor = System.Drawing.Color.FromArgb(90, 100, 240);
this.ForeColor = System.Drawing.Color.Firebrick; ;
}

[DefaultValue("")]
public string MyProperty
{
get {return this.m_MyProperty;}
set {this.m_MyProperty = value;}
}
[DefaultValue(typeof(System.Drawing.Color), "90,100,240")]
public override System.Drawing.Color BackColor
{
get
{
return base.BackColor;
}
set
{
base.BackColor = value;
}
}
[DefaultValue(typeof(System.Drawing.Color), "Firebrick")]
public override System.Drawing.Color ForeColor
{
get
{
return base.ForeColor;
}
set
{
base.ForeColor = value;
}
}
}

Some properties aren't virtual and can't be overridden. For those properties, you can use "new" instead of "override".

The [DefaultValue] attribute serves two purposes:

  1. It allows the property to be easily Reset to it's Default Value from the Property Sheet.
  2. It prevents the code that sets the default value from actually showing up in the InitializeComponent() method.

That second point is pretty important. Let me illustrate why. Say that you've not used the [DefaultValue] attribute in your TextBox, but simply set the value of the BackColor and ForeColor properties in your MyTextBox constructor, like this:

public class MyTextBox : TextBox
{
public MyTextBox()
{
this.BackColor = Color.DarkGreen;
this.ForeColor = Color.Firebrick;
}
}

When you drop this TextBox onto a Form, the BackColor and ForeColor will be explicitly set in the code  generated in the  InitializeComponent() method of the Form (IOW, you’ll have the code to set BackColor and ForeColor for every TextBox you drop on your design surface). Consequently, if you later decide to change the color in your MyTextBox class, you have to revisit every single Form that you ever dropped a MyTextBox on, to change it to the new default value. Not good!

Conversely, let's look at the opposite scenario where you do include a property with a [DefaultValue] attribute, but you don't initialize that in the constructor. So, your class looks like this:

public class MyTextBox : TextBox
{
// bad code! Do not try this at home! ;0)
public MyTextBox()
{
}

[DefaultValue(typeof(System.Drawing.Color), "DarkGreen")]
public override System.Drawing.Color BackColor
{
get {return base.BackColor;}
set {base.BackColor = value;}
}
[DefaultValue(typeof(System.Drawing.Color), "Firebrick")]
public override System.Drawing.Color ForeColor
{
get {return base.ForeColor;}
set {base.ForeColor = value;}
}
}

When you drop MyTextBox on a Form now, it will default to a color of SystemColors.Control for the BackColor property and SystemColors.WindowText for the ForeColor property, and the IDE will generate the code in the InitializeComponent() method of the Form where you dropped MyTextBox onto, unless you go to the Property Sheet, right-click the BackColor and choose "Reset" (and likewise for ForeColor). Once you do this, the correct color appears for the TextBox in the Designer, the IDE removes the setting of the BackColor and ForeColor properties in the InitializeComponent() method and all looks fine ... until you decide to change the default to something else in your MyTextBox class ... since your TextBox doesn't initialize its BackColor and ForeColor properties in its constructor, the Form goes back to displaying SystemColors.Control and SystemColors.WindowText (even though it's not hard-coded in the InitializeComponent() method).  Again, this is not good!

Suffice it to say that you simply must do both -- initialize it in the constructor and specify the [DefaultValue] attribute. Just something that you're going to have to remember to do!!

Monday, November 30, 2009

Hooking Into the Form's Events, from Form Controls

Have you ever had the need to have a Control on your Form hook into some of the Form’s events? For example, say you have a Control on your Form that needs to do something extra when the Form Loads or the Closing event is triggered.

Let's use an example to illustrate how we might accomplish this. Let's use the ListView as an example. First, we'll sub-class the ListView Control. As you can see, we override the OnParentChanged event in the ListView sub-class.

We’ll utilize the TopLevelControl (not the Parent). If the TopLevelControl is null then we hookup event handlers backwards through the control hierarchy as each control is parented. When we finally get to a TopLevelControl for a Form type we hookup the load/closing event handlers.

public class MyListView : System.Windows.Forms.ListView
{
private Form FormParent = null;

public MyListView()
{
}

protected override void OnParentChanged(EventArgs e)
{
base.OnParentChanged(e);

if (this.FormParent != null)
return;

if (this.DesignMode == false)
{
if (this.TopLevelControl != null && this.TopLevelControl is Form)
{
this.FormParent = (Form)this.TopLevelControl;
this.EstablishParentEvents();
}
else
{
Control LastParent = this;

while(LastParent != null)
{
LastParent.ParentChanged += new EventHandler(LastParent_ParentChanged);
LastParent = LastParent.Parent;
}
}
}
}

private void EstablishParentEvents()
{
this.FormParent.Closing += new CancelEventHandler(MyListView_Closing);
this.FormParent.Load += new EventHandler(MyListView_Load);
}

private void MyListView_Closing(object sender, CancelEventArgs e)
{
// put your extra code here

if (this.FormParent != null)
{
this.FormParent.Closing -= new CancelEventHandler(MyListView_Closing);
this.FormParent.Load -= new EventHandler(MyListView_Load);
}
}

private void MyListView_Load(object sender, EventArgs e)
{
// put your extra code here
}

private void LastParent_ParentChanged(object sender, EventArgs e)
{
Control Source = (Control)sender;

if (Source.TopLevelControl != null && Source.TopLevelControl is Form)
{
this.FormParent = (Form)Source.TopLevelControl;
this.EstablishParentEvents();
}
}
}

Thanks to Neil Tonkin in Message #1084683 from the Universal Thread

Friday, November 20, 2009

Reflection Class Redux

I’m sorry to say that there was a bug of sorts in the MyReflectionClass posted in my blog entry back in September (Reflection In .NET). It was in the LoadAssembly() method and it’s been corrected in the original post.

One of the comments in that original post (the comment has been modified now) was that you might need to include the full path of the Assembly as part of the Assembly name. Well,  we really do have to take into account a path to the Assembly, but not as part of its name, which was the implication of my original comment. 

Sorry for any confusion or pulling of hair that this has caused. =0(

Thursday, November 19, 2009

Dynamic Menu Items

There was a question recently on the Universal Thread about dynamically adding MenuItems to a Form. The data for these dynamically added Items can be obtained from anywhere, like from your database. This fits in quite nicely with the first substantial post I wrote in this blog back in September, Reflection in .NET, because you can use these dynamically added Items to launch new DLLs that you might create (for example, a custom form for one of your customers), via Reflection, without having to recompile and re-distribute your entire application. Just supply the newly-created DLL. At my last company, we used DevExpress SideBars and incorporated this dynamic functionality that way.

So, without further ado, here’s the first thing: the code you need to dynamically add the menu items. Note that this creates different sub-classes of MenuItems, depending on your data:

private void TestMenuAddItemsDynamically()
{
MenuItem item; // This is so you can use MenuItem sub-classes
foreach (DataRow row in this.oData.Rows)
{
if (string.IsNullOrEmpty(row["assembly"].ToString()) == false)
{
item = new LaunchMenuItem(row["description"].ToString(), row["assembly"].ToString(), row["class"].ToString());
this.AddMenuItem("Custom Forms", item);
}
else
if (string.IsNullOrEmpty(row["url"].ToString()) == false)
{
item = new FavoritesMenuItem(row["description"].ToString(), row["url"].ToString());
this.AddMenuItem("Favorites", item);
}
else
{
item = new DefaultMenuItem(row["description"].ToString());
this.AddMenuItem("Dynamic Menu", item);
}
}
}

Next, I’ll show you the LaunchMenuItem class, since it is what this post is focusing on.

// Used to launch a DLL by Reflection
public class LaunchMenuItem : MenuItem
{
protected string AssemblyName;
protected string ClassName;

public LaunchMenuItem(string text, string assemblyName, string className)
: base(text)
{
this.Click += new System.EventHandler(this.ClickHandler);
this.AssemblyName = assemblyName;
this.ClassName = className;
}
protected virtual void ClickHandler(object sender, System.EventArgs e)
{
MyReflectionClass oReflect = new MyReflectionClass(this.AssemblyName, this.ClassName);

// In it's simplest usage, I will assume that the class I am instantiating is a Form
// Expanding on this concept is left as an exercise for the reader.
// I've also left out error checking for the instantiated object

string message = "";
Form oForm = oReflect.InstantiateClass(ref message) as Form;
if (oForm == null)
MessageBox.Show(message);
else
oForm.Show();
}
}

Note that the above class uses the MyReflectionClass from my previous post on the subject, Reflection In .NET.

The other custom MenuItem classes would contain other things to do in their Click event handlers, such as browsing to a URL link inside a BrowserControl on your Form (for the FavoritesMenuItem class). I’m not including that code in this example … I leave it as an exercise for the reader.

There’s one more method to show, and that’s a common method that will add any MenuItem to the Form’s Menu. Notice that it does things like check to see if the top menu item already exists (“Custom Forms”, “Favorites” and “Dynamic Menu” in the above example). It adds it if it doesn’t, and then adds the new MenuItems under it.

// Generic method for adding to any Menu
private void AddMenuItem(string name, MenuItem item)
{
string lookForName = name.Replace("&", "");

// Find top-level menu item
MenuItem addTo = null;
for (int i = 0; i < this.Menu.MenuItems.Count; i++)
{
MenuItem topLevel = this.Menu.MenuItems[i];
if (string.Compare(topLevel.Text.Replace("&", ""), lookForName, true) == 0)
{
addTo = topLevel;
break;
}
}

// Was a top-level menu item found?
if (addTo == null)
{
addTo = new MenuItem(name);
this.Menu.MenuItems.Add(addTo);
addTo.Index = this.Menu.MenuItems.Count - 2;
}

addTo.MenuItems.Add(item);
}

That about wraps it up. I hope this has given my readers lots of ideas to go forth and try out some cool dynamic stuff.

Sunday, November 15, 2009

Setting Focus to a Control at Form Load

I used to write a “.Net Tips and Tricks” column for an online magazine associated with a forum called the  Universal Thread. The magazine has been known by several names, the Universal Thread Magazine, Level Extreme .NET Magazine and simply the UT Mag. Unfortunately, after being in “publication” since 2001, the last issue was in April of this year and it doesn’t look like it will be published anymore.

So, if no one minds, I think it’s time to start including a few of the Tips from my columns over the years. The format of my column was to garner tidbits of wisdom from other people’s posts on the UT, re-work them into a good format for a Tip, and credit the people who wrote the post (sometime it was even from a post that I wrote).

So, let’s start out with this --- how about a simple WinForms tip. Nothing earth-shattering here, but worth mentioning.

Normally, the Focus() method of a control is used to move the focus to that control:

private void MyButton_Click(object sender, System.EventArgs e)
{
// Move the Focus elsewhere
this.MySpecialTextBox.Focus();
}

This works at any time, except during Form/Control Load. Then, you simply have to set the ActiveControl:

private void MyForm_Load(object sender, System.EventArgs e)
{
// Start the Form with the Focus on a certain control
this.ActiveControl = this.MySpecialTextBox;
}

Thanks to Kevin McNeish in Message #1080245 on the Universal Thread.

Thursday, November 05, 2009

Getting Non-Null Data

UPDATE: See my new post on this topic. (I also corrected code in this current post, where I changed to test for null before testing for DBNull.Value ... it was an oversight on my part. Sorry, hope it didn't cause anyone problems).

I see questions along these lines all the time:

//I'm doing this:

int CustID = (int)dsCustomer.Tables["Customer"].Rows[0]["CustID"];

// It throws an exception because CustID is DBNull in the data.
// How do I handle this?


I have a CommonFunctions class that I use for things such as a GetNonNull( ) method (it's an old class, dating back to the 1.1 days, but it still works fine and so I have never updated it for 2.0, haven't really looked to see if it's even necessary).  This will work for any type of object, not just data in a DataSet, but is seems that DataSet access is  the commonly asked question.

This is implemented with many overloads, but here's an example of just a few:

public class CommonFunctions
{
public static object GetNonNull(object Test, object Default)
{
if (Test != null && Test != DBNull.Value)
return Test;
else
return Default;
}
public static string GetNonNull(object Test, string Default)
{
if (Test != null && Test != DBNull.Value)
{
if(Test is DateTime)
{
DateTime TestDT = Convert.ToDateTime(Test);
DateTime SqlNull = new DateTime(1900, 1, 1);

if(TestDT == SqlNull)
return Default;
}
else
if (Test is bool)
{
bool YesNo = Convert.ToBoolean(Test);
if (YesNo)
return "Yes";
else
return "No";
}

return Test.ToString().Trim();
}
else
return Default;
}
public static int GetNonNull(object Test, int Default)
{
if (Test != null && Test != DBNull.Value)
return Convert.ToInt32(Test);
else
return Default;
}
public static DateTime GetNonNull(object Test, DateTime Default)
{

if (Test != null && Test != DBNull.Value)
{
DateTime TestDT = Convert.ToDateTime(Test);
DateTime SqlNull = new DateTime(1900, 1, 1);
DateTime NetNull = new DateTime(1, 1, 1);

if(TestDT != SqlNull && TestDT != NetNull)
return TestDT;
else
return Default;
}
else
return Default;
}
}

These are just a sample of the overloads I use. I have a few more such as for bool, decimal, long and even a few differently named methods specifically for Dates, such as these next two:

public static string GetNonNullDate(object Test, string Default)
{
if (Test != null && Test != DBNull.Value)
{
if(Test is DateTime)
{
DateTime TestDT = Convert.ToDateTime(Test);
DateTime SqlNull = new DateTime(1900, 1, 1);

if(TestDT != SqlNull)
return TestDT.ToShortDateString();
}

return Default;
}
else
return Default;
}
public static DateTime GetNonNullDate(object Test)
{
if (Test != null && Test != DBNull.Value && Test is DateTime)
return Convert.ToDateTime(Test);
else
return new DateTime(1900, 1, 1);
}


Anyway, you get the point. Note that these are static methods, so no instantiation of the CommonFunctions class is necessary.To use them, you would simply have something like this:

int MyInt = CommonFunctions.GetNonNull(MyDataSet.Tables[0].Rows[0]["MyColumn"], 0);

// -or-

DateTime MyDatetime = CommonFunctions.GetNonNullDate(MyDataSet.Tables[0].Rows[0]["MyDateColumn"])