控件开发笔记,鄙视写 LinkButton 那个傻蛋.

1. GridView 的 LinkButton 是如何生成 形如:href="javascript:__doPostBack('ctl00$Content$gridCorner','Upload$2')" 的??

E:\myapp\MS_Symbols\src\source\FXUpdate3074\1.1\DEVDIV\depot\DevDiv\releases\whidbey\QFE\ndp\fx\src\xsp\System\Web\UI\WebControls\GridView.cs\7\GridView.cs

        PostBackOptions IPostBackContainer.GetPostBackOptions(IButtonControl buttonControl) {
            
if (buttonControl == null) {
                
throw new ArgumentNullException("buttonControl"); 
            }
 
            
if (buttonControl.CausesValidation) { 
                
throw new InvalidOperationException(SR.GetString(SR.CannotUseParentPostBackWhenValidating, this.GetType().Name, ID));
            } 

            PostBackOptions options 
= new PostBackOptions(thisbuttonControl.CommandName + "$" + buttonControl.CommandArgument);
            options.RequiresJavaScriptProtocol 
= true;
 
            
return options;
        } 

它是从 E:\myapp\MS_Symbols\src\source\FXUpdate3074\1.1\DEVDIV\depot\DevDiv\releases\whidbey\QFE\ndp\fx\src\xsp\System\Web\UI\WebControls\DataControlLinkButton.cs\2\DataControlLinkButton.cs 而来。 注意这里是 DataControlLinkButton ,而不是 LinkButton,它继承了 LinkButton,所以在GridView上,可看作是 LinkButton。

        protected override PostBackOptions GetPostBackOptions() {
            
if (_container != null) {
                
return _container.GetPostBackOptions(this); 
            }
 
            
return base.GetPostBackOptions(); 
        }

继续倒推,它是从 E:\myapp\MS_Symbols\src\source\FXUpdate3074\1.1\DEVDIV\depot\DevDiv\releases\whidbey\QFE\ndp\fx\src\xsp\System\Web\UI\WebControls\LinkButton.cs\4\LinkButton.cs 发出的。

        protected override void AddAttributesToRender(HtmlTextWriter writer) { 
            
// Make sure we are in a form tag with runat=server.
            if (Page != null) { 
                Page.VerifyRenderingInServerForm(
this);
            }

            
// Need to merge the onclick attribute with the OnClientClick 
            string onClick = Util.EnsureEndWithSemiColon(OnClientClick);
 
            
if (HasAttributes) { 
                
string userOnClick = Attributes["onclick"];
                
if (userOnClick != null) { 
                    
// We don't use Util.MergeScript because OnClientClick or
                    
// onclick attribute are set by page developer directly.  We
                    
// should preserve the value without adding javascript prefix.
                    onClick += Util.EnsureEndWithSemiColon(userOnClick); 
                    Attributes.Remove(
"onclick");
                } 
            } 

            
if (onClick.Length > 0) { 
                writer.AddAttribute(HtmlTextWriterAttribute.Onclick, onClick);
            }

            
bool effectiveEnabled = IsEnabled; 
            
if (Enabled && !effectiveEnabled) {
                
// We need to do the cascade effect on the server, because the browser 
                
// only renders as disabled, but doesn't disable the functionality. 
                writer.AddAttribute(HtmlTextWriterAttribute.Disabled, "disabled");
            } 

            
base.AddAttributesToRender(writer);

            
if (effectiveEnabled && Page != null) { 
                
//
 
                PostBackOptions options 
= GetPostBackOptions(); 
                
string postBackEventReference = null;
                
if (options != null) { 
                    postBackEventReference 
= Page.ClientScript.GetPostBackEventReference(options, true);
                }

                
// If the postBackEventReference is empty, use a javascript no-op instead, since 
                
// <a href="" /> is a link to the root of the current directory.
                if (String.IsNullOrEmpty(postBackEventReference)) { 
                    postBackEventReference 
= "javascript:void(0)"
                }
 
                writer.AddAttribute(HtmlTextWriterAttribute.Href, postBackEventReference);
            }
        }

