2014-02-24 96 views
0

我在ASP.NET用戶控件中有一個列表框,我想填充從數據庫檢索的潛在大List<string>(最多50k項)。當列表框被填充(在頁面加載事件中)時,我不想阻止UI。使用同步代碼,直到列表框中人口完成不顯示頁面:異步填充ASP.NET ListBox而不阻塞UI

List<string> items = GetItemsFromDB();  
foreach (var item in items) // can take some time, blocks UI 
{ 
    if (shouldItemBeListed(item)) 
     ListBox1.Items.Add(item); 
} 

我來自桌面應用程序背景哪裏實現,這是簡單的使用例如BackgroundWorker - 用戶將實時看到填充了新項目的列表框。網絡的東西似乎更復雜一點,我想就什麼是最好的方式去做這個建議。

這裏是我的嘗試:

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的線程。工作稍好一點(至少列表框正在更新新項目),但仍然非常反應遲鈍。

var bw = new BackgroundWorker(); 
bw.DoWork += (o, args) => Populate(); 
bw.RunWorkerAsync(); 

我總是可以按照用戶的要求將列表框項目分成更小的組和填充更多,但通常如何實現?

+1

我認爲你要找的是一個Ajax回調,不需要後臺線程變得複雜。 – Damon

+0

當你開始有這樣的需求時,該開始學習ASP.Net MVC和/或ASP.Net Web api了。實施起來要容易得多。 –

+0

再次讀你的問題,我覺得你犯了錯誤。不是加載50K項目,然後刪除不需要的項目,爲什麼不加載相關項目?你可以將'shouldItemBeListed'方法中的邏輯移動到數據庫查詢中嗎? –

回答

3

不能使用這種方法,因爲asp.net生命週期(和一般的網絡)的。基本上,每個向web服務器的請求都會產生你的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>是,你不能回發之間改變它的孩子。所以我們使用純客戶端,並在隱藏控件中同步更改,這可以在回發中讀取。

0

Damon說得對,因爲您正在尋找ajax,它應該會爲您提供所需的功能。我發現frmo MSDN的例子使用一個GridView,但它應該是適應性強:

<%@ 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> 
    &nbsp;</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> 
+0

網格的初始加載仍將在頁面呈現中發生。它將無助於加載下拉列表異步 –