天天看點

關于自定義控件設計時如何把屬性寫入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類

 1

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

private static void SerializeControl(Control control, IDesignerHost host, TextWriter writer, string filter)

 2

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

{

 3

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

    if (control == null)

 4

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

 5

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        throw new ArgumentNullException("control");

 6

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

    }

 7

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

    if (host == null)

 8

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

 9

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        throw new ArgumentNullException("host");

10

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

11

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

    if (writer == null)

12

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

13

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        throw new ArgumentNullException("writer");

14

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

15

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

    if (control is LiteralControl)

16

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

17

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        writer.Write(((LiteralControl) control).Text);

18

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

19

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

    else if (control is DesignerDataBoundLiteralControl)

20

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

21

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        DataBinding binding = ((IDataBindingsAccessor) control).DataBindings["Text"];

22

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        if (binding != null)

23

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

24

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            writer.Write("<%# ");

25

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            writer.Write(binding.Expression);

26

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            writer.Write(" %>");

27

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        }

28

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

29

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

    else if (control is UserControl)

30

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

31

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        IUserControlDesignerAccessor accessor = (IUserControlDesignerAccessor) control;

32

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        string tagName = accessor.TagName;

33

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        if (tagName.Length > 0)

34

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

35

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            writer.Write('<');

36

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            writer.Write(tagName);

37

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            writer.Write(" runat=\"server\"");

38

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            ObjectPersistData persistData = null;

39

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            IControlBuilderAccessor accessor2 = control;

40

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            if (accessor2.ControlBuilder != null)

41

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

42

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

                persistData = accessor2.ControlBuilder.GetObjectPersistData();

43

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            }

44

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            SerializeAttributes(control, host, string.Empty, persistData, writer, filter);

45

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            writer.Write('>');

46

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            string innerText = accessor.InnerText;

47

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            if ((innerText != null) && (innerText.Length > 0))

48

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

49

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

                writer.Write(accessor.InnerText);

50

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

51

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            writer.Write("</");

52

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

53

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            writer.WriteLine('>');

54

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

55

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

56

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

    else

57

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

58

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        string text3;

59

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        HtmlControl control2 = control as HtmlControl;

60

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        if (control2 != null)

61

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

62

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            text3 = control2.TagName;

63

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

64

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        else

65

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

66

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            text3 = GetTagName(control.GetType(), host);

67

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

68

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        writer.Write('<');

69

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        writer.Write(text3);

70

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        writer.Write(" runat=\"server\"");

71

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        ObjectPersistData objectPersistData = null;

72

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        IControlBuilderAccessor accessor3 = control;

73

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        if (accessor3.ControlBuilder != null)

74

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)
關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

75

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

            objectPersistData = accessor3.ControlBuilder.GetObjectPersistData();

76

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

77

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        SerializeAttributes(control, host, string.Empty, objectPersistData, writer, filter);

78

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        writer.Write('>');

79

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        SerializeInnerContents(control, host, objectPersistData, writer, filter);

80

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        writer.Write("</");

81

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

82

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

        writer.WriteLine('>');

83

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

84

關于自定義控件設計時如何把屬性寫入aspx中的研究(上)

}

從代碼就可以看出來,這不就是在寫aspx嘛。隻是看而已,沒有确定^_^

這個類,還有大量串行化的方法。

至于怎麼發現的……

是這樣的,我寫了一個類來繼承GridView,把所有可以override的方法,都override一遍,然後,重寫的類裡面,輸出目前調用堆棧資訊到一個文本檔案中。然後,在ide中使用這個控件,綁定資料源,取消綁定,多試幾次,就可以得到足夠的日志了。

下面是綁定到一個資料源控件時,所得到的override EnsureChildControls方法調用方法棧幀,第一個EnsureChildControls是GridView的EnsureChildControls:

EnsureChildControls  <-  

CompositeDataBoundControl.get_Controls  <-  

ControlSerializer.SerializeInnerProperties  <-  

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  <-  

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 ,然後導緻一系列的方法調用。

我的研究,就到這裡了,下次有空再把剩下的發上來吧。

我不相信神話,我隻相信汗水!我不相信命運,我隻相信雙手!

繼續閱讀