我有一个名为LayoutManager的类。这个类的目的是保存对ASP.NET页面上当前表示的对象的引用。我最初创建这门课是因为我在Page.FindControl()中遇到了很大的挫折感。我的挫折有两方面:当它不需要时创建一个静态类;谨慎使用Page.FindControl。建议吗?
- Page.FindControl()在其本机实现中仅搜索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”对象。
这一切都源于我不想使用Page.FindControl ....所以我现在感觉非常愚蠢的事实。
我的问题:
- 我应该害怕使用递归实现Page.FindControl的?This link强调我的关注 - 给出的回应是我选择遵循的路线。
- 如果我不应该使用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);
不知道如何从另一个类的页面获得一个句柄?我真的不想将我的Page对象传递给任何想要找到控件的方法。 –
当然,你应该可以通过'HttpContext.Current.Handler' –
这个词来获取页面。这正是我开始使用的解决方案。看我的编辑确认,但我认为我们现在走在一条好路上。谢谢! –