ASP.NET下Control的Deep Clone
最近在開發中有用到control的克隆,在網上搜索了許多文章,總結后代碼如下:
原由:
在做GridView的模板列生成方法時,想使用一個通用的方法,代碼如下:
代码
public class GridViewTemplate : ITemplate
{
Control _control;
public GridViewTemplate(Control control)
{
_control = control;
}
public void InstantiateIn(Control container)
{
//Control descontrol = CloneControl(_control);
//container.Controls.Add(descontrol);
container.Controls.Add(_control);
}
}
{
Control _control;
public GridViewTemplate(Control control)
{
_control = control;
}
public void InstantiateIn(Control container)
{
//Control descontrol = CloneControl(_control);
//container.Controls.Add(descontrol);
container.Controls.Add(_control);
}
}
這种做法的優點是生成的模板列內的控件由生成模板時生成在代入,不需要在iTemplate中寫死指定
那缺點很明顯,就是所有內部控件在內一列他的hashcode是一樣的,也就意味著整個gridview只有最后一行資料才能顯示正常的值,其它行的值都是空白.
解決方法:最后想到了在Itemplate中的InstantiateIn方法中用到contrl的克隆.才解決了這個問題.
修改后正確運行的代碼為
代码
public void InstantiateIn(Control container)
{
Control descontrol = CloneControl(_control);
container.Controls.Add(descontrol);
}
{
Control descontrol = CloneControl(_control);
container.Controls.Add(descontrol);
}
下面是關於克隆的代碼:
1.Clone Method
代码
private Control CloneControl(Control src_ctl)
{
try
{
Type t = src_ctl.GetType();
Object obj = Activator.CreateInstance(t);
Control dst_ctl = (Control)obj;
PropertyDescriptorCollection src_pdc = TypeDescriptor.GetProperties(src_ctl);
PropertyDescriptorCollection dst_pdc = TypeDescriptor.GetProperties(dst_ctl);
for (int i = 0; i < src_pdc.Count; i++)
{
if (src_pdc[i].Attributes.Contains(DesignerSerializationVisibilityAttribute.Content))
{
object collection_val = src_pdc[i].GetValue(src_ctl);
if ((collection_val is IList) == true)
{
foreach (object child in (IList)collection_val)
{
Control new_child = CloneControl(child as Control);
object dst_collection_val = dst_pdc[i].GetValue(dst_ctl);
((IList)dst_collection_val).Add(new_child);
}
}
}
else
{
dst_pdc[src_pdc[i].Name].SetValue(dst_ctl, src_pdc[i].GetValue(src_ctl));
}
}
EventDescriptorCollection events = TypeDescriptor.GetEvents(src_ctl);
for (int i = 0, cnt = events.Count; i < cnt; i++)
{
EventDatum ed = EventDatum.Create(src_ctl, events[i]);
if (ed != null)
ed.Wire(dst_ctl);
}
return dst_ctl;
}
catch (Exception ex)
{
throw ex;
return null;
}
}
{
try
{
Type t = src_ctl.GetType();
Object obj = Activator.CreateInstance(t);
Control dst_ctl = (Control)obj;
PropertyDescriptorCollection src_pdc = TypeDescriptor.GetProperties(src_ctl);
PropertyDescriptorCollection dst_pdc = TypeDescriptor.GetProperties(dst_ctl);
for (int i = 0; i < src_pdc.Count; i++)
{
if (src_pdc[i].Attributes.Contains(DesignerSerializationVisibilityAttribute.Content))
{
object collection_val = src_pdc[i].GetValue(src_ctl);
if ((collection_val is IList) == true)
{
foreach (object child in (IList)collection_val)
{
Control new_child = CloneControl(child as Control);
object dst_collection_val = dst_pdc[i].GetValue(dst_ctl);
((IList)dst_collection_val).Add(new_child);
}
}
}
else
{
dst_pdc[src_pdc[i].Name].SetValue(dst_ctl, src_pdc[i].GetValue(src_ctl));
}
}
EventDescriptorCollection events = TypeDescriptor.GetEvents(src_ctl);
for (int i = 0, cnt = events.Count; i < cnt; i++)
{
EventDatum ed = EventDatum.Create(src_ctl, events[i]);
if (ed != null)
ed.Wire(dst_ctl);
}
return dst_ctl;
}
catch (Exception ex)
{
throw ex;
return null;
}
}
2.Clone Event Class
代码
public class EventDatum
{
#region Fields
private EventDescriptor _eventDesc;
private Delegate _event;
#endregion
#region Static
private static BindingFlags All
{
get
{
return
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.IgnoreCase |
BindingFlags.Static;
}
}
private static MethodInfo GetEventsMethod(Type objType)
{
MethodInfo mi = objType.GetMethod("get_Events", All);
if ((mi == null) & (objType.BaseType != null))
mi = GetEventsMethod(objType.BaseType);
return mi;
}
private static EventHandlerList GetEvents(object obj)
{
MethodInfo mi = GetEventsMethod(obj.GetType());
if (mi == null) return null;
return (EventHandlerList)mi.Invoke(obj, new object[] { });
}
private static System.Reflection.FieldInfo GetEventIDField(Type objType, string eventName)
{
System.Reflection.FieldInfo fi = objType.GetField("Event" + eventName, All);
if ((fi == null) & (objType.BaseType != null))
fi = GetEventIDField(objType.BaseType, eventName);
return fi;
}
private static object GetEventID(object obj, string eventName)
{
System.Reflection.FieldInfo fi = GetEventIDField(obj.GetType(), eventName);
if (fi == null)
return null;
return fi.GetValue(obj);
}
public static EventDatum Create(object obj, EventDescriptor desc)
{
EventHandlerList list = GetEvents(obj);
if (list == null)
return null;
object key = GetEventID(obj, desc.Name);
if (key == null)
return null;
Delegate evnt = list[key];
if (evnt == null)
return null;
return new EventDatum(desc, evnt);
}
#endregion
#region Constructors
internal EventDatum(EventDescriptor desc, Delegate aEvent)
{
_eventDesc = desc;
_event = aEvent;
}
#endregion
public void Wire(object obj)
{
_eventDesc.AddEventHandler(obj, _event);
}
public void Unwire(object obj)
{
_eventDesc.RemoveEventHandler(obj, _event);
}
}
}
{
#region Fields
private EventDescriptor _eventDesc;
private Delegate _event;
#endregion
#region Static
private static BindingFlags All
{
get
{
return
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.IgnoreCase |
BindingFlags.Static;
}
}
private static MethodInfo GetEventsMethod(Type objType)
{
MethodInfo mi = objType.GetMethod("get_Events", All);
if ((mi == null) & (objType.BaseType != null))
mi = GetEventsMethod(objType.BaseType);
return mi;
}
private static EventHandlerList GetEvents(object obj)
{
MethodInfo mi = GetEventsMethod(obj.GetType());
if (mi == null) return null;
return (EventHandlerList)mi.Invoke(obj, new object[] { });
}
private static System.Reflection.FieldInfo GetEventIDField(Type objType, string eventName)
{
System.Reflection.FieldInfo fi = objType.GetField("Event" + eventName, All);
if ((fi == null) & (objType.BaseType != null))
fi = GetEventIDField(objType.BaseType, eventName);
return fi;
}
private static object GetEventID(object obj, string eventName)
{
System.Reflection.FieldInfo fi = GetEventIDField(obj.GetType(), eventName);
if (fi == null)
return null;
return fi.GetValue(obj);
}
public static EventDatum Create(object obj, EventDescriptor desc)
{
EventHandlerList list = GetEvents(obj);
if (list == null)
return null;
object key = GetEventID(obj, desc.Name);
if (key == null)
return null;
Delegate evnt = list[key];
if (evnt == null)
return null;
return new EventDatum(desc, evnt);
}
#endregion
#region Constructors
internal EventDatum(EventDescriptor desc, Delegate aEvent)
{
_eventDesc = desc;
_event = aEvent;
}
#endregion
public void Wire(object obj)
{
_eventDesc.AddEventHandler(obj, _event);
}
public void Unwire(object obj)
{
_eventDesc.RemoveEventHandler(obj, _event);
}
}
}
這個克隆方法的優點是既copy了原control的屬性,又copy了原control的事件.
現在放出代碼,希望對大家有所幫助.