【问题标题】:Vb6 "Tag" property equivalent in ASP.Net?ASP.Net 中等效的 Vb6“标记”属性?
【发布时间】:2010-09-16 00:49:42
【问题描述】:

我在这里寻找想法和意见,而不是“真正的答案”,我猜......

在旧的 VB6 时代,所有控件中都有一个名为“Tag”的属性,这是一种存储与控件相关的自定义信息的有用方法。每一个控件都有它,一切都很幸福......

现在,在 .Net 中(至少对于 WebForms),它不再存在了......

有没有人可以替代它?

我经常发现这个问题,我有不同的函数在生命周期中的不同时间运行,它们与我的控件一起做一些事情,我希望它们保持独立,但应该将信息传递给另一个关于特定控件。

我能想到一百万种替代方法(显然是从模块级字典开始),但没有一个像好的 ol' Tag 那样干净。

(注意:我知道我可以将所有控件子类化并改用我的版本。我宁愿不这样做)

有什么建议吗? 你通常如何解决这个问题? 关于他们为什么首先删除它的任何想法?

编辑:我正在寻找请求内的东西,而不是请求间的东西。我不需要这些信息仍然存在于 PostBack 上。例如,它位于 _Load 和 _PreRender 方法之间。

EDIT2:我知道我的 ASp.Net,而且我知道桌面和网络之间的区别,伙计们!我只是想最大限度地使用 .Net 给我的抽象。我理解权衡,相信我,请假设我理解并回答。

