如何LoadControl一个使用VaryByControl OutputCache的控件,指定属性的值

时间:2011-07-04 17:38:54

标签: asp.net caching user-controls runtime loadcontrol

我有一个应该使用缓存的用户控件VaryByControl.ascx文件如下所示:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="TestControl.ascx.cs" Inherits="mynamespace.TestControl" %>
<%@ OutputCache Duration="10" Shared="true" VaryByControl="Test" %>
<p id="SomeText" runat="server">Nothing</p>

代码隐藏文件中的TestControl类具有int Test {...}属性和Page_Load()事件处理程序,该句柄用SomeText段填充:

SomeText.InnerText = string.Format(@"Test={0} at {1}", Test, DateTime.Now)

我有一个.aspx文件,如下所示:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestPage.aspx.cs" Inherits="mynamespace.TestPage" %>
<%@ Register TagPrefix="xxx" TagName="TestControl" Src="Controls\TestControl.ascx" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <xxx:TestControl Test="6" runat="server" />
    <xxx:TestControl Test="7" runat="server" />
    <hr />
    <asp:PlaceHolder ID="Suport" runat="server" />
</body>
</html>

两个<xxx:TestControl>代码正确加载TestControl的实例,Test设置为预期值,我可以刷新浏览器几次,我可以看到缓存正常完成它的工作

现在,我想使用<asp:PlaceHolder ID="Suport" />的{​​{1}}个实例填充TestControl,使用不同的Test值,这些都应该从正确的缓存中获益。我正在尝试使用LoadControl方法,但我找不到为Test属性指定值的方法。我希望这样的方法存在,在加载asp.net页面的所有.aspx代码之后设法找到适当的缓存控件。我得到的是PartialCachingControl没有CachedControl初始化的实例,在运行时,呈现的TestControl显示Test的默认值为0

这就是我的.aspx Page_Load()事件处理程序的样子:

protected void Page_Load(object sender, EventArgs e)
{
    PartialCachingControl tc = (PartialCachingControl) LoadControl(@"Controls\TestControl.ascx");
    if (tc.CachedControl != null)
        ((TestControl)tc.CachedControl).Test = 67;            
    Suport.Controls.Add(tc);
}

修改

我可以通过缓存整个页面来解决这个问题,但我似乎无法找到一种方法来实现这样。特别是因为通过ASPX文件调用控件按预期工作(证明有一种方法)。

编辑2

嗯,到目前为止还没有答案。我开始获得赏金,希望它得到更多的关注。

3 个答案:

答案 0 :(得分:3)

要使控件参与整个页面生命周期,应将其添加到Init事件或CreateChildControls方法中,而不是将其添加到Load上。由于VaryByControl需要完全限定的控件标识符才能工作,因此必须在页面循环开始之前对其进行初始化。

类似的东西:

protected override void OnInit(EventArgs e) {
    var testControl = LoadControl(@"TestControl.ascx");
    testControl.ID =  "TestControl";
    Suport.Controls.Add(testControl);
    base.OnInit(e);
}

protected override void OnLoad(EventArgs e) {
    TestControl testControl = GetTestControl("TestControl");
    if(testControl != null){ //If it is null it is cached and can not be changed
        testControl.Test = 242;
    }
    base.OnLoad(e);
}

private TestControl GetTestControl(string name) {
    var control = this.Suport.FindControl(name);
    var partialCachedControl = control as PartialCachingControl;
    if(partialCachedControl != null) {
        control = partialCachedControl.CachedControl;
    }
    return control as TestControl;
}

由于每个控件都缓存了输出,因此在清除缓存之前无法更改控件。如果要更改值并重新生成内容,则必须清除缓存或创建新控件(使用新ID)。清除缓存的一种方法是使用VaryByCustom,并生成一个缓存密钥,如果您的测试值发生变化,该密钥会发生变化。

还要记住在测试控件上实现INamingContainer接口,以避免不同对象之间的命名冲突。为此,只需将界面添加到控件中,如下所示:

public class TestControl: WebControl, INamingContainer {}

答案 1 :(得分:3)

您必须交换2行才能使代码正常工作:

PartialCachingControl tc = (PartialCachingControl) LoadControl(@"Controls\TestControl.ascx");
Suport.Controls.Add(tc);
if (tc.CachedControl != null)
    ((TestControl)tc.CachedControl).Test = 67;            

添加控件后,将初始化缓存的控件。

E.G。

答案 2 :(得分:2)

我认为您误解了VarByControl属性,它不会告诉缓存更改控件上的属性,而是指示页面上控件的ID。 Here is the text from MSDN

  

VaryByControl属性设置为完全限定的控件标识符,其中标识符是从顶级父控件开始并以美元符号($)字符分隔的控件ID的串联。

在您的情况下,您可以设置VaryByCustom而不是VaryByControl,并从Test-property-value生成缓存密钥,如果更改则更改它。