我有一个名为 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);