我在这里寻找想法和意见,而不是“真正的答案”,我猜......
回到旧的VB6时代,所有控件中都有一个名为“Tag”的属性,这是存储与控件相关的自定义信息的有用方法。每个控制都有它,而且一切都很幸福......
现在,在.Net(至少对于WebForms),它不再存在......
有没有人有更好的替代品?
我经常发现这个问题,我在生命周期的不同时间运行不同的函数,并且他们使用我的控件进行操作,并且我希望将它们保持原样,但是应该将信息传递给另一个关于具体的控制。
我可以想到一百万个替代品(显然是从模块级字典开始),但没有一个像好的标签一样干净。
(注意:我知道我可以将所有控件子类化并使用我的版本。我宁愿不这样做)
有什么建议吗? 你是如何解决这个问题的? 关于他们为什么首先删除这个的任何想法?
编辑:我正在寻找内部请求,而非内部请求。我不需要这些信息仍然在PostBack上。例如,这是在_Load和_PreRender方法之间。EDIT2:我知道我的ASp.Net,我确实知道桌面和网络之间的区别,伙计们!我只是试图使用.Net给我的最大化的抽象。我理解这些权衡,相信我,请假设我这样做。
答案 0 :(得分:4)
不,没有直接的等价物,但如果您使用的是框架的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
LATER EDIT:如果你真的,真的不想将你的标签存储在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
仍然有点黑客,但比使用反射更可接受......
答案 1 :(得分:3)
您也可以使用复合模式而不是使用继承:
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;
答案 2 :(得分:1)
我采用了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;
}
}
答案 3 :(得分:0)
您可以为某些控件添加属性,但这似乎会在渲染控件周围添加一些令人讨厌的HTML,例如<div attrName="attrValue">
......(它可能是一个跨度)
答案 4 :(得分:0)
我不确定标签属性在VB6中做了什么,但也许您正在寻找Web控件的Attributes
属性:
MyImgCtrl.Attributes["myCustomTagAttribute"] = "myVal";
答案 5 :(得分:0)
你问过ASP.Net,但是vb6是一种桌面语言,它也是'标记'控件。用于经典asp的VBScript并没有真正的控件概念。
现在在.Net中,对于桌面控件,您可以使用继承,这比旧的Tag属性更强大。继承也适用于Web控件,但您必须小心使用它来保存状态。
答案 6 :(得分:-1)
您可以使用asp:隐藏控件在帖子之间存储数据。就像会说的那样,如果你失去了它的价值,就没有意义。
答案 7 :(得分:-1)
Tag
属性始终是一个奇怪的类似于wart的东西, 非常有用,因为你可以挂起你想要的任何数据。但它并不是强类型的,它并没有真正形成一个连贯的设计。该物业本身就像一个奇怪的旋钮一样悬挂在控制之下。他们将它保存在WinForms中,以方便从VB6移植代码。新的WPF Control
类没有Tag
。
使用.NET,您可以获得完整的面向对象和足够的类型多态性,因此您可以强类型地输入要与代码关联的任何额外信息,无论它是在子类中还是Dictionary<Control,TValue>
。
如果它在单个Page
请求中并且您想要一个通用解决方案,每个值类型(例如,Dictionary<Control,string>
和Dictionary<Control,BusinessObject>
)的页面本身中的字典应该正是您的需要。