它是从 E:\myapp\MS_Symbols\src\source\FXUpdate3074\1.1\DEVDIV\depot\DevDiv\releases\whidbey\QFE\ndp\fx\src\xsp\System\Web\UI\WebControls\WebControl.cs\4\WebControl.cs

        public virtual void RenderBeginTag(HtmlTextWriter writer) {
            AddAttributesToRender(writer);

            HtmlTextWriterTag tagKey 
= TagKey; 
            
if (tagKey != HtmlTextWriterTag.Unknown) {
                writer.RenderBeginTag(tagKey); 
            } 
            
else {
                writer.RenderBeginTag(
this.TagName); 
            }
        }

。。

如果想给GridView 中的 LinkButton 的 Hreft 添加 Javascript 代码.代码是不能包含 空格的, 否则,它会被解析成 %20, 很讨厌, 而且它会先执行 Href 再执行 onclick . 如果在不用 Href 属性,即不执行

javascript:__doPostBack('ctl00$Content$gvCon','YourCommand$0'); 

在 RowDataBound 里先设置 Href 属性: LinkButton.Attribute["href"]="" .再添加 onclick 属性.

如果是在命令按钮之前添加完自定义脚本,那么,就非常不好玩了.暂无好法.

1.LinkButton文字替换成 A 标签. 给 A标签添加 自定义脚本.

2.不用LinkButton.ImageButton就没有问题嘛.

3.重写LinkButton.阻止 Href 被Url编码.

为什么 Href 不能直接设置呢. 贴一下代码.就说明 写 LinkButton 的为什么是傻蛋了.

protected override void AddAttributesToRender (HtmlTextWriter writer)
{
     
if (Page != null)
     {
          Page.VerifyRenderingInServerForm(
this);
     }
     
string str0 = Util.EnsureEndWithSemiColon(OnClientClick);
     
if (base.HasAttributes)
     {
          
string value = base.Attributes["onclick"];
          
if (value != null)
          {
               str0 
= str0 + Util.EnsureEndWithSemiColon(value);
               
base.Attributes.Remove("onclick");
          }
     }
     
if (str0.Length > 0)
     {
          writer.AddAttribute(HtmlTextWriterAttribute.Onclick, str0);
     }
     
bool flag1 = base.IsEnabled;
     
if (Enabled && !flag1)
     {
          writer.AddAttribute(HtmlTextWriterAttribute.Disabled, 
"disabled");
     }
     
base.AddAttributesToRender(writer);
     
if (flag1 && (Page != null))
     {
          PostBackOptions options 
= GetPostBackOptions();
          
string text3 = null;
          
if (options != null)
          {
               text3 
= Page.ClientScript.GetPostBackEventReference(options, true);
          }
          
if (string.IsNullOrEmpty(text3))
          {
               text3 
= "javascript:void(0)";
          }
          writer.AddAttribute(HtmlTextWriterAttribute.Href, text3);
     }
}
 

如果你提前给 LinkButton 设置了 Href 属性.  它会先在 base.AddAttributesToRender(writer) 里生成所有的属性.贴WebControl.AddAttributesToRender 的主要代码.

 if (attrState != null)
     {
          AttributeCollection collection1 
= Attributes;
          IEnumerator enumerator1 
= collection1.Keys.GetEnumerator();
          
while (enumerator1.MoveNext())
          {
               
string name = (string) enumerator1.Current;
               writer.AddAttribute(name, collection1[name]);
          }
     }

LinkButton 的 AddAttributesToRender 会二次生成 Href , 所以,直接给 LinkButton 赋 Href 会生成两个 Href 标签 . 狂晕啊.我顶他个肺!

我在重写 LinkButton 时只能调用父类的 AddAttributesToRender ,但是,还需要爷类的 AddAttributesToRender , 如何在孙类调用爷类的 AddAttributesToRender 呢,我想了半天也想不出来. 谁能告诉我! 在孙类写  (this as WebControl).AddAttributesToRender(writer); 会出现死循环.因为它会一直往下调用,在孙类调用爷类的方法,在爷类执行的时候又去查找被Override 的子类的方法.导致死循环.

这里也能表现出:用组合而不用继承的好处.组合更灵活!

...故事似乎还没完...

alarm   作者:NewSea     出处:http://newsea.cnblogs.com/    QQ,MSN:iamnewsea@hotmail.com

  如无特别标记说明,均为NewSea原创,版权私有,翻载必纠。欢迎交流,转载,但要在页面明显位置给出原文连接。谢谢。
原文地址:https://www.cnblogs.com/newsea/p/1536317.html