专栏首页智能大石头关于自定义控件设计时如何把属性写入aspx中的研究(上)

关于自定义控件设计时如何把属性写入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类

private static void SerializeControl(Control control, IDesignerHost host, TextWriter writer, string filter)
{
    if (control == null)
    {
        throw new ArgumentNullException("control");
    }
    if (host == null)
    {
        throw new ArgumentNullException("host");
    }
    if (writer == null)
    {
        throw new ArgumentNullException("writer");
    }
    if (control is LiteralControl)
    {
        writer.Write(((LiteralControl) control).Text);
    }
    else if (control is DesignerDataBoundLiteralControl)
    {
        DataBinding binding = ((IDataBindingsAccessor) control).DataBindings["Text"];
        if (binding != null)
        {
            writer.Write("<%# ");
            writer.Write(binding.Expression);
            writer.Write(" %>");
        }
    }
    else if (control is UserControl)
    {
        IUserControlDesignerAccessor accessor = (IUserControlDesignerAccessor) control;
        string tagName = accessor.TagName;
        if (tagName.Length > 0)
        {
            writer.Write('<');
            writer.Write(tagName);
            writer.Write(" runat=\"server\"");
            ObjectPersistData persistData = null;
            IControlBuilderAccessor accessor2 = control;
            if (accessor2.ControlBuilder != null)
            {
                persistData = accessor2.ControlBuilder.GetObjectPersistData();
            }
            SerializeAttributes(control, host, string.Empty, persistData, writer, filter);
            writer.Write('>');
            string innerText = accessor.InnerText;
            if ((innerText != null) && (innerText.Length > 0))
            {
                writer.Write(accessor.InnerText);
            }
            writer.Write("</");
            writer.Write(tagName);
            writer.WriteLine('>');
        }
    }
    else
    {
        string text3;
        HtmlControl control2 = control as HtmlControl;
        if (control2 != null)
        {
            text3 = control2.TagName;
        }
        else
        {
            text3 = GetTagName(control.GetType(), host);
        }
        writer.Write('<');
        writer.Write(text3);
        writer.Write(" runat=\"server\"");
        ObjectPersistData objectPersistData = null;
        IControlBuilderAccessor accessor3 = control;
        if (accessor3.ControlBuilder != null)
        {
            objectPersistData = accessor3.ControlBuilder.GetObjectPersistData();
        }
        SerializeAttributes(control, host, string.Empty, objectPersistData, writer, filter);
        writer.Write('>');
        SerializeInnerContents(control, host, objectPersistData, writer, filter);
        writer.Write("</");
        writer.Write(text3);
        writer.WriteLine('>');
    }
}

从代码就可以看出来,这不就是在写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 ,然后导致一系列的方法调用。

我的研究,就到这里了,下次有空再把剩下的发上来吧。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • C#嵌入x86汇编——一个GPIO接口的实现

    开始进入工业自动化,买的工控机带有GPIO接口,可用于直接控制继电器。 从厂家拿到接口手册一看,居然是汇编直接操作端口,基本上是IN/OUT指令了。接口很简单,...

    大石头
  • [NewLife.XCode]角色权限

    NewLife.XCode是一个有10多年历史的开源数据中间件,支持nfx/netcore,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCo...

    大石头
  • [NewLife.XCode]数据模型文件

    NewLife.XCode是一个有10多年历史的开源数据中间件,由新生命团队(2002~2019)开发完成并维护至今,以下简称XCode。

    大石头
  • DropDownList下拉框多选

    最近弄完个项目、项目需要支持多选功能、找了很多例子没找到合适的,最后自己开发了个控件:

    跟着阿笨一起玩NET
  • 为什么 spring 中,不支持 autowired 静态变量?

    因为静态变量是属于本身类的信息,当类加载器加载静态变量时,Spring 的上下文环境还没有被加载,所以不可能为静态变量绑定值。

    水货程序员
  • 自动售书机问世了!

    去年年底的时候,我曾经介绍了《财富》杂志评选出2007年最具有创意的十种新产品。其中有一种是类似ATM的自动售书机,只需按几个按钮,一本新书就会自动打印和装订,...

    ruanyf
  • 【群友记录】记录写rust遇到一个坑

    目的是想在map新增key的时候做一些处理,看起来很美好,编译通过了,但是多了警告 warning: value assigned to is_new is n...

    MikeLoveRust
  • phpEnv一款优雅强大的php集成开发环境

    php集成开发环境有很多种,例如phpstudy,wamp,xmapp等等,各有各的优点和缺点,本文并不是对各个 IDE 的使用和调试进行详细的对比和评测,因为...

    php007
  • Linux防火墙-firewall

    Firewall : 由于centOS 7采用了新的firewall防火墙,也是未来的一种趋势,所以咱们在7上面既可以使用6也可以使用7。 由于iptables...

    老七Linux
  • VirtualBox 共享文件夹自动挂载

    solate

扫码关注云+社区

领取腾讯云代金券