我在ASP.NET用户控件中有一个列表框,我想填充从数据库中检索到的可能很大的List<string>
(最多50k项)。在填充列表框时(在页面加载事件中),我不想阻止UI。在完成列表框填充之前,使用同步代码不会显示页面:
List<string> items = GetItemsFromDB();
foreach (var item in items) // can take some time, blocks UI
{
if (shouldItemBeListed(item))
ListBox1.Items.Add(item);
}
我来自桌面应用程序背景,其中使用例如BackgroundWorker
- 用户将看到实时填充新项目的列表框。 Web的东西似乎有点复杂,我想就什么是最好的方法来提出一些建议。
这是我试过的:
1。创建后台线程。 不能很好地工作 - 与桌面(WinForms)版本相比,一切仍然没有响应,并且列表没有按预期更新/刷新:
Thread thread = new Thread(new ThreadStart(Populate));
thread.IsBackground = true;
thread.Start();
private void Populate()
{
List<string> items = GetItemsFromDB();
foreach (var item in items)
{
if (shouldItemBeListed(item))
ListBox1.Items.Add(item);
}
}
2。 BackgroundWorker线程。比1更好一点。(至少列表框正在更新新项目),但仍然非常反应迟钝。
var bw = new BackgroundWorker();
bw.DoWork += (o, args) => Populate();
bw.RunWorkerAsync();
我总是可以将列表框项目分成更小的组,并根据用户的要求填充更多,但这通常如何正确实现呢?
答案 0 :(得分:3)
由于asp.net生命周期(以及一般的网络),你不能使用这种方法。基本上,对webserver的每个请求都会产生你的asp.net页面类,生成html,发送给客户端,然后关闭实例。使用多线程技术无济于事,因为您将更改控制树 AFTER 服务器已发送答案。
要解决您的问题,您应该使用<asp:hidden runat='server'>
字段。
然后,使用某种客户端脚本,从Web服务调用中动态填充下拉列表。
使用jQuery(来自内存)这样的东西:
<select id='ddl' onchange='document.getElementById("<%= hidValue.ClientID %>").value=this.value'>
<option value=''>Loading...</option>
</select>
<asp:Hidden runat='server' id='hidValue' />
$(function(){
$.ajax("... your api endpoit").then(function(result){
var items = result.items; // actual implementation will change
var ddl = $(ddl);
ddl.html(''); // remove the 'loading' option.
foreach(var item in items) {
var option = $("<option>");
option.attr("value",item.value);
option.text(item.text);
ddl.append(option);
}
});
});
不使用<asp:DropDownList>
的原因是您无法在回发之间更改其子级。所以我们使用一个纯客户端,并在隐藏控件中同步更改,这可以在回发时读取。
答案 1 :(得分:0)
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Collections.Generic" %>
<!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>Enter New Employees</title>
<script runat="server">
private List<Employee> EmployeeList;
protected void Page_Load()
{
if (!IsPostBack)
{
EmployeeList = new List<Employee>();
EmployeeList.Add(new Employee(1, "Jump", "Dan"));
EmployeeList.Add(new Employee(2, "Kirwan", "Yvette"));
ViewState["EmployeeList"] = EmployeeList;
}
else
EmployeeList = (List<Employee>)ViewState["EmployeeList"];
EmployeesGridView.DataSource = EmployeeList;
EmployeesGridView.DataBind();
}
protected void InsertButton_Click(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(FirstNameTextBox.Text) ||
String.IsNullOrEmpty(LastNameTextBox.Text)) { return; }
int employeeID = EmployeeList[EmployeeList.Count-1].EmployeeID + 1;
string lastName = Server.HtmlEncode(FirstNameTextBox.Text);
string firstName = Server.HtmlEncode(LastNameTextBox.Text);
FirstNameTextBox.Text = String.Empty;
LastNameTextBox.Text = String.Empty;
EmployeeList.Add(new Employee(employeeID, lastName, firstName));
ViewState["EmployeeList"] = EmployeeList;
EmployeesGridView.DataBind();
EmployeesGridView.PageIndex = EmployeesGridView.PageCount;
}
protected void CancelButton_Click(object sender, EventArgs e)
{
FirstNameTextBox.Text = String.Empty;
LastNameTextBox.Text = String.Empty;
}
[Serializable]
public class Employee
{
private int _employeeID;
private string _lastName;
private string _firstName;
public int EmployeeID
{
get { return _employeeID; }
}
public string LastName
{
get { return _lastName; }
}
public string FirstName
{
get { return _firstName; }
}
public Employee(int employeeID, string lastName, string firstName)
{
_employeeID = employeeID;
_lastName = lastName;
_firstName = firstName;
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true" />
<table>
<tr>
<td style="height: 206px" valign="top">
<asp:UpdatePanel ID="InsertEmployeeUpdatePanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<table cellpadding="2" border="0" style="background- color:#7C6F57">
<tr>
<td><asp:Label ID="FirstNameLabel" runat="server" AssociatedControlID="FirstNameTextBox"
Text="First Name" ForeColor="White" /></td>
<td><asp:TextBox runat="server" ID="FirstNameTextBox" /></td>
</tr>
<tr>
<td><asp:Label ID="LastNameLabel" runat="server" AssociatedControlID="LastNameTextBox"
Text="Last Name" ForeColor="White" /></td>
<td><asp:TextBox runat="server" ID="LastNameTextBox" /></td>
</tr>
<tr>
<td></td>
<td>
<asp:LinkButton ID="InsertButton" runat="server" Text="Insert" OnClick="InsertButton_Click" ForeColor="White" />
<asp:LinkButton ID="Cancelbutton" runat="server" Text="Cancel" OnClick="CancelButton_Click" ForeColor="White" />
</td>
</tr>
</table>
<asp:Label runat="server" ID="InputTimeLabel"><%=DateTime.Now %> </asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
</td>
<td style="height: 206px" valign="top">
<asp:UpdatePanel ID="EmployeesUpdatePanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:GridView ID="EmployeesGridView" runat="server" BackColor="LightGoldenrodYellow" BorderColor="Tan"
BorderWidth="1px" CellPadding="2" ForeColor="Black" GridLines="None" AutoGenerateColumns="False">
<FooterStyle BackColor="Tan" />
<SelectedRowStyle BackColor="DarkSlateBlue" ForeColor="GhostWhite" />
<PagerStyle BackColor="PaleGoldenrod" ForeColor="DarkSlateBlue" HorizontalAlign="Center" />
<HeaderStyle BackColor="Tan" Font-Bold="True" />
<AlternatingRowStyle BackColor="PaleGoldenrod" />
<Columns>
<asp:BoundField DataField="EmployeeID" HeaderText="Employee ID" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" />
<asp:BoundField DataField="FirstName" HeaderText="First Name" />
</Columns>
<PagerSettings PageButtonCount="5" />
</asp:GridView>
<asp:Label runat="server" ID="ListTimeLabel"><%=DateTime.Now %> </asp:Label>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="InsertButton" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
</td>
</tr>
</table>
</form>
</body>
</html>