Archive

Archive for the ‘C#’ Category

Simple custom event handling

February 17th, 2009

The event model in C# is based on idea of publisher and subscribers. Each publisher can have more subscribers subscribed to each event. Publisher will do some logic and publish an event to all subscribers. Subscribers will do their logic reacting to raised event. In C#, any object can publish a set of events to which other applications can subscribe. When the publishing class raises an event, all the subscribed applications are notified. Example of this behaviour can be that the application will subscribe to event which will be raised from database connection control when the connection is lost. Main application will know, that this happened and can react on that event –reconnect, show alert message, etc.

Conventions

The following important conventions are used with events:

  • Event Handlers in the .NET Framework return void and take two parameters.
  • The first paramter is the source of the event; that is the publishing object.
  • The second parameter is an object derived from EventArgs.
  • Events are properties of the class publishing the event.
  • The keyword event controls how the event property is accessed by the subscribing classes.

Example

Lets say that we have Product class which has Name property. When the name is changed we want ot change this name in Label as well. We don’t know from where this name can be changed. We will “convert” product class into event publisher and the window where is the label will subscribe to this event.

First step will be to create the event and method which will fire this event.


public class Product
{
  public string Name { get; set; }
  // Delegate
  public delegate void PropertyChangeHandler (object sender,  EventArgs data);
  // The event
  public event PropertyChangeHandler PropertyChange;
  // The method which fires the Event
  protected void OnPropertyChange (object sender,  EventArgs data)
  {
    // Check if there are any Subscribers
    if (PropertyChange!= null)
    {
      // Call the Event
      PropertyChange (this, data);
    }
  }
}

We created delegate which encapsulates any method that takes these attributes, this delegate must be implemented by all subscribers. Now we need one small change to the class. That will be to fire the event, when Name property is changed. It can be nice to pass information about this change to subscribers with what have been changed and to have old value and new value. For this we will create PropertyChangeEventArgs class which will be derived from EventArgs.


public class PropertyChangeEventArgs : EventArgs
{
  public string PropertyName { get; internal set; }
  public object OldValue { get; internal set; }
  public object NewValue { get; internal set; }
  public PropertyChangeEventArgs(string propertyName, object oldValue, object newValue)
  {
    this.PropertyName = propertyName;
    this.OldValue = oldValue;
    this.NewValue = newValue;
  }
}

public class Product
{
  private string name;
  public string Name {
    get
    {
      this.name;
    }
    set
    {
      Object old = this.name;
      this.name = value;
      OnPropertyChange(this, new PropertyChangeEventArgs(“Name”, old, value));
    }
  }

  // Delegate
  public delegate void PropertyChangeHandler (object sender,  PropertyChangeEventArgs data);
  // The event
  public event PropertyChangeHandler PropertyChange;
  // The method which fires the Event
  protected void OnPropertyChange (object sender,  PropertyChangeEventArgs data)
  {
    // Check if there are any Subscribers
    if (PropertyChange!= null)
    {
      // Call the Event
      PropertyChange (this, data);
    }
  }
}

Now we are done with the Product class (publisher) and can subscribe to the OnPropertyChange event.


protected void Page_Init(object sender, EventArgs e)
{
  this.Product = new Product();
  this.Product.OnPropertyChange += new Product.PropertyChangeHandler(PropertyHasChanged);
}
protected void Page_Load (object sender, EventArgs e)
{
  this.Product.Name = "New name";
}

public void PropertyHasChanged (object sender,  PropertyChangeEventArgs data)
{
  if(data.PropertyName == “Name”)
  {
    this.ProductLabel.Text = (string)data.NewValue + " was " + (string)data.OldValue;
  }
}

In the Init event we created product instance and subscribe to OnPropertyChange event of Product class. In Load phase we changed name of that product. This operation fired PropertyChange and this was send to all subscribers. This calls PropertyHasChanged method with all informations.

Donwload example: Download

C# , ,