【问题讨论】:

    标签: asp.net controls webforms tag-property


    【解决方案1】:

    不,没有直接的等价物,但如果您使用的是框架的 v3.5,则可以使用扩展方法轻松添加此功能。例如:

    Imports System.Runtime.CompilerServices
    
    Public Module Extensions
      <Extension()> _
      Public Sub SetTag(ByVal ctl As Control, ByVal tagValue As String)
        If SessionTagDictionary.ContainsKey(TagName(ctl)) Then
            SessionTagDictionary(TagName(ctl)) = tagValue
        Else
            SessionTagDictionary.Add(TagName(ctl), tagValue)
        End If
      End Sub
    
      <Extension()> _
      Public Function GetTag(ByVal ctl As Control) As String
        If SessionTagDictionary.ContainsKey(TagName(ctl)) Then
            Return SessionTagDictionary(TagName(ctl))
        Else
            Return String.Empty
        End If
      End Function
    
      Private Function TagName(ByVal ctl As Control) As String
        Return ctl.Page.ClientID & "." & ctl.ClientID
      End Function
    
      Private Function SessionTagDictionary() As Dictionary(Of String, String)
        If HttpContext.Current.Session("TagDictionary") Is Nothing Then
            SessionTagDictionary = New Dictionary(Of String, String)
            HttpContext.Current.Session("TagDictionary") = SessionTagDictionary
        Else
            SessionTagDictionary = DirectCast(HttpContext.Current.Session("TagDictionary"), _ 
              Dictionary(Of String, String))
        End If
      End Function
    End Module
    

    然后,在您的 ASP.NET 页面中,首先将您的扩展纳入范围,例如:

    Imports WebApplication1.Extensions
    

    ...然后根据需要使用您的控件:

    TextBox1.SetTag("Test")
    
    Label1.Text = TextBox1.GetTag
    

    稍后编辑:如果您真的不想将标签存储在 Session 对象中,则可以将它们填充到您的 Viewstate 中。这当然意味着您的标签 暴露在发送给用户的页面标记中(尽管是以模糊的形式),并且不幸的是,需要一些反射功能,因为 ViewState 属性由于某种原因,页面被标记为“受保护”。

    因此,这段代码应该仅用于娱乐目的,除非您真的喜欢在代码审查期间引起注意:

    <Extension()> _
      Public Sub SetTag(ByVal ctl As Control, ByVal tagValue As String)
        ViewState.Add(ctl.ID & "_Tag", tagValue)
      End Sub
    
    <Extension()> _
      Public Function GetTag(ByVal ctl As Control) As String
        Return ViewState(ctl.ID & "_Tag")
      End Function
    
    Private Function ViewState() As Web.UI.StateBag
        Return HttpContext.Current.Handler.GetType.InvokeMember("ViewState", _
                    Reflection.BindingFlags.GetProperty + _
                    Reflection.BindingFlags.Instance + _
                    Reflection.BindingFlags.NonPublic, _
                    Nothing, HttpContext.Current.CurrentHandler, Nothing)
    End Function
    

    最终编辑(我保证...)。这里有一种摆脱反射的方法:首先,创建一个新类以公开具有可用保护级别的 ViewState 属性,然后更改您的 Code-Behind (.aspx.vb) 类以继承它而不是 Web.UI。页面,例如:

    Public Class PageEx
      Inherits System.Web.UI.Page
    
      Friend ReadOnly Property ViewStateEx() As Web.UI.StateBag
        Get
            Return MyBase.ViewState
        End Get
      End Property
    End Class
    

    现在,在您的扩展模块中,您可以通过以下方式访问这个新定义的属性:

    Private Function ViewState() As Web.UI.StateBag
      Return DirectCast(HttpContext.Current.Handler, PageEx).ViewStateEx
    End Function
    

    还是有点 hack,但比使用反射更容易接受...

    【讨论】:

    • 哇。这非常接近我的要求,并假设没有办法。我对 Session 的事情不太满意,但我肯定要学习这个 Extensions 的事情(我使用的是 v2.0,但现在我要迁移 :-D)
    • 这很漂亮,实际上!
    • 不错!我很想给你更多的积分!希望他们能够实现他们正在谈论的业力传递......
    • 现在,有什么办法可以在设计时在 aspx 页面中使用它,这样标签就可以像其他属性一样设置,而无需在代码隐藏中进行设置??
    • tbone:不,不幸的是,扩展方法仅在运行时可用。我想如果你真的想要,你可以使用 VS.NET 插件或类似的插件来实现这一点,但这比它的价值更麻烦
    【解决方案2】:

    你也可以使用复合模式而不是使用继承:

    public class TaggedControl<TControl, TTag> : Control 
     where TControl : Control, new()
     { public TaggedControl() {this.Control= new TControl();}
    
       public TControl Control {get; private set;}
       public TTag     Tag     {get; set;}     
    
       protected override void CreateChildControls(){Controls.Add(Control);}
     }
    
     var textBox = new TaggedControl<TextBox, string>();
     textBox.Tag = "Test";
     label.Text  = textBox.Tag;
    

    【讨论】:

      【解决方案3】:

      我采用了 mdb 的出色解决方案,并将其移植到 C# 以满足我自己的需要。我还将标签从字符串字典更改为字符串字典,对象...因为理论上任何类型的对象都可以存储在会话中,而不仅仅是字符串:

      using System.Collections.Generic;
      using System.Web;
      using System.Web.UI;
      
      public static class Extensions
      {
          public static void SetTag(this Control ctl, object tagValue)
          {
              if (ctl.SessionTagDictionary().ContainsKey(TagName(ctl)))
                  ctl.SessionTagDictionary()[TagName(ctl)] = tagValue;
              else
                  ctl.SessionTagDictionary().Add(TagName(ctl), tagValue);
          }
      
          public static object GetTag(this Control ctl)
          {
              if (ctl.SessionTagDictionary().ContainsKey(TagName(ctl)))
                  return ctl.SessionTagDictionary()[TagName(ctl)];
              else
                  return string.Empty;
          }
      
          private static string TagName(Control ctl)
          {
              return ctl.Page.ClientID + "." + ctl.ClientID;
          }
      
          private static Dictionary<string, object> SessionTagDictionary(this Control ctl)
          {
              Dictionary<string, object> SessionTagDictionary;
              if (HttpContext.Current.Session["TagDictionary"] == null)
              {
                  SessionTagDictionary = new Dictionary<string, object>();
                  HttpContext.Current.Session["TagDictionary"] = SessionTagDictionary;
              }
              else
                  SessionTagDictionary = (Dictionary<string, object>)HttpContext.Current.Session["TagDictionary"];
              return SessionTagDictionary;
          }
      }
      

      【讨论】:

        【解决方案4】:

        您可以向某些控件添加属性,但这似乎会在呈现的控件周围添加一些令人讨厌的 HTML,例如 &lt;div attrName="attrValue"&gt;...(虽然它可能是一个跨度)

        【讨论】:

        • 是的,我不希望标签出现。这是一个内部的东西。另外,稍后那是无效的 HTML(我不在乎 ASP.Net 一直这样做,但仍然如此)
        • 正是我不使用它们的原因!
        【解决方案5】:

        我不确定 tag 属性在 VB6 中做了什么,但也许您正在寻找 Web 控件的 Attributes 属性:

        MyImgCtrl.Attributes["myCustomTagAttribute"] = "myVal";
        

        【讨论】:

        • 不。属性输出到 HTML。我想要一些内部的东西。
        【解决方案6】:

        您询问了 ASP.Net,但 vb6 是一种桌面语言,它的“标记”控件也是如此。用于经典 asp 的 VBScript 并没有真正的控件概念。

        现在在 .Net 中,对于桌面控件,您可以使用继承,这比旧的 Tag 属性更强大。继承也适用于 Web 控件,但您必须小心使用它来保持状态。

        【讨论】:

        • 是的,然后您必须对您制作的每个控件进行子类化。不酷。我明白 Web 和桌面之间的区别,ASP.Net 非常像桌面,并且有控件。他们应该在那里添加标签。
        • 不,您只需在要使用标签的地方对控件进行子类化。无论如何,您可能应该进行更多的子类化。
        【解决方案7】:

        Tag 属性总是一个奇怪的疣状的东西,有用的东西,你可以从中挂出你想要的任何数据。但它不是强类型的,也没有真正实现连贯的设计。该属性本身就像一个奇怪的旋钮一样挂在控件上。他们将其保存在 WinForms 中以方便从 VB6 移植代码。新的 WPF Control 类没有 Tag

        使用 .NET,您拥有完整的面向对象和足够的类型多态性,因此您可以强类型化您想要与代码关联的任何额外信息,无论是在子类中还是在 Dictionary&lt;Control,TValue&gt; 中。

        如果它在单个 Page 请求中,并且您想要一个通用解决方案,那么页面本身中每个值类型(例如,Dictionary&lt;Control,string&gt;Dictionary&lt;Control,BusinessObject&gt;)的字典应该正是您所需要的。

        【讨论】:

        • 当然。但这比标签丑多了,说真的。我明白你在说什么,我同意,但它仍然非常有用。您将关联的数据放在应有的位置,而不是放在完全不碍事的“全局”变量上。
        【解决方案8】:

        您可以使用 asp:Hidden 控件在帖子之间存储数据。就像意志所说,如果你失去了它的价值,那么拥有一个标签属性是没有意义的。

        【讨论】:

        • 呃,更丑。再一次,他们可以序列化到 Viewstate,无需丢失它。对我来说是有价值的,即使你失去了它。
        • 请先尝试更好地解释你想要什么
        猜你喜欢
        • 1970-01-01
        • 2014-08-03
        • 1970-01-01
        • 2014-04-09
        • 1970-01-01
        • 2010-10-02
        • 1970-01-01
        • 2011-09-14
        • 2010-09-06
        相关资源
        最近更新 更多