2008-10-24 3 views
15

У меня возникла проблема динамического добавления столбцов в GridView. Мне нужно изменить макет - то есть включенные столбцы - на основе значения в DropDownList. Когда пользователь меняет выбор в этом списке, мне нужно удалить все, кроме первого столбца, и динамически добавлять дополнительные столбцы на основе выбора.Добавление динамических столбцов в ASP.NET Gridview

У меня есть только один столбец, определенный в моей разметке - столбец 0 столбца шаблона, в котором я объявляю ссылку «Выбрать» и ссылку на LinkButton другого приложения. Эта колонка всегда должна быть там. Когда выполняется ListBoxSelection, я удаляю все, кроме первого столбца, а затем повторно добавляю нужные столбцы (в этом примере я упростил его, чтобы всегда добавлять столбец «Заголовок»). Вот часть кода:

RemoveVariableColumnsFromGrid(); 
BoundField b = new BoundField(); 
b.DataField = "Title"; 
this.gvPrimaryListView.Columns.Add(b); 
this.gvPrimaryListView.DataBind(); 


private void RemoveVariableColumnsFromGrid() { 
    int ColCount = this.gvPrimaryListView.Columns.Count; 
    //Leave column 0 -- our select and view template column 
    while (ColCount > 1) { 
     this.gvPrimaryListView.Columns.RemoveAt(ColCount - 1); 
     --ColCount; 
    } 
} 

В первый раз этот код проходит через, я вижу, как статический столбец и динамически столбец добавляется «Title». Однако в следующий раз, когда будет сделан выбор, первый столбец будет сгенерирован пустым (ничего в нем). Я вижу столбец заголовка, и я вижу первый столбец слева от него, но в нем ничего не генерируется. В отладчике я вижу, что gvPrimaryListView действительно имеет два столбца, а первый (индекс 0) действительно является столбцом шаблона. Фактически, столбец даже сохраняет свою ширину, которая установлена ​​в 165px в разметке ниже (для целей отладки).

Любые идеи?

<asp:GridView ID="gvPrimaryListView" runat="server" Width="100%" AutoGenerateColumns="false" 
    DataKeyNames="Document_ID" EnableViewState="true" DataSourceID="odsPrimaryDataSource" 
    AllowPaging="true" AllowSorting="true" PageSize="10" OnPageIndexChanging="activeListView_PageIndexChanging" 
    AutoGenerateSelectButton="False" OnSelectedIndexChanged="activeListView_SelectedIndexChanged" 
    Visible="true" OnRowDataBound="CtlDocList_RowDataBound" Font-Size="8pt" Font-Names="Helvetica"> 
    <Columns> 
     <asp:TemplateField ShowHeader="false"> 
      <ItemTemplate> 
       <asp:LinkButton EnableTheming="false" ID="CtlSelectDocRowBtn" runat="server" Text="Select" 
        CommandName="Select" CssClass="gridbutton" OnClick="RowSelectBtn_Click" /> 
       <asp:ImageButton EnableTheming="false" ID="DocViewBtn" runat="server" ImageUrl="../../images/ViewDoc3.png" 
        CssClass="gridbutton" CommandName="Select" OnClick="DocViewBtn_Click" /> 
      </ItemTemplate> 
      <ItemStyle Width="165px" /> 
     </asp:TemplateField> 
    </Columns> 
    <EmptyDataTemplate> 
     <asp:Label ID="Label6" runat="server" Text="No rows found." SkinID="LabelHeader"></asp:Label> 
    </EmptyDataTemplate> 
</asp:GridView> 

Просто некоторая дополнительная информация.

Это не имеет никакого отношения к тому факту, что это первый столбец, но все связано с тем, что это TemplateField. Если я поместил нормальный столбец влево (в разметке) и сдвинул столбец TemplateField вправо, первый столбец отобразится отлично, а столбец (теперь второй) TemplateField исчезнет.

Еще одна странная вещь: проблема не в том, что первая обратная передача - ИЛИ ВТОРАЯ - но она начинается с третьей обратной передачи, а затем продолжается для последующих обратных передач. Я в тупике.

+0

Я делаю то же самое, чтобы динамически добавлять столбцы в коде Однако проблема заключается в том, что я добавляю 20 + столбцов динамически, для каждого цикла замедляется вся страница, есть ли у вас такая же проблема? – Princa 2013-11-25 14:33:04

ответ

0

Я нашел этот маленький самородок в документации под классом DataControlFieldCollection.

Если вы используете элемент управления GridView или DetailsView, объекты DataControlField, которые автоматически создаются (например, когда свойство AutoGenerateColumns истинно), не хранятся в общедоступной коллекции полей. Вы можете обращаться к объектам DataControlField и манипулировать ими, которые не генерируются автоматически.

Я предполагаю, что ответ должен сделать все ваши манипуляции с колонками в коде, а затем ваш подход должен работать нормально.

0

