|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionAnyone who has spent anytime developing applications in MS Access knows how RAD a RAD approach and system can be. Not only in a prototype or a simple two hour project, but even in full blown multi developer, multi tiered, enterprise edifices. The platform with all of its pre built functionality, readily accessible components and "at your fingertips" design interface, can save you thousands of man-hours not having to worry about UI issues.
In VS, Microsoft is obviously trying to offer data access to even those who can not code. If so, why in the world, if Bill Gates is paying the salary for the Access design interface designers, isn't he using them on the VS environment, is beyond my comprehension. Why, do I have to sift through a property manager to change the color of the text on my buttons or right align the text in a label, when Microsoft has the source code and design specs for a RAD like access? Well enough on what I'd like to see from Microsoft and now what I made for them. The one biggest loss for me when I tried moving from Access to C# was the continuous forms! We all know them. And have all used them. When you want to display many records at once but you want to layout each record, they are the perfect tools. In ASPX, it is the ever persistent "template" in Win forms, you can't find anything like it. So here it is. Once it's been created in .NET, it is now better than it ever was in Access because now it's OOP and every records panel is a true instance. Not to mention that it's usable from every .NET language like VB or managed extensions to C++. Understanding the controlUsing reflection, I clone a All this is done in two files, with one subclassed control, two utility classes, a delegate and an interface. Totaling fewer than 200 lines of code. The Central Class - The ControlThe first built-in feature I exploit is the public class NewPanel : System.Windows.Forms.Panel
The PropertiesTo make this code snippet as reusable as possible and to make it as easy as using VS's graphical layout tool, we assume that each record will be represented as a The variable created in the control like this: public System.Windows.Forms.Panel BasePanel = null;
will be assigned a reference to the design panel in the using project like this: newPanel2.BasePanel = panel1;
The point of this control is to present (and edit) data, thus said, we must have a The variable created in the control like this: public IDataSocket DataSource = null;
will be assigned a reference to the Data Container in the using project like this: newPanel2.DataSource = new DataRowCollectionSocket(dsAddresses2.Addresses.Rows);
The controls on the In code, that may look like this: this.comboBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text",
this.dsAddresses2, "Addresses.State"));
this.txtZip.DataBindings.Add(new System.Windows.Forms.Binding("Text",
this.dsAddresses2, "Addresses.Zip"));
this.txtCity.DataBindings.Add(new System.Windows.Forms.Binding("Text",
this.dsAddresses2, "Addresses.City"));
or graphically like this:
Bind FunctionThe rest of the work is done in the For some reason, you cant Control[] Carr = new Control
The Map creation: Hashtable ctMap = new Hashtable();
for(int i =0; i < Carr.Length; i++)
ctMap.Add(Carr[i].Name,i);
Function to use map: public System.Windows.Forms.Control ControlFromName(string name)
{
try
{
return Item.Controls[(int)ControlMap[name]];
}
catch(InvalidCastException)
{
return null;
}
catch(NullReferenceException)
{
return null;
}
}
We then get what we are all here for, the looping through the data. For each row (item), I clone the for(int i = 0; i < DataSource.Count; i++)
{
Panel tempPanel = (Panel)DeepCloneControl(BasePanel,i);
tempPanel.Top = i * BasePanel.Height;
tempPanel.Left = 0;
panel1.Controls.Add(tempPanel);
foreach(Control c in Carr)
{
tempPanel.Controls.Add(DeepCloneControl(c,i));
}
if(ItemDataBound != null)
ItemDataBound(this, new ContinuousItemEventArgs(tempPanel,
DataSource[i], ctMap));
}
DeepCloneControl FunctionAll the reflection needs to clone non-cloneable objects is accessible through the Type ctrlType = subject.GetType();
ConstructorInfo cInfo = ctrlType.GetConstructor(Type.EmptyTypes);
Control retControl = (Control)cInfo.Invoke(null);
At that point, all I need to do is create (through reflection / the foreach(PropertyInfo pInfo in
ctrlType.GetProperties(BindingFlags.Public|BindingFlags.Instance))
{
if (pInfo.CanWrite &&
(pInfo.PropertyType.IsValueType ||
pInfo.PropertyType.Name == "String"))
{
try
{
switch(pInfo.Name)
{
case "Parent":
break;
default:
pInfo.SetValue(retControl,pInfo.GetValue(subject,null),null);
break;
}
}
catch(Exception ex)
{
Console.WriteLine("Could not assign the value" +
" of {0} to \nObject:\t{1}\nOf Type:\t{2}\nBecause:\t{3}",
pInfo.Name, subject.Name, ctrlType.Name, ex.Message);
}
}
}
The string BindingMember = ctrlBinding.BindingMemberInfo.BindingMember;
string BindingField = BindingMember.Substring(BindingMember.LastIndexOf("."));
retControl.DataBindings.Add(ctrlBinding.PropertyName,
DataSource[i],
BindingField);
ContinuousItemDataBound & ContinuousItemEventArgsThese two items come together to bring you the control of per row (record / item) changes. The event is fired once for every row (record / item) at the end of all the processing. It gives you a chance - with the help of the MembersThe public System.Windows.Forms.Panel Item;
public object Data;
public System.Collections.Hashtable ControlMap;
IDataSocket & DataRowCollectionSocketThe public interface IDataSocket
{
int Count{get;}
object this[int index]{get;}
}
The only socket I have created so far is the public class DataRowCollectionSocket: IDataSocket
{
public System.Data.DataRowCollection Data;
public int Count
{
get
{
return Data.Count;
}
}
public object this[int index]
{
get
{
return Data[index];
}
}
}
Possible ImprovementsMany and I mean many! This is intended to demonstrate how this could be done. However, it is in no way a complete solution.
I am sure you guys can think of much more. I'd love to see where this goes.
|
||||||||||||||||||||||