2012-05-11 14 views
1

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

回答

2

我不认为你应该根本不敢使用递归的FindControl()方法。除非页面变得无数深层(它不应该),否则递归函数应该能够遍历你的控制层次而不会冒汗。

总之,建立一个递归的FindControl()方法。你没有什么可担心的;只是不要把它变成静态的。

编辑

要想从外部类的当前页面上的把手,你应该能够做到这一点:

var page = HttpContext.Current.Handler as Page; 
if (page != null) 
{ 
    //found the current page 
    //... 
} 
+0

不知道如何从另一个类的页面获得一个句柄?我真的不想将我的Page对象传递给任何想要找到控件的方法。 –

+0

当然,你应该可以通过'HttpContext.Current.Handler' –

+0

这个词来获取页面。这正是我开始使用的解决方案。看我的编辑确认,但我认为我们现在走在一条好路上。谢谢! –

相关问题