LayoutManager というクラスがあります。このクラスの目的は、ASP.NET ページに現在表示されているオブジェクトへの参照を保持することです。Page.FindControl()で多くのフラストレーションを経験していたため、最初にこのクラスを作成しました。私のフラストレーションは次の 2 つでした。
- ネイティブ実装の 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);