風之力

导航

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);
            }
}

 

這种做法的優點是生成的模板列內的控件由生成模板時生成在代入,不需要在iTemplate中寫死指定

那缺點很明顯,就是所有內部控件在內一列他的hashcode是一樣的,也就意味著整個gridview只有最后一行資料才能顯示正常的值,其它行的值都是空白.

解決方法:最后想到了在Itemplate中的InstantiateIn方法中用到contrl的克隆.才解決了這個問題.

修改后正確運行的代碼為

 

代码
 public void InstantiateIn(Control container)
            {
                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;
                }
            }

 

 

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 == nullreturn 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的事件.

 

現在放出代碼,希望對大家有所幫助.

 

 

 

posted on 2010-01-11 09:30  ZY.Zhou  阅读(337)  评论(0编辑  收藏  举报