Friday, 6 July 2007

ActionTree

Well, i always wanted to create a control that is generic and should provide common functionalities used in our daily programming activities. Here, in this article i have made an attempt to express my thoughts and experience on creating and managing a control which provides basic functionalites.

We know that we use activities CRUD's like Create, Save/Update, Delete in almost all UI's of applications. Also, we think that there should be a way to make these activites by using controls like buttons. We rather place buttons for each Create, Save/Update and Delete and handle their enablity and visiblity at various scenarios.
ActionTree is named after a control which will have Action basic buttons like Create, Save, Delete and provides a an object in the form of Tree to these controls to control their enablity.

Step 1:

So, to get started i am gonna create a form (can be a windows or webform, doesnt matter!).

Next, to control enabilty or visibility of these controls, i would need a class, which holds a property for each control.

public class ActionTree
{
private bool _create;

public bool Create
{
get { return _create; }
set { _create = value; }
}

private bool _save;

public bool Save
{
get { return _save; }
set { _save = value; }
}

private bool _delete;

public bool Delete
{
get { return _delete; }
set { _delete = value; }
}
}


The propeties defined in above class can be corresponds to Properties of Control's Enabiltiy or Visuality. In my case i am choosing enability.

Step 2:
for the above class, i would create one more property called HasChanged and a method NotifyChange() which will notify that property has changed (One more thing i would like to mention here is i am using Observer pattern here) as follows:


...
...

public bool Delete
{
get { return _delete; }
set
{
_delete = value;
NotifyChange();
}
}

private bool _hasChanged;

public bool HasChanged
{
get { return _hasChanged; }
}

private void NotifyChange()
{
this._hasChanged = true;
}


In NotifyChange() method, i would need to notify that property has changed. In order to do that, i am gonna create an event of type EventHandler delegate. But i also would need these properties to send out. So i am gonna create a class to hold that as well.


public class ActionTreeEventArgs : EventArgs
{
private ActionTree _actions;

public ActionTreeEventArgs(ActionTree actions)
{
this._actions = actions;
}

public ActionTree ActionTree
{
get
{
return _actions;
}
}
}


then create a event property of type EventHadnler delegate in class ActionTree which would look like as follows:

ActionTree.cs

...
...
private event EventHandler _actionTreeChanged;
public event EventHandler ActionTreeChanged
{
add
{
_actionTreeChanged += value;
}
remove
{
_actionTreeChanged -= value;
}
}


then finally i am gonna create a method in ActionTree class, to handle this event and notify.

ActionTree.cs

..
..
private void NotifyChange()
{
this._hasChanged = true;
}

private void OnActionTreeChanged()
{
EventHandler handler = this._actionTreeChanged;
if (handler != null)
{
handler.Invoke(this, new ActionTreeEventArgs(this));
}
}
...
...


and call this OnActionTreeChanged() method in NotifyChange() method. So we are nearly complete. What i mean is, at this moment, we are able to notify. and the UI who is subscribing to these notification needs to be done. that is step 3!.
so final ActionTree class looks like this!.


public class ActionTree
{
private bool _create;

public bool Create
{
get { return _create; }
set
{
_create = value;
NotifyChange();
}
}

private bool _save;

public bool Save
{
get { return _save; }
set
{
_save = value;
NotifyChange();
}
}

private bool _delete;

public bool Delete
{
get { return _delete; }
set
{
_delete = value;
NotifyChange();
}
}

private bool _hasChanged;

public bool HasChanged
{
get { return _hasChanged; }
}

private void NotifyChange()
{
this._hasChanged = true;
this.OnActionTreeChanged();
}

private void OnActionTreeChanged()
{
EventHandler handler = this._actionTreeChanged;
if (handler != null)
{
handler.Invoke(this, new ActionTreeEventArgs(this));
}
}

private event EventHandler _actionTreeChanged;
public event EventHandler ActionTreeChanged
{
add
{
_actionTreeChanged += value;
}
remove
{
_actionTreeChanged -= value;
}
}
}


Step 3:
Now we are on UI. Lets create a Windows/Web form. I am gonna create Windows form and add few buttons as said earlier as shown below:



