5

我有一个应该使用缓存的用户控件,带有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>实例,我可以刷新浏览器几次,我可以看到缓存正确地完成了它的工作。TestControlTest

现在我想<asp:PlaceHolder ID="Suport" />用一些实例来填充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

嗯,暂时没有答案。我开始了一个赏金,希望它得到更多的关注。

4

3 回答 3

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 {}
于 2011-07-14T09:18:44.063 回答
3

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

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

一旦添加了控件,缓存的控件就会被初始化。

例如

于 2012-10-31T13:09:53.067 回答
2

我认为您误解了 VarByControl 属性,它不会告诉缓存更改控件上的属性,而是更改页面上控件的 ID。这是来自 MSDN 的文本

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

在您的情况下,您可以设置 VaryByCustom 而不是 VaryByControl 并从 Test-property-value 生成一个缓存键,并在它发生变化时对其进行更改。

于 2011-07-14T12:37:21.357 回答