1

我有一个名为 LayoutManager 的类。此类的目的是保存对当前在我的 ASP.NET 页面上表示的对象的引用。我最初创建这个类是因为我对Page.FindControl()感到非常沮丧。我的挫败感有两方面:

  • Page.FindControl() 在其本机实现中仅搜索 Page 的直接子级。为了在 Page 上找到任何给定的控件,递归实现是必要的。出于性能原因,我反对这一点。
  • 为了调用 Page.FindControl 我所有有问题的类都需要知道 Page。这似乎是一个很大的耦合,我试图通过一个中间人类来减轻它。

因此,我创建了如下所示的类。我现在才看到我的实施有多糟糕。我删除了在不同对象上执行相同工作的方法,以简化此示例:

/// <summary>
/// This class manages controls which are present on the page.
/// Whenever a control is created it notifies this manager that it has been
/// created (inside of its constructor). At that point, you can use this
/// manager to find controls on the dashboard. 
/// The only other option is to use Page.FindControl, but its pretty broken and slow.
/// </summary>
public class LayoutManager
{
    private static readonly ILog _logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    private static readonly LayoutManager _instance = new LayoutManager();
    private LayoutManager() { }

    public static LayoutManager Instance
    {
        get { return _instance; }
    }

    //HashSets for efficiency. As long as order doesn't matter, use these.
    private HashSet<CormantRadDock> _registeredDocks;

    public RadMultiPage MultiPage { get; set; }
    public CormantTimer Timer { get; set; }
    public DashboardUpdatePanel MultiPageUpdatePanel { get; set; }
    public CormantRadTabStrip TabStrip { get; set; }
    public RadListBox TabsListBox { get; set; }
    public UpdatePanel GlobalSettingsUpdatePanel { get; set; }

    public HashSet<CormantRadDock> RegisteredDocks
    {
        get
        {
            if (Equals(_registeredDocks, null))  
                _registeredDocks = new HashSet<CormantRadDock>();
            return _registeredDocks;
        }
    }

    public CormantRadDock GetDockByID(string dockID)
    {
        CormantRadDock dock = RegisteredDocks.FirstOrDefault(registeredZone => dockID.Contains(registeredZone.ID));

        if (Equals(dock, null))
            _logger.ErrorFormat("Did not find dock: {0}", dockID);
        else
            _logger.DebugFormat("Found dock: {0}", dockID);

        return dock;
    }
}

所以,有几件事:

  • 我搞砸了大时间。这个类不能是静态的。多个用户可以期望 LayoutManager 返回他们的 RegisteredDocks——但这会导致数据冲突。
  • 我将我的 RegisteredDocks 集合暴露给外界,而不是提供与私有集合交互的方法。因此,我在整个代码中调用 RegisteredDocks.Add(dock) ......我目前正在添加诸如 LayoutManager.AddDock(dock) 之类的方法,这将允许我保持集合私有并且只公开与交互的方法收藏品。
  • 我开始将我需要引用的任何其他“1-of”对象扔进课堂。

这一切都源于我不想使用 Page.FindControl.... 所以我现在感觉很傻。

我的问题:

  • 我应该害怕使用 Page.FindControl 的递归实现吗? 这个链接突出了我的担忧——给出的回应是我选择遵循的路线。
  • 如果我不应该使用 Page.FindControl,什么是可靠的解决方案?我想到的唯一简单的解决方案是将我的集合存储在 Session 中并让 LayoutManager 继续保持静态。在这个实现中,它将输出到 Session(根据用户而变化)并返回正确的集合......但我对在 Session 中保存太多数据以及不断写回 Session 的成本持谨慎态度。

编辑:

最后的想法:

public static Dashboard GetInstance()
{
    var dashboard = HttpContext.Current.Handler as Dashboard;
    //TODO: Handle case where dashboard is null.
    return dashboard;
}

public Control FindControlRecursive(Control root, string id)
{
    if (root.ID == id)
        return root;

    foreach (Control control in root.Controls)
    {
        Control foundControl = FindControlRecursive(control, id);
        if (foundControl != null)
            return foundControl;
    }

    return null;
}

//Usage:
Dashboard dashboard = Dashboard.GetInstance();
CormantRadDock dock = (CormantRadDock)dashboard.FindControlRecursive(dashboard, dockID);
4

2 回答 2

2

我认为您根本不应该害怕使用递归FindControl()方法。除非页面达到无数层级(它不应该如此),否则递归函数应该能够遍历您的控制层次结构而不会出汗。

简而言之,构建一个递归FindControl()方法。你没有什么可担心的; 只是不要让它静态。

编辑

要从外部类获取当前页面的句柄,您应该能够执行以下操作:

var page = HttpContext.Current.Handler as Page;
if (page != null)
{
    //found the current page
    //...
}
于 2012-05-11T18:59:42.630 回答
0

在您实际尝试之前,我不会害怕递归扫描仪的性能。如果你需要,我在这里找到了:

http://netpl.blogspot.com/2009/04/how-to-controll-aspnet-listview-page.html

(寻找ControlHelper类,现在它甚至可以是一个带有扩展方法的静态类)

于 2012-05-11T18:59:23.993 回答