Учитывая сценарий, когда на странице / элементе управления должны отображаться различные представления (например, вкладки) в различных обстоятельствах (аргумент строки запроса, обратная передача из элемента управления, пользовательские настройки, извлеченные из базы данных), я обычно помещал бы элемент управления, такой как MultiView или Placeholder, и переключите активный индекс представления или свойство Visible следующим образом:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="TestWebApplication.WebForm2" %>
<%@ Register Src="SomeControl.ascx" TagName="SomeControl" TagPrefix="uc1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:PlaceHolder runat="server" ID="phControl" Visible="false">
<uc1:SomeControl ID="SomeControl1" runat="server" />
</asp:PlaceHolder>
<asp:PlaceHolder runat="server" ID="phNotControl" Visible="false">
Some other content
</asp:PlaceHolder>
</div>
</form>
</body>
</html>
И я бы переключил представления в коде в зависимости от логики, подобной этой:
using System;
namespace TestWebApplication
{
public partial class WebForm2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
phControl.Visible = false;
phNotControl.Visible = true;
}
}
}
Это управление:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="SomeControl.ascx.cs" Inherits="TestWebApplication.SomeControl" EnableViewState="false" %>
I am the control
И код контроля:
using System;
namespace TestWebApplication
{
public partial class SomeControl : System.Web.UI.UserControl
{
protected void Page_Init(object sender, EventArgs e)
{
Response.Write("I am the control's Init and I am executing heavy operations <br />");
}
protected void Page_Load(object sender, EventArgs e)
{
Response.Write("I am the control's Load <br />");
}
protected void Page_PreRender(object sender, EventArgs e)
{
Response.Write("I am the control's PreRender and I am only called if the control is Visible <br />");
}
}
}
Однако что, если у рассматриваемого элемента управления есть довольно тяжелая работа (вызов базы данных) в его событиях init и load? Они выполняются, даже если элемент управления не виден и будет замедлять страницу. Одно возможное решение, которое я вижу, - это перемещение всей работы в методе PreRender дочернего элемента управления, поскольку оно не выполняется для элементов управления, которые не отображаются. Однако это не будет работать, если элемент управления принимает пользовательский ввод от некоторого динамически заполненного элемента управления (например, выпадающего списка), поскольку логика, которая заполняет раскрывающийся список с параметрами, не будет выполнена.
Я предложил следующие решения:
Переместите тяжелую работу в метод PreRender и оберните ее в if (! IsPostBack). Затем пусть ViewState содержит возможные значения для раскрывающегося списка, и ASP.NET восстановит его. Недостатком является то, что он использует ViewState и увеличивает размер страницы.
Создайте элемент управления динамически с помощью LoadControl и добавьте его в заполнитель из кода. Это вызовет события догоняющего, и код, который заполняет выпадающий список, может быть помещен в метод Init, где он принадлежит. Недостатком является то, что макет определяется в коде позади. Глядя на разметку, нельзя увидеть, какие элементы управления находятся на странице, и, глядя на код, лежащий за ним, неясно, где появится элемент управления. Это также усложняет стилизацию и другие «дизайнерские» операции.
Оставь как есть. Недостатком является то, что будут дополнительные запросы к базе данных, и если будет много просмотров, они будут складываться.
Мой настоящий вопрос заключается в том, как решить эту проблему, не помещая вещи в ViewState, без нескольких запросов и не перетаскивая свой макет в код позади.