關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
如何通過繼承GridView來修改在設計時綁定數據源時自動生成的ASP.Net代碼?
具體情況是這樣的,ObjectDataSource綁定到實體類,GridView幫定到ObjectDataSource,這時候,GridView會獲取實體類的構架信息,并自動生成一些列,HeaderText就是實體類的屬性名,是E文的,我現在想在GridView的CreateColumns方法中進行攔截這個生成過程,硬是把E文改為對應的中文。
結果,在設計時和運行時都可以看到是中文的,但是aspx中就不是中文的。
我就想問問,怎么樣,才能讓它在aspx中體現中文,GridView自身是怎么樣把自動生成的列寫入到aspx中的。
我已經把GridView以及幾個基類的源碼翻了好幾遍了,我肯定,我已經把CreateColumns攔截到并修改成功了,但是,它從哪里得到英文HeaderText的BoundColumn寫入到aspx中的?難道自動生成列的某些過程不需要調用CreateColumns?
經過跟蹤發現:在設計時,vs會生成這個控件的兩個實例,具體干什么我不知道,在取消數據源綁定或者重新綁定數據源的時候,其中一個實例B被銷毀,又有新的實例被創建,如此反反復復。剩下的那個實例A,只是偶爾被調用幾個方法。(有一個方法,可以在A以外的實例中,取得A實例,就是this.Site.Component as GridView。)
原來,我所攔截的CreateColumns,都是B和后面的實例,根本就沒有攔截到A,它從來不調用CreateColumns方法。在綁定數據源時,既然IDE寫入到aspx的列頭是英文,那么,我可以肯定,它讀取的是A中的列信息,因為,除了A以外,別的所有實例都已經被我捕獲到,并把列頭改為了中文,所以,IDE不可能從實例A取列信息。
但是,我有納悶了,A從來不調用CreateColumns方法,它哪里來的列信息?
最后只有一種可能,那就是:那些屬性,是被復制過去的,或者在GridViewDesigner中創建的。
這個猜想,沒有得到驗證,不過,在我把調用堆棧翻過幾遍以后,終于發現了寫入aspx的一個可疑之處:
ControlSerializer類
從代碼就可以看出來,這不就是在寫aspx嘛。只是看而已,沒有確定^_^
這個類,還有大量串行化的方法。
至于怎么發現的……
是這樣的,我寫了一個類來繼承GridView,把所有可以override的方法,都override一遍,然后,重寫的類里面,輸出當前調用堆棧信息到一個文本文件中。然后,在ide中使用這個控件,綁定數據源,取消綁定,多試幾次,就可以得到足夠的日志了。
下面是綁定到一個數據源控件時,所得到的override EnsureChildControls方法調用方法棧幀,第一個EnsureChildControls是GridView的EnsureChildControls:
EnsureChildControls <-
CompositeDataBoundControl.get_Controls <-
ControlSerializer.SerializeInnerProperties <-
ControlSerializer.SerializeInnerContents <-
ControlSerializer.SerializeInnerContents <-
ControlDesigner.GetPersistInnerHtmlInternal <-
ControlDesigner.GetPersistInnerHtml <-
ControlDesigner.GetPersistenceContent <-
IdentityBehavior.OnBehaviorNotify <-
DHTMLBehavior.Microsoft.VisualStudio.Web.Interop.Trident.IElementBehavior._Notify <-
IHTMLElement.GetOuterHTML <-
IdentityBehavior.GetOuterHTML <-
IdentityBehavior.System.Web.UI.Design.IControlDesignerTag.GetOuterContent <-
ControlDesignerSite.System.Web.UI.Design.IControlDesignerTag.GetOuterContent <-
ControlDesigner.CreateClonedControl <-
ControlDesigner.CreateViewControl <-
ControlDesigner.CreateViewControlInternal <-
ControlDesigner.get_ViewControl <-
GridViewDesigner.GetDesignTimeHtml <-
GridViewDesigner.GetDesignTimeHtml <-
ControlDesigner.GetViewRendering <-
ControlDesigner.GetViewRendering <-
IdentityBehavior.GetDesignTimeHtml <-
IdentityBehavior.RenderDesignTimeHtml <-
IdentityBehavior.UpdateView <-
IdentityBehavior.System.Web.UI.Design.IControlDesignerView.Update <-
ControlDesignerSite.System.Web.UI.Design.IControlDesignerView.Update <-
ControlDesigner.UpdateDesignTimeHtml <-
ControlDesigner.OnComponentChanged <-
ComponentChangeAction.DoAction <-
BaseUndoableAction.Microsoft.VisualStudio.Web.Interop.TriDsn.IUndoAction.DoAction <-
IUndoTransaction.Rollback <-
ASPUndoCoordinator.CancelTransaction <-
ASPUndoCoordinator.OnTransactionClosed <-
DesignerTransactionCloseEventHandler.Invoke <-
DesignerHost.OnTransactionClosed <-
DesignerHostTransaction.OnCancel <-
DesignerTransaction.Cancel <-
DesignerTransaction.Dispose
這些方法是從下往上調用的。
從中可以看到幾個GridViewDesigner的方法,大概意思就是,我綁定數據源控件后,設計時觸發ControlDesigner.UpdateDesignTimeHtml ,然后導致一系列的方法調用。
我的研究,就到這里了,下次有空再把剩下的發上來吧。
具體情況是這樣的,ObjectDataSource綁定到實體類,GridView幫定到ObjectDataSource,這時候,GridView會獲取實體類的構架信息,并自動生成一些列,HeaderText就是實體類的屬性名,是E文的,我現在想在GridView的CreateColumns方法中進行攔截這個生成過程,硬是把E文改為對應的中文。
結果,在設計時和運行時都可以看到是中文的,但是aspx中就不是中文的。
我就想問問,怎么樣,才能讓它在aspx中體現中文,GridView自身是怎么樣把自動生成的列寫入到aspx中的。
我已經把GridView以及幾個基類的源碼翻了好幾遍了,我肯定,我已經把CreateColumns攔截到并修改成功了,但是,它從哪里得到英文HeaderText的BoundColumn寫入到aspx中的?難道自動生成列的某些過程不需要調用CreateColumns?
經過跟蹤發現:在設計時,vs會生成這個控件的兩個實例,具體干什么我不知道,在取消數據源綁定或者重新綁定數據源的時候,其中一個實例B被銷毀,又有新的實例被創建,如此反反復復。剩下的那個實例A,只是偶爾被調用幾個方法。(有一個方法,可以在A以外的實例中,取得A實例,就是this.Site.Component as GridView。)
原來,我所攔截的CreateColumns,都是B和后面的實例,根本就沒有攔截到A,它從來不調用CreateColumns方法。在綁定數據源時,既然IDE寫入到aspx的列頭是英文,那么,我可以肯定,它讀取的是A中的列信息,因為,除了A以外,別的所有實例都已經被我捕獲到,并把列頭改為了中文,所以,IDE不可能從實例A取列信息。
但是,我有納悶了,A從來不調用CreateColumns方法,它哪里來的列信息?
最后只有一種可能,那就是:那些屬性,是被復制過去的,或者在GridViewDesigner中創建的。
這個猜想,沒有得到驗證,不過,在我把調用堆棧翻過幾遍以后,終于發現了寫入aspx的一個可疑之處:
ControlSerializer類
1
private static void SerializeControl(Control control, IDesignerHost host, TextWriter writer, string filter)
2
{
3
if (control == null)
4
{
5
throw new ArgumentNullException("control");
6
}
7
if (host == null)
8
{
9
throw new ArgumentNullException("host");
10
}
11
if (writer == null)
12
{
13
throw new ArgumentNullException("writer");
14
}
15
if (control is LiteralControl)
16
{
17
writer.Write(((LiteralControl) control).Text);
18
}
19
else if (control is DesignerDataBoundLiteralControl)
20
{
21
DataBinding binding = ((IDataBindingsAccessor) control).DataBindings["Text"];
22
if (binding != null)
23
{
24
writer.Write("<%# ");
25
writer.Write(binding.Expression);
26
writer.Write(" %>");
27
}
28
}
29
else if (control is UserControl)
30
{
31
IUserControlDesignerAccessor accessor = (IUserControlDesignerAccessor) control;
32
string tagName = accessor.TagName;
33
if (tagName.Length > 0)
34
{
35
writer.Write('<');
36
writer.Write(tagName);
37
writer.Write(" runat=\"server\"");
38
ObjectPersistData persistData = null;
39
IControlBuilderAccessor accessor2 = control;
40
if (accessor2.ControlBuilder != null)
41
{
42
persistData = accessor2.ControlBuilder.GetObjectPersistData();
43
}
44
SerializeAttributes(control, host, string.Empty, persistData, writer, filter);
45
writer.Write('>');
46
string innerText = accessor.InnerText;
47
if ((innerText != null) && (innerText.Length > 0))
48
{
49
writer.Write(accessor.InnerText);
50
}
51
writer.Write("</");
52
writer.Write(tagName);
53
writer.WriteLine('>');
54
}
55
}
56
else
57
{
58
string text3;
59
HtmlControl control2 = control as HtmlControl;
60
if (control2 != null)
61
{
62
text3 = control2.TagName;
63
}
64
else
65
{
66
text3 = GetTagName(control.GetType(), host);
67
}
68
writer.Write('<');
69
writer.Write(text3);
70
writer.Write(" runat=\"server\"");
71
ObjectPersistData objectPersistData = null;
72
IControlBuilderAccessor accessor3 = control;
73
if (accessor3.ControlBuilder != null)
74
{
75
objectPersistData = accessor3.ControlBuilder.GetObjectPersistData();
76
}
77
SerializeAttributes(control, host, string.Empty, objectPersistData, writer, filter);
78
writer.Write('>');
79
SerializeInnerContents(control, host, objectPersistData, writer, filter);
80
writer.Write("</");
81
writer.Write(text3);
82
writer.WriteLine('>');
83
}
84
}
private static void SerializeControl(Control control, IDesignerHost host, TextWriter writer, string filter)2
{3
if (control == null)4
{5
throw new ArgumentNullException("control");6
}7
if (host == null)8
{9
throw new ArgumentNullException("host");10
}11
if (writer == null)12
{13
throw new ArgumentNullException("writer");14
}15
if (control is LiteralControl)16
{17
writer.Write(((LiteralControl) control).Text);18
}19
else if (control is DesignerDataBoundLiteralControl)20
{21
DataBinding binding = ((IDataBindingsAccessor) control).DataBindings["Text"];22
if (binding != null)23
{24
writer.Write("<%# ");25
writer.Write(binding.Expression);26
writer.Write(" %>");27
}28
}29
else if (control is UserControl)30
{31
IUserControlDesignerAccessor accessor = (IUserControlDesignerAccessor) control;32
string tagName = accessor.TagName;33
if (tagName.Length > 0)34
{35
writer.Write('<');36
writer.Write(tagName);37
writer.Write(" runat=\"server\"");38
ObjectPersistData persistData = null;39
IControlBuilderAccessor accessor2 = control;40
if (accessor2.ControlBuilder != null)41
{42
persistData = accessor2.ControlBuilder.GetObjectPersistData();43
}44
SerializeAttributes(control, host, string.Empty, persistData, writer, filter);45
writer.Write('>');46
string innerText = accessor.InnerText;47
if ((innerText != null) && (innerText.Length > 0))48
{49
writer.Write(accessor.InnerText);50
}51
writer.Write("</");52
writer.Write(tagName);53
writer.WriteLine('>');54
}55
}56
else57
{58
string text3;59
HtmlControl control2 = control as HtmlControl;60
if (control2 != null)61
{62
text3 = control2.TagName;63
}64
else65
{66
text3 = GetTagName(control.GetType(), host);67
}68
writer.Write('<');69
writer.Write(text3);70
writer.Write(" runat=\"server\"");71
ObjectPersistData objectPersistData = null;72
IControlBuilderAccessor accessor3 = control;73
if (accessor3.ControlBuilder != null)74
{75
objectPersistData = accessor3.ControlBuilder.GetObjectPersistData();76
}77
SerializeAttributes(control, host, string.Empty, objectPersistData, writer, filter);78
writer.Write('>');79
SerializeInnerContents(control, host, objectPersistData, writer, filter);80
writer.Write("</");81
writer.Write(text3);82
writer.WriteLine('>');83
}84
}從代碼就可以看出來,這不就是在寫aspx嘛。只是看而已,沒有確定^_^
這個類,還有大量串行化的方法。
至于怎么發現的……
是這樣的,我寫了一個類來繼承GridView,把所有可以override的方法,都override一遍,然后,重寫的類里面,輸出當前調用堆棧信息到一個文本文件中。然后,在ide中使用這個控件,綁定數據源,取消綁定,多試幾次,就可以得到足夠的日志了。
下面是綁定到一個數據源控件時,所得到的override EnsureChildControls方法調用方法棧幀,第一個EnsureChildControls是GridView的EnsureChildControls:
EnsureChildControls <-
CompositeDataBoundControl.get_Controls <-
ControlSerializer.SerializeInnerProperties <-
ControlSerializer.SerializeInnerContents <-
ControlSerializer.SerializeInnerContents <-
ControlDesigner.GetPersistInnerHtmlInternal <-
ControlDesigner.GetPersistInnerHtml <-
ControlDesigner.GetPersistenceContent <-
IdentityBehavior.OnBehaviorNotify <-
DHTMLBehavior.Microsoft.VisualStudio.Web.Interop.Trident.IElementBehavior._Notify <-
IHTMLElement.GetOuterHTML <-
IdentityBehavior.GetOuterHTML <-
IdentityBehavior.System.Web.UI.Design.IControlDesignerTag.GetOuterContent <-
ControlDesignerSite.System.Web.UI.Design.IControlDesignerTag.GetOuterContent <-
ControlDesigner.CreateClonedControl <-
ControlDesigner.CreateViewControl <-
ControlDesigner.CreateViewControlInternal <-
ControlDesigner.get_ViewControl <-
GridViewDesigner.GetDesignTimeHtml <-
GridViewDesigner.GetDesignTimeHtml <-
ControlDesigner.GetViewRendering <-
ControlDesigner.GetViewRendering <-
IdentityBehavior.GetDesignTimeHtml <-
IdentityBehavior.RenderDesignTimeHtml <-
IdentityBehavior.UpdateView <-
IdentityBehavior.System.Web.UI.Design.IControlDesignerView.Update <-
ControlDesignerSite.System.Web.UI.Design.IControlDesignerView.Update <-
ControlDesigner.UpdateDesignTimeHtml <-
ControlDesigner.OnComponentChanged <-
ComponentChangeAction.DoAction <-
BaseUndoableAction.Microsoft.VisualStudio.Web.Interop.TriDsn.IUndoAction.DoAction <-
IUndoTransaction.Rollback <-
ASPUndoCoordinator.CancelTransaction <-
ASPUndoCoordinator.OnTransactionClosed <-
DesignerTransactionCloseEventHandler.Invoke <-
DesignerHost.OnTransactionClosed <-
DesignerHostTransaction.OnCancel <-
DesignerTransaction.Cancel <-
DesignerTransaction.Dispose
這些方法是從下往上調用的。
從中可以看到幾個GridViewDesigner的方法,大概意思就是,我綁定數據源控件后,設計時觸發ControlDesigner.UpdateDesignTimeHtml ,然后導致一系列的方法調用。
我的研究,就到這里了,下次有空再把剩下的發上來吧。
我不相信神話,我只相信汗水!我不相信命運,我只相信雙手!



浙公網安備 33010602011771號