Вместо динамического добавления столбцов вы могли бы определить их с самого начала и скрыть/показать их по мере необходимости (либо с помощью Visible = "false", либо установить CssClass элемента управления/заголовка/нижнего колонтитула в класс с "display: никто;")? Я использую этот метод в некоторых своих кодах, включая столбцы шаблонов, без проблем.

0

Извините, Декер. Я пропустил несколько ключевых моментов, очевидно. :)

Если это все еще проблема для вас, интересно, имеет ли значение то, что у вас есть в вашем шаблоне? Если вы просто разместите там какой-либо текст, обновите страницу несколько раз, появится ли текст при первой загрузке, а не на второй?

Кроме того, когда возникает проблема, есть ли какая-либо html-разметка в ячейках или они полностью пусты?

5

Недавно я завоевал проблемы с динамическими столбцами в gridviews, возможно, это поможет.

Сначала поверните ViewState от
Второму добавить столбцы в программно функции обожженной в OnInit случае
Наконец я использовал следующий вспомогательный класс, чтобы заставить флажки экземпляра, когда событие RowDataBound стартовало. Да, некоторые из них жестко закодированы.

Вот полный код. Имейте это в виду :) Warrenty as is, blah blah blah ...

Наконец, поскольку я только что намочил ноги DotNet, любые советы будут оценены [IE не слишком меня разорвал :)]. И да «заимствованы» исходный код из Интернета где-то, извините, я не могу вспомнить с верхней части моей головы :(

- Огонь это прочь в защищенном переназначения пустоте OnInit

private void GridViewProject_AddColumns() 
    { 
     DataSet dsDataSet = new DataSet(); 
     TemplateField templateField = null; 

     try 
     { 
      StoredProcedure sp = new StoredProcedure("ExpenseReportItemType_GetList", "INTRANETWEBDB", Context.User.Identity.Name); 
      dsDataSet = sp.GetDataSet(); 

      if (sp.RC != 0 && sp.RC != 3000) 
      { 
       labelMessage.Text = sp.ErrorMessage; 
      } 

      int iIndex = 0; 
      int iCount = dsDataSet.Tables[0].Rows.Count; 
      string strCategoryID = ""; 
      string strCategoryName = ""; 
      iStaticColumnCount = GridViewProject.Columns.Count; 

      // Insert all columns immediatly to the left of the LAST column 
      while (iIndex < iCount) 
      { 
       strCategoryName = dsDataSet.Tables[0].Rows[iIndex]["CategoryName"].ToString(); 
       strCategoryID = dsDataSet.Tables[0].Rows[iIndex]["CategoryID"].ToString(); 

       templateField = new TemplateField(); 
       templateField.HeaderTemplate = new GridViewTemplateExternal(DataControlRowType.Header, strCategoryName, strCategoryID); 
       templateField.ItemTemplate = new GridViewTemplateExternal(DataControlRowType.DataRow, strCategoryName, strCategoryID); 
       templateField.FooterTemplate = new GridViewTemplateExternal(DataControlRowType.Footer, strCategoryName, strCategoryID); 

       // Have to decriment iStaticColumnCount to insert dynamic columns BEFORE the edit row 
       GridViewProject.Columns.Insert((iIndex + (iStaticColumnCount-1)), templateField); 
       iIndex++; 
      } 
      iFinalColumnCount = GridViewProject.Columns.Count; 
      iERPEditColumnIndex = (iFinalColumnCount - 1); // iIndex is zero based, Count is not 
     } 
     catch (Exception exception) 
     { 
      labelMessage.Text = exception.Message; 
     } 
    } 

- вспомогательный класс

public class GridViewTemplateExternal : System.Web.UI.ITemplate 
{ 
    #region Fields 
    public DataControlRowType DataRowType; 
    private string strCategoryID; 
    private string strColumnName; 
    #endregion 

    #region Constructor 
    public GridViewTemplateExternal(DataControlRowType type, string ColumnName, string CategoryID) 
    { 
     DataRowType = type; // Header, DataRow, 
     strColumnName = ColumnName; // Header name 
     strCategoryID = CategoryID; 
    } 
    #endregion 

    #region Methods 
    public void InstantiateIn(System.Web.UI.Control container) 
    { 
     switch (DataRowType) 
     { 
      case DataControlRowType.Header: 
       // build the header for this column 
       Label labelHeader = new Label(); 
       labelHeader.Text = "<b>" + strColumnName + "</b>"; 
       // All CheckBoxes "Look Up" to the header row for this information 
       labelHeader.Attributes["ERICategoryID"] = strCategoryID; 
       labelHeader.Style["writing-mode"] = "tb-rl"; 
       labelHeader.Style["filter"] = "flipv fliph"; 
       container.Controls.Add(labelHeader); 
       break; 
      case DataControlRowType.DataRow: 
       CheckBox checkboxAllowedRow = new CheckBox(); 
       checkboxAllowedRow.Enabled = false; 
       checkboxAllowedRow.DataBinding += new EventHandler(this.CheckBox_DataBinding); 
       container.Controls.Add(checkboxAllowedRow); 
       break; 
      case DataControlRowType.Footer: 
       // No data handling for the footer addition row 
       CheckBox checkboxAllowedFooter = new CheckBox(); 
       container.Controls.Add(checkboxAllowedFooter); 
       break; 
      default: 
       break; 
     } 
    } 
    public void CheckBox_DataBinding(Object sender, EventArgs e) 
    { 
     CheckBox checkboxAllowed = (CheckBox)sender;// get the control that raised this event 
     GridViewRow row = (GridViewRow)checkboxAllowed.NamingContainer;// get the containing row 
     string RawValue = DataBinder.Eval(row.DataItem, strColumnName).ToString(); 
     if (RawValue.ToUpper() == "TRUE") 
     { 
      checkboxAllowed.Checked = true; 
     } 
     else 
     { 
      checkboxAllowed.Checked = false; 
     } 
    } 
    #endregion 
} 
1

diningphilanderer.myopenid.com имеет подобный подход к тому, что я бы не рекомендовал.

проблема заключается в том, что вы должны перепривязывают сетке каждый раз постбэк о ccurs и, следовательно, вам нужно перестроить столбцы. Мне нравится иметь метод BindGrid(), который сначала очищает столбцы GridView1.Columns.Clear(); затем добавляет их программно, затем устанавливает источник данных и вызывает привязку данных. Убедитесь, что для сетки отключен режим просмотра, и у вас есть autogeneratecolumns = false;

1

Я нашел это сегодня сегодня: TemplateField in a GridView doesn't have its ViewState restored when BoundFields are inserted.

Похож на ошибку, которую Microsoft не планирует исправлять, поэтому вам придется попробовать одно из решений выше. У меня такая же проблема: у меня есть некоторые DataBoundFields и некоторые TemplateFields, и после обратной передачи столбцы на основе TemplateField теряют свои элементы управления и данные.

1

Я написал короткую статью по аналогичной теме, которая касается динамически заполняющего столбца GridView на основе столбцов, выбранных пользователем в элементе управления CheckBoxList. Надеюсь, это поможет тем, кто ищет простую демонстрацию How to generate GridView columns dynamically based on user selection?.

1
void Page_PreRenderComplete(object sender, EventArgs e) 
    { 
     // TemplateField reorder bug: if there is a TemplateField based column (or derived therefrom), GridView may blank out 
     // the column (plus possibly others) during any postback, if the user has moved it from its original markup position. 
     // This is probably a viewstate bug, as it happens only if a TemplateField based column has been moved. The workaround is 
     // to force a databind before each response. See https://connect.microsoft.com/VisualStudio/feedback/details/104994/templatefield-in-a-gridview-doesnt-have-its-viewstate-restored-when-boundfields-are-inserted 
     // 
     // This problem is also happening for grid views inside a TabPanel, even if the TemplateField based columns have not 
     // been moved. Also do a databind in that case. 
     // 
     // We also force a databind right after the user has submitted the column chooser dialog. 
     // (This is because the user could have moved TemplateField based column(s) but ColChooserHasMovedTemplateFields() 
     // returns false -- ie when the user has moved all TemplateField based columns back to their original positions. 
     if ((!_DataBindingDone && (ColChooserHasMovedTemplateFields() || _InTabPanel)) || _ColChooserPanelSubmitted || _ColChooserPanelCancelled) 
      DataBind(); 

     // There is a problem with the GridView in case of custom paging (which is true here) that if we are on the last page, 
     // and we delete all row(s) of that page, GridView is not aware of the deletion during the subsequent data binding, 
     // will ask the ODS for the last page of data, and will display a blank. By PreRenderComplete, it will somehow have 
     // realized that its PageIndex, PageCount, etc. are too big and updated them properly, but this is too late 
     // as the data binding has already occurred with oudated page variables. So, if we were on the last page just before 
     // the last data binding (_LastPageIndex == _LastPageCount - 1) and PageIndex was decremented after the data binding, 
     // we know this scenario has happened and we redo the data binding. See http://scottonwriting.net/sowblog/archive/2006/05/30/163173.aspx 
     // for a discussion of the problem when the GridView uses the ODS to delete data. The discussion also applies when we 
     // delete data directly through ClassBuilder objects. 
     if (_LastPageIndex == _LastPageCount - 1 && PageIndex < _LastPageIndex) 
      DataBind(); 

     if (EnableColChooser) 
     { 
      if (!_IsColChooserApplied) 
       ApplyColChooser(null, false, false); 
      else 
      { 
       // The purpose of calling ApplyColChooser() here is to order the column headers properly. The GridView 
       // at this point will have reverted the column headers to their original order regardless of ViewState, 
       // so we need to apply our own ordering. (This is not true of data cells, so we don't have to apply 
       // ordering to them, as reflected by the parameters of the call.) 

       // If we have already processed column reordering upon the column chooser panel being submitted, 
       // don't repeat the operation. 
       if (!_ColChooserPanelSubmitted) 
        ApplyColChooser(null, false, true); 
      } 
     } 
    } 
Смежные вопросы