Tree traversal data structure - stored procedures

October 8th, 2008

In the first part of this article I wrote about tree traversal database structure. Now I want to show you how to prepare all stored procedures and triggers to be able to work with it effectively. From the first part we have already database structure and we filled the table with data. Now we need to have these data always with correct informations.

What can happen

There are many scenarios what can happen and you need to recreate lft and rtg in the tree. For inserting new category, deleting old one and move category under another parent, we can use one procedure:


ALTER PROCEDURE dbo.RecreateCategoryTree
  @id INT = NULL,
  @cnt INT = 0
AS
BEGIN
  SET NOCOUNT ON;
  DECLARE @actId INT,
    @actLft INT,
    @actRtg INT;
  DECLARE categories_cursor CURSOR LOCAL
  FOR
    SELECT ID, lft, rtg
    FROM dbo.Categories
    WHERE (ParentID = @id) OR (@id IS NULL AND ParentID IS NULL);
  OPEN categories_cursor
  FETCH NEXT FROM categories_cursor
  INTO @actId, @actLft, @actRtg

  WHILE @@FETCH_STATUS = 0
  BEGIN
    SET @cnt = @cnt + 1;

    UPDATE dbo.Categories SET lft = @cnt WHERE ID = @actID;

    EXEC @cnt = [dbo].[RecreateCategoryTree] @actId, @cnt;
    SET @cnt = @cnt + 1;

    UPDATE dbo.Categories SET rtg = @cnt WHERE ID = @actID;

    FETCH NEXT FROM categories_cursor
    INTO @actId, @actLft, @actRtg
  END
  CLOSE categories_cursor
  DEALLOCATE categories_cursor

  RETURN @cnt;
END
GO

When we call this stored procedure it will recreate all lft and rtg information in Categories table. Second step will be to create trigger what will be fired after insert, update or delete.


CREATE TRIGGER dbo.RecreateCategories
ON  dbo.Categories
AFTER INSERT,DELETE,UPDATE
AS
BEGIN
  SET NOCOUNT ON;
  EXEC [dbo].[RecreateCategoryTree]
END
GO

This is realy the easiest way. It will not be fast with many records. For table with a few hundred record and occasional update it’s enought. Now we can try if everything is working as we need. Try to insert into category:


INSERT INTO dbo.Categories (CategoryName, ParentID) VALUES ('Celeron', 2);

C#, Database , , , , ,

Stripping span tag from WebControl

September 15th, 2008

When I started developing web controls which are created by CreateChildControls method i run into problem that this control is surrounded by span tag.


[ToolboxData("<{0}:ExtendedLabel runat=\"server\" Text=\"Label\" />")]
public class ExtendedLabel : WebControl, INamingContainer
{
  protected override void CreateChildControls()
  {
    Label label = new Label();
    label.Text = this.Text;
    this.Controls.Add (label);
  }
}

This example will product not so nice HTML code:


<span id=”ExtendedLabel”>
  <span name=”ExtendedLabel:Label”>Test string</span>
</span>

The first label come from RenderBeginTag method which contains by default span tag. What you can do is to override both RenderBeginTag and RenderEndTag.


protected override void RenderBeginTag(HtmlTextWriter writer)
{
  writer.Text = writer.Text + "<div id=\"myTag\">";
}
protected override void RenderBeginTag(HtmlTextWriter writer)
{
  writer.Text = writer.Text + "</div>";
}

Or remove this tag completely by overriding Render method.

Original:


protected override void Render(HtmlTextWriter writer)
{
  this.RenderBeginTag(writer);
  this.RenderContents(writer);
  this.RenderEndTag(writer);
}

New:


protected override void Render(HtmlTextWriter writer)
{
  this.RenderContents(writer);
}

In these examples you have full control over behavior of the control. These is another possibility how to change or remove the outlining tag. You can extend your web control from another class.


protected ExtendedLabel () : base()
{ }

.NET, C# , , ,