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

 

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

 

 

 

你可能感兴趣的:(asp.net)