Introduction:
This article shows a how to make a custom Wizard control using Chain of Responsibility Pattern which passes and returns data between each step. This sample creates a wizard control through windows form. Every step is responsible for its own validation and responsibility is break on each step rather then a single form. Previously we have implemented this thing through panels or some counter values. But using these techniques we will face some difficulty passing the data from one screen to another.
I have tried a lot, because I was building a wizard control which is interactive and each slide is responsible for each .I had searched on but no fruitful result I have found.
Scope:
Windows Form, C#, VB.NET, Visual Basic, Java.
Implications of using The Chain Of Responsibility Pattern:
Our intent is to delegate the responsibility of each screen (Form) so, that each one is responsible for its own request and validation. Chain of Responsibility is the pattern which addresses this problem by decoupling the sender and request handler.
Class Code:
In this approach I have responsibility class that contains the IHandler in Linked List fashion. And the picture below is best describe.
We have a Master Form, which have panel this panel contain a control on runtime as the condition satisfied. Every Control added into Master Panel on runtime.
As we have IHandler contract which have three methods
-
GetRequest(),
-
ProcessRequest(),
-
Validate()
As you will see these method implementation so, it depends on the user I just describe the "Chain of Responsibility Pattern" in Wizard Control. As this is a common problem for all WinForm developers especially who working in products.
ChainHandler holds the reference of IHandler because in this example chain handler is like a linkedlist. So, every chainhandler has a reference of IHandler.
public ChainHandler(IHandler currentHandler)
{
this.handler = currentHandler;
}
AddNext method acutally holds the next referance of the chain and because the current referance should be the previous of next that is why nexthandler holds the referance of current as a previous.
public void AddNext(ChainHandler nextHandler)
{
this.nextHandle = nextHandler;
nextHandle.AddPrevious(this);
}
Add previous holdes the previous referance of the current object.
public void AddPrevious(ChainHandler previousHandler)
{
this.previousHandle = previousHandler;
}
It will return the handler referance which current chainhanlder contain in it.
public IHandler GetCurrentHandle()
{
return this.handler;
}
this function responsiblbity is to return the next referance of the chain.
public ChainHandler GetNext()
{
return this.nextHandle;
}
this function responsibility is to return the previous referance of the chain.
public ChainHandler GetPrevious()
{
return this.previousHandle;
}
Interesting thing in this example is I am using chain and IHandler both have responsibilities, But in my case I have to use controls in my different screen. That's why chain contains the references of IHandler.
Build Chain:
On Main or startup the application we have to build the chain in This way.
private static void Start()
{
Code.ChainHandler objchain1 = new ChainOfResponsibility.Code.ChainHandler(new Controls.First());
Code.ChainHandler objchain2 = new ChainOfResponsibility.Code.ChainHandler(new Controls.Second());
Code.ChainHandler objchain3 = new ChainOfResponsibility.Code.ChainHandler(new Controls.Third());
Code.ChainHandler objchain4 = new ChainOfResponsibility.Code.ChainHandler(new Controls.Fourth());
objchain1.AddNext(objchain2);
objchain2.AddNext(objchain3);
objchain3.AddNext(objchain4);
Application.EnableVisualStyles();
Application.Run(new Form1(objchain1));
}
Transfer data between chains:
We have request ojbect which contain the data of each object to another object. Every request can save it's data in request using AddRequst() method.
public void AddRequest(object key ,object value)
{
if (objrequestCollection == null)
{
objrequestCollection = new Hashtable();
}
objrequestCollection.Add(key, value);
}
Similarly Delegated responsible request Handler will get the data GetReqeuest.
public object GetRequest(object key)
{
return objrequestCollection[key];
}
Check before ReqeustProcessing:
public bool IsRequestProcess
{
get
{
return isRequestProcess;
}
set
{
isRequestProcess = value;
}
}
Every Request is responsible to set the isRequestProceess attribute true/false. Then next responsible object will decide either process the request or not. It will help us to previous and next option. So,that every time request will not process until set the attribute value to true.
Another Implementation:
Interesting thing in this implementation is this ChainHandler is acting like a linked List Handler because it knows its next and previous chainHandler. So, that every Chain Handler contains the Ihandler.
Ihandler Code:
public interface IHandler
{
void ProcessRequest(Request req);
Request GetRequest();
bool Validate();
Panel GetPanel();
}
Another Implementation:
We can also implement this through some collection object like Arraylist, hashtable, hashmap, etc. But in this we have to ensure the limits of greater than and less than the limits.