In the form code for each button click, other buttons should be disable accorging to the funcationality requirements. So, i am gonna create handler for each button as follows:


private void btnCreate_Click(object sender, EventArgs e)
{

}

private void btnSave_Click(object sender, EventArgs e)
{

}

private void btnDelete_Click(object sender, EventArgs e)
{

}



and declare ActionTree as class variable and initialise in Load event.


private ActionTree _actions;

private void Form1_Load(object sender, EventArgs e)
{
_actions = new ActionTree();
_actions.ActionTreeChanged += new EventHandler(_actions_ActionTreeChanged);
}

private void _actions_ActionTreeChanged(object sender, ActionTreeEventArgs args)
{
this.btnCreate.Enabled = args.ActionTree.Create;
this.btnSave.Enabled = args.ActionTree.Save;
this.btnDelete.Enabled = args.ActionTree.Delete;
}



Now, we can now actually control properties of buttons using ActionTree object.
for each button's handler, i am gonna introduce the following snippet of code.


private void btnCreate_Click(object sender, EventArgs e)
{
_actions.Create = false;
_actions.Save = true;
_actions.Delete = true;
}

private void btnSave_Click(object sender, EventArgs e)
{
_actions.Create = true;
_actions.Save = false;
_actions.Delete = true;
}

private void btnDelete_Click(object sender, EventArgs e)
{
_actions.Create = true;
_actions.Save = true;
_actions.Delete = false;
}


and when i open form and click on any button, it looks like this!






Nice isn't it!!

Here is the complete code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace ActionTreeDemo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private ActionTree _actions;

private void btnCreate_Click(object sender, EventArgs e)
{
_actions.Create = false;
_actions.Save = true;
_actions.Delete = true;
}

private void btnSave_Click(object sender, EventArgs e)
{
_actions.Create = true;
_actions.Save = false;
_actions.Delete = true;
}

private void btnDelete_Click(object sender, EventArgs e)
{
_actions.Create = true;
_actions.Save = true;
_actions.Delete = false;
}

private void Form1_Load(object sender, EventArgs e)
{
_actions = new ActionTree();
_actions.ActionTreeChanged += new EventHandler(_actions_ActionTreeChanged);
}

private void _actions_ActionTreeChanged(object sender, ActionTreeEventArgs args)
{
this.btnCreate.Enabled = args.ActionTree.Create;
this.btnSave.Enabled = args.ActionTree.Save;
this.btnDelete.Enabled = args.ActionTree.Delete;
}
}

public class ActionTree
{
private bool _create;

public bool Create
{
get { return _create; }
set
{
_create = value;
NotifyChange();
}
}

private bool _save;

public bool Save
{
get { return _save; }
set
{
_save = value;
NotifyChange();
}
}

private bool _delete;

public bool Delete
{
get { return _delete; }
set
{
_delete = value;
NotifyChange();
}
}

private bool _hasChanged;

public bool HasChanged
{
get { return _hasChanged; }
}

private void NotifyChange()
{
this._hasChanged = true;
this.OnActionTreeChanged();
}

private void OnActionTreeChanged()
{
EventHandler handler = this._actionTreeChanged;
if (handler != null)
{
handler.Invoke(this, new ActionTreeEventArgs(this));
}
}

private event EventHandler _actionTreeChanged;
public event EventHandler ActionTreeChanged
{
add
{
_actionTreeChanged += value;
}
remove
{
_actionTreeChanged -= value;
}
}
}

public class ActionTreeEventArgs : EventArgs
{
private ActionTree _actions;

public ActionTreeEventArgs(ActionTree actions)
{
this._actions = actions;
}

public ActionTree ActionTree
{
get
{
return _actions;
}
}
}
}


Finally, u might ask whts the use of using this!? .. confused?... let me make it clear now.

1. ActionTree will have all button's propertes whcih you want to control
2. UI update is completely thread safe!. (irrespective of anything doing in background or asynchronous)

3. you need not have to search buttons on the screen everytime. you will always will see controls defined in ActionTree, thats why its called TREE!...

hope you enjoyed the ride and please leave your critics.

No comments: