ASP.NET 自定义模板化数据列表在按下按钮时抛出参数超出范围(索引)

发布于 2024-08-25 03:01:51 字数 22514 浏览 6 评论 0原文

我有一个类 BaseTemplate

public abstract class BaseTemplate : ITemplate

它添加了控件,并提供了在继承类中实现的抽象方法。然后继承类根据其数据源添加其 html 并管理数据绑定。

这一切都工作正常 - 我得到了带有正确解析的 html 的控件。

问题在于基类将具有自己的 CommandName 参数的控件添加到模板中;这个想法是,实现自定义模板化 dataList 的类将提供设置选定索引和编辑索引的逻辑。该类还管理数据绑定等。它在 Init 方法中设置数据列表上的所有模板(这是此异常的另一个原因)。

当我点击这些按钮之一时,会引发异常 - 我尝试在各处连接它们的单击和命令事件,以防出现问题。我还确保它们的命令名称与任何系统命令名称都不匹配。堆栈跟踪不包含对我的方法或对象的任何引用,这就是我如此陷入困境的原因。这是我能想象到的最无益的信息。

真正令人沮丧的是,我无法触发断点 - 即问题发生在我单击按钮之后,但之前我的代码可以执行。

上次发生此异常是当我在用户控件中包含此代码并将模板分配给 PageLoad 中的数据列表时。我将它们移入 init 来解决这个问题;然而,这是当时存在的一个问题,我不知道是什么原因导致的,更不用说如何解决它了(索引超出范围在不知道索引的情况下并没有真正的帮助。)

异常详细信息

Exception Details: System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: index

堆栈跟踪

[ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: index]
   System.Web.UI.ControlCollection.get_Item(Int32 index) +8665582
   System.Web.UI.WebControls.DataList.GetItem(ListItemType itemType, Int32 repeatIndex) +8667655
       System.Web.UI.WebControls.DataList.System.Web.UI.WebControls.IRepeatInfoUser.GetItemStyle(ListItemType itemType, Int32 repeatIndex) +11
   System.Web.UI.WebControls.RepeatInfo.RenderVerticalRepeater(HtmlTextWriter writer, IRepeatInfoUser user, Style controlStyle, WebControl baseControl) +8640873
   System.Web.UI.WebControls.RepeatInfo.RenderRepeater(HtmlTextWriter writer, IRepeatInfoUser user, Style controlStyle, WebControl baseControl) +27
   System.Web.UI.WebControls.DataList.RenderContents(HtmlTextWriter writer) +208
   System.Web.UI.WebControls.BaseDataList.Render(HtmlTextWriter writer) +30
   System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
   System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +134
   System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19
   System.Web.UI.HtmlControls.HtmlForm.RenderChildren(HtmlTextWriter writer) +163
   System.Web.UI.HtmlControls.HtmlContainerControl.Render(HtmlTextWriter writer) +32
   System.Web.UI.HtmlControls.HtmlForm.Render(HtmlTextWriter output) +51
   System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
   System.Web.UI.HtmlControls.HtmlForm.RenderControl(HtmlTextWriter writer) +40
   System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +134
   System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19
   System.Web.UI.Page.Render(HtmlTextWriter writer) +29
   System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1266

: code

基类:

public abstract class BaseTemplate : ITemplate 
{
    ListItemType _templateType;
    public BaseTemplate(ListItemType theTemplateType)
    { _templateType = theTemplateType; }     

    public ListItemType ListItemType
    { get { return _templateType; } }

    #region ITemplate Members

    public void InstantiateIn(Control container)
    {
        PlaceHolder ph = new PlaceHolder();
        container.Controls.Add(ph);
    
        Literal l = new Literal();
        switch (_templateType)
        {
            case ListItemType.Header:
            {                         
                ph.Controls.Add(new LiteralControl(@"<table><tr>"));
                InstantiateInHeader(ph);
                ph.Controls.Add(new LiteralControl(@"</tr>"));
                break;
            }
            case ListItemType.Footer:
            {
                ph.Controls.Add(new LiteralControl(@"<tr>"));
                InstantiateInFooter(ph);
                ph.Controls.Add(new LiteralControl(@"</tr></table>"));
                break;
            }
            case ListItemType.Item:
            {
                ph.Controls.Add(new LiteralControl(@"<tr>"));
                InstantiateInItem(ph);
                ph.Controls.Add(new LiteralControl(@"<td>"));

                Button select = new Button();
                select.ID = "btnSelect";
                select.CommandName = "SelectRow";
                select.Text = "Select";
                ph.Controls.Add(select);

                ph.Controls.Add(new LiteralControl(@"</td>"));
                ph.Controls.Add(new LiteralControl(@"</tr>"));
                ph.DataBinding += new EventHandler(ph_DataBinding);

                break;
            }
            case ListItemType.AlternatingItem:
            {
                ph.Controls.Add(new LiteralControl(@"<tr>"));
                InstantiateInAlternatingItem(ph);
                ph.Controls.Add(new LiteralControl(@"<td>"));

                Button select = new Button();
                select.ID = "btnSelect";
                select.CommandName = "SelectRow";
                select.Text = "Select";
                ph.Controls.Add(select);

                ph.Controls.Add(new LiteralControl(@"</td>"));
                ph.Controls.Add(new LiteralControl(@"</tr>"));
                ph.DataBinding+=new EventHandler(ph_DataBinding);
                break;

            }
            case ListItemType.SelectedItem:
            {
                ph.Controls.Add(new LiteralControl(@"<tr>"));
                InstantiateInItem(ph);
                ph.Controls.Add(new LiteralControl(@"<td>"));

                Button edit = new Button();
                edit.ID = "btnEdit";
                edit.CommandName = "EditRow";
                edit.Text = "Edit";
                ph.Controls.Add(edit);

                Button delete = new Button();
                delete.ID = "btnDelete";
                delete.CommandName = "DeleteRow";
                delete.Text = "Delete";
                ph.Controls.Add(delete);

                ph.Controls.Add(new LiteralControl(@"</td>"));
                ph.Controls.Add(new LiteralControl(@"</tr>"));
                ph.DataBinding += new EventHandler(ph_DataBinding);
                break;
            }
            case ListItemType.EditItem:
            {
                ph.Controls.Add(new LiteralControl(@"<tr>"));
                InstantiateInEdit(ph);

                ph.Controls.Add(new LiteralControl(@"<td>"));

                Button save = new Button();
                save.ID = "btnSave";
                save.CommandName = "SaveRow";
                save.Text = "Save";
                ph.Controls.Add(save);

                Button cancel = new Button();
                cancel.ID = "btnCancel";
                cancel.CommandName = "CancelRow";
                cancel.Text = "Cancel";
                ph.Controls.Add(cancel);

                ph.Controls.Add(new LiteralControl(@"</td>"));
                ph.Controls.Add(new LiteralControl(@"</tr>"));
                ph.DataBinding += new EventHandler(ph_DataBinding);
                break;
            }
            case ListItemType.Separator:
            {
                InstantiateInSeperator(ph);
                break;
            }                     
        }            
    }

    void ph_DataBinding(object sender, EventArgs e)
    {
        DataBindingOverride(sender, e);
    }

    /// <summary>
    /// the controls placed into the PlaceHolder will get wrapped in &lt;table&gt;&lt;tr&gt;   &lt;/tr&gt;. I.e. you need to provide the column names wrapped in &lt;td&gt;&lt;/td&gt; tags.
    /// </summary>
    /// <param name="header"></param>
    public abstract void InstantiateInHeader(PlaceHolder ph);
    /// <summary>
    /// the controls will have a column added after them and so require each column to be properly wrapped in &lt;td&gt;&lt;/td&gt; tags. The &lt;tr&gt;&lt;/tr&gt; is handled in the base class.
    /// </summary>
    /// <param name="ph"></param>
    public abstract void InstantiateInItem(PlaceHolder ph);
    /// <summary>
    /// the controls will have a column added after them and so require each column to be properly wrapped in &lt;td&gt;&lt;/td&gt; tags. The &lt;tr&gt;&lt;/tr&gt; is handled in the base class.
    /// </summary>
    /// <param name="ph"></param>
    public abstract void InstantiateInAlternatingItem(PlaceHolder ph);
    /// <summary>
    /// the controls will have a column added after them and so require each column to be properly wrapped in &lt;td&gt;&lt;/td&gt; tags. The &lt;tr&gt;&lt;/tr&gt; is handled in the base class.
    /// </summary>
    /// <param name="ph"></param>
    public abstract void InstantiateInEdit(PlaceHolder ph);
    /// <summary>
    /// Any html used in the footer will have &lt;/tr&gt;&lt;table&gt; appended to the end.
    /// &lt;tr&gt; will be appended to the front.
    /// </summary>
    /// <param name="ph"></param>
    public abstract void InstantiateInFooter(PlaceHolder ph); 
    /// <summary>
    /// the controls will have a column added after them and so require each column to be properly wrapped in &lt;td&gt;&lt;/td&gt; tags. The &lt;tr&gt;&lt;/tr&gt; is handled in the base class.
    /// Adds Delete and Edit Buttons after the table contents.
    /// </summary>
    /// <param name="ph"></param>
    public abstract void InstantiateInSelectedItem(PlaceHolder ph);
    /// <summary>
    /// The base class provides no &lt;tr&gt;&lt;/tr&gt; tags
    /// </summary>
    /// <param name="ph"></param>
    public abstract void InstantiateInSeperator(PlaceHolder ph);        
    /// <summary>
    /// Use this method to bind the controls to their data.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public abstract  void DataBindingOverride(object sender, EventArgs e);

    #endregion
}

继承类:

public class NominalGroupTemplate : BaseTemplate 
{
    public NominalGroupTemplate(ListItemType theListItemType)
        : base(theListItemType) { }

    public override void InstantiateInHeader(PlaceHolder ph)
    {
        ph.Controls.Add(new LiteralControl(@"<td>ID</td><td>Group</td><td>IsPositive</td>"));
    }

    public override void InstantiateInItem(PlaceHolder ph)
    {
        ph.Controls.Add(new LiteralControl(@"<td>"));
        Label lblID = new Label();
        lblID.ID = "lblID";
        ph.Controls.Add(lblID);
        ph.Controls.Add(new LiteralControl(@"</td><td>"));
        Label lblGroup = new Label();
        lblGroup.ID = "lblGroup";
        ph.Controls.Add(lblGroup);
        ph.Controls.Add(new LiteralControl(@"</td><td>"));
        CheckBox chkIsPositive = new CheckBox();
        chkIsPositive.ID = "chkIsPositive";
        chkIsPositive.Enabled = false;
        ph.Controls.Add(chkIsPositive);
        ph.Controls.Add(new LiteralControl(@"</td>"));
    }

    public override void InstantiateInAlternatingItem(PlaceHolder ph)
    {
        InstantiateInItem(ph);
    }

    public override void InstantiateInEdit(PlaceHolder ph)
    {
        ph.Controls.Add(new LiteralControl(@"<td>"));
        Label lblID = new Label();
        lblID.ID = "lblID";
        ph.Controls.Add(lblID);
        ph.Controls.Add(new LiteralControl(@"</td><td>"));
        TextBox txtGroup = new TextBox();
        txtGroup.ID = "txtGroup";
        txtGroup.Visible = true;
        txtGroup.Enabled = true ;
        ph.Controls.Add(txtGroup);
        ph.Controls.Add(new LiteralControl(@"</td><td>"));
        CheckBox chkIsPositive = new CheckBox();
        chkIsPositive.ID = "chkIsPositive";
        chkIsPositive.Visible = true;
        chkIsPositive.Enabled = true ;
        ph.Controls.Add(chkIsPositive);
        ph.Controls.Add(new LiteralControl(@"</td>")); 
    }

    public override void InstantiateInFooter(PlaceHolder ph)
    {
        InstantiateInHeader(ph); 
    }

    public override void InstantiateInSelectedItem(PlaceHolder ph)
    {
        ph.Controls.Add(new LiteralControl(@"<td>"));
        Label lblID = new Label();
        lblID.ID = "lblID";
        ph.Controls.Add(lblID);
        ph.Controls.Add(new LiteralControl(@"</td><td>"));
        TextBox txtGroup = new TextBox();
        txtGroup.ID = "txtGroup";
        txtGroup.Visible = true;
        txtGroup.Enabled = false;
        ph.Controls.Add(txtGroup);
        ph.Controls.Add(new LiteralControl(@"</td><td>"));
        CheckBox chkIsPositive = new CheckBox();
        chkIsPositive.ID = "chkIsPositive";
        chkIsPositive.Visible = true;
        chkIsPositive.Enabled = false;
        ph.Controls.Add(chkIsPositive);
        ph.Controls.Add(new LiteralControl(@"</td>"));  
    }

    public override void InstantiateInSeperator(PlaceHolder ph)
    {             
    }

    public override void DataBindingOverride(object sender, EventArgs e)
    {
        PlaceHolder ph = (PlaceHolder)sender;
        DataListItem li = (DataListItem)ph.NamingContainer;
        int id = Convert.ToInt32(DataBinder.Eval(li.DataItem, "ID"));
        string group = (string)DataBinder.Eval(li.DataItem, "Group");
        bool isPositive = Convert.ToBoolean(DataBinder.Eval(li.DataItem, "IsPositive"));
        switch (this.ListItemType)
        {
            case ListItemType.Item:
            case ListItemType.AlternatingItem:
            {                         
                ((Label)ph.FindControl("lblID")).Text = id.ToString();
                ((Label)ph.FindControl("lblGroup")).Text = group;
                ((CheckBox)ph.FindControl("chkIsPositive")).Text = isPositive.ToString();
                break;
            }
            case ListItemType.EditItem:
            case ListItemType.SelectedItem:
            {
                ((TextBox)ph.FindControl("lblID")).Text = id.ToString();
                ((TextBox)ph.FindControl("txtGroup")).Text = group;
                ((CheckBox)ph.FindControl("chkIsPositive")).Text = isPositive.ToString();
                break;
            }   
        }
    }
}

从这里我将控件添加到代码后面的页面

 public partial class NominalGroupbroke : System.Web.UI.UserControl
{
    public void SetNominalGroupList(IList<BONominalGroup> theNominalGroups)
    {
        XElement data = Serialiser<BONominalGroup>.SerialiseObjectList(theNominalGroups);
        ViewState.Add("nominalGroups", data.ToString());
        dlNominalGroup.DataSource = theNominalGroups;
        dlNominalGroup.DataBind();
    }

    protected void Page_init()
    {
        dlNominalGroup.HeaderTemplate = new NominalGroupTemplate(ListItemType.Header);
        dlNominalGroup.ItemTemplate = new NominalGroupTemplate(ListItemType.Item);
        dlNominalGroup.AlternatingItemTemplate = new NominalGroupTemplate(ListItemType.AlternatingItem);
        dlNominalGroup.SeparatorTemplate = new NominalGroupTemplate(ListItemType.Separator);
        dlNominalGroup.SelectedItemTemplate = new NominalGroupTemplate(ListItemType.SelectedItem);
        dlNominalGroup.EditItemTemplate = new NominalGroupTemplate(ListItemType.EditItem);
        dlNominalGroup.FooterTemplate = new NominalGroupTemplate(ListItemType.Footer);
    } 

    protected void Page_Load(object sender, EventArgs e)
    {          
        dlNominalGroup.ItemCommand += new DataListCommandEventHandler(dlNominalGroup_ItemCommand);
    }

    void dlNominalGroup_Init(object sender, EventArgs e)
    {
        dlNominalGroup.HeaderTemplate = new NominalGroupTemplate(ListItemType.Header);
        dlNominalGroup.ItemTemplate = new NominalGroupTemplate(ListItemType.Item);
        dlNominalGroup.AlternatingItemTemplate = new NominalGroupTemplate(ListItemType.AlternatingItem);
        dlNominalGroup.SeparatorTemplate = new NominalGroupTemplate(ListItemType.Separator);
        dlNominalGroup.SelectedItemTemplate = new NominalGroupTemplate(ListItemType.SelectedItem);
        dlNominalGroup.EditItemTemplate = new NominalGroupTemplate(ListItemType.EditItem);
        dlNominalGroup.FooterTemplate = new NominalGroupTemplate(ListItemType.Footer);
    }

    void dlNominalGroup_DataBinding(object sender, EventArgs e)
    {
    }

    void deleteNominalGroup(int index)
    {
        XElement data = XElement.Parse(Convert.ToString( ViewState["nominalGroups"] ));
        IList<BONominalGroup> list = Serialiser<BONominalGroup>.DeserialiseObjectList(data);
        FENominalGroup.DeleteNominalGroup(list[index].ID);
        list.RemoveAt(index);
        data = Serialiser<BONominalGroup>.SerialiseObjectList(list);
        ViewState["nominalGroups"] = data.ToString();
        dlNominalGroup.DataSource = list;
        dlNominalGroup.DataBind();
    }

    void updateNominalGroup(DataListItem theItem)
    {
        XElement data = XElement.Parse(Convert.ToString(  ViewState["nominalGroups"]));
        IList<BONominalGroup> list = Serialiser<BONominalGroup>.DeserialiseObjectList(data);
        BONominalGroup old = list[theItem.ItemIndex];

        BONominalGroup n = new BONominalGroup();
        byte id = Convert.ToByte(((TextBox)theItem.FindControl("lblID")).Text);
        string group = ((TextBox)theItem.FindControl("txtGroup")).Text;
        bool isPositive = Convert.ToBoolean(((CheckBox)theItem.FindControl("chkIsPositive")).Text);
        n.ID = id;
        n.Group = group;
        n.IsPositive = isPositive;

        FENominalGroup.UpdateNominalGroup(old, n);

        list[theItem.ItemIndex] = n;
        data = Serialiser<BONominalGroup>.SerialiseObjectList(list);
        ViewState["nominalGroups"] = data.ToString();
    }

    void dlNominalGroup_ItemCommand(object source, DataListCommandEventArgs e)
    {
        DataList l = (DataList)source;
        switch (e.CommandName)
        {
            case "SelectRow":
            {
                if (l.EditItemIndex == -1)
                {
                    l.SelectedIndex = e.Item.ItemIndex;
                    l.EditItemIndex = -1;
                }
                break;
            }
            case "EditRow":
            {
                if (l.SelectedIndex == e.Item.ItemIndex)
                {
                    l.EditItemIndex = e.Item.ItemIndex;
                }
                break;
            }
            case "DeleteRow":
            {
                deleteNominalGroup(e.Item.ItemIndex);
                l.EditItemIndex = -1;
                try
                {
                    l.SelectedIndex = e.Item.ItemIndex;
                }
                catch
                {
                    l.SelectedIndex = -1;
                }
                break;
            }
            case "CancelRow":
            {
                l.SelectedIndex = l.EditItemIndex;
                l.EditItemIndex = -1;  
                break;
            }
            case "SaveRow":
            {
                updateNominalGroup(e.Item);
                try
                {
                    l.SelectedIndex = e.Item.ItemIndex;
                }
                catch 
                {
                    l.SelectedIndex = -1;
                }
                l.EditItemIndex = -1; 
                break;
            }
        }
    }   

,恐怕有很多代码,但它应该构建。

如果有人能发现我的愚蠢,谢谢。

BONominalGroup 类(请忽略我疯狂的 getHash 覆盖,我并不为此感到自豪)。
IAudit 在这里可以只是一个空接口,一切都会好起来的。
它曾经从另一个类继承,我已经清除了它 - 所以这里的序列化逻辑可能会被破坏。

public class BONominalGroup 
{  
    public BONominalGroup()
         

    #region Fields and properties
    private Int16 _ID;
    public Int16 ID
    {
        get { return _ID; }
        set { _ID = value; }
    }  
        
    private string _group;
    public string Group
    {
        get { return _group; }
        set { _group = value; }
    }

    private bool _isPositve;
    public bool IsPositive
    {
        get { return _isPositve; }
        set { _isPositve = value; }
    }
    #endregion

    public override bool Equals(object obj)
    {
        bool retVal = false;
        BONominalGroup ng = obj as BONominalGroup;
            
        if (ng!=null)
            if (ng._group == this._group &&
                ng._ID == this.ID &&
                ng.IsPositive == this.IsPositive)
            {
                retVal = true;
            }
        return retVal;
    } 
    public override int GetHashCode()
    {
        return ToString().GetHashCode();
    }    
    public override string ToString()
    {
        return "BONominalGroup{ID:" + this.ID.ToString() +
              ",Group:" + this.Group.ToString() +
              ",IsPositive:" + this.IsPositive.ToString() +
              "," + "}";
    }

    #region IXmlSerializable Members
    public override void ReadXml(XmlReader reader)
    {
        reader.ReadStartElement("BONominalGroup");
        this.ID = Convert.ToByte(reader.ReadElementString("id"));
        this.Group = reader.ReadElementString("group");
        this.IsPositive = Convert.ToBoolean(reader.ReadElementString("isPositive"));
        base.ReadXml(reader);
        reader.ReadEndElement();
    }

    public override void WriteXml(XmlWriter writer)
    {
        writer.WriteElementString("id", this.ID.ToString());
        writer.WriteElementString("group", this.Group);
        writer.WriteElementString("isPositive", this.IsPositive.ToString());
    //    writer.WriteStartElement("BOBase");
    //    base.WriteXml(writer);
        writer.WriteEndElement();
    }
    #endregion
}

I have a class BaseTemplate

public abstract class BaseTemplate : ITemplate

This adds the controls, and provides abstract methods to implement in the inheriting class. The inheriting class then adds its html according to its data source and manages the data binding.

This all works fine - I get the control appearing with properly parsed html.

The problem is that the base class adds controls into the template that have their own CommandName arguments; the idea is that the class that implements the custom templated dataList will provide the logic of setting the Selected and Edit Indexes. This class also manages the data binding, etc. It sets all of the templates on the datalist in the Init method (which was another cause of this exception).

The exception gets thrown when I hit one of these buttons - I have tried hooking up both their click and command events everywhere in case this was the problem. I have also ensured that their command names do not match any of the system ones. The stack trace does not include any references to my methods or objects which is why I am so stuck. It is the most unhelpful message I can imagine.

The really frustrating thing is that I cannot get a breakpoint to fire - i.e. the problem is happening after I click the button, but before and of my code can execute.

The last time this exception happened was when I had this code in a user control and was assigning the templates to the datalist in the PageLoad. I moved these into init to fix that problem; however, this is a problem that was there then and I have no idea what is causing it let alone how to solve it (and index out of range doesn't really help without knowing what index.)

The Exception Details

Exception Details: System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: index

The Stack Trace:

[ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: index]
   System.Web.UI.ControlCollection.get_Item(Int32 index) +8665582
   System.Web.UI.WebControls.DataList.GetItem(ListItemType itemType, Int32 repeatIndex) +8667655
       System.Web.UI.WebControls.DataList.System.Web.UI.WebControls.IRepeatInfoUser.GetItemStyle(ListItemType itemType, Int32 repeatIndex) +11
   System.Web.UI.WebControls.RepeatInfo.RenderVerticalRepeater(HtmlTextWriter writer, IRepeatInfoUser user, Style controlStyle, WebControl baseControl) +8640873
   System.Web.UI.WebControls.RepeatInfo.RenderRepeater(HtmlTextWriter writer, IRepeatInfoUser user, Style controlStyle, WebControl baseControl) +27
   System.Web.UI.WebControls.DataList.RenderContents(HtmlTextWriter writer) +208
   System.Web.UI.WebControls.BaseDataList.Render(HtmlTextWriter writer) +30
   System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
   System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +134
   System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19
   System.Web.UI.HtmlControls.HtmlForm.RenderChildren(HtmlTextWriter writer) +163
   System.Web.UI.HtmlControls.HtmlContainerControl.Render(HtmlTextWriter writer) +32
   System.Web.UI.HtmlControls.HtmlForm.Render(HtmlTextWriter output) +51
   System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
   System.Web.UI.HtmlControls.HtmlForm.RenderControl(HtmlTextWriter writer) +40
   System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +134
   System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19
   System.Web.UI.Page.Render(HtmlTextWriter writer) +29
   System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99
   System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1266

The code

Base class:

public abstract class BaseTemplate : ITemplate 
{
    ListItemType _templateType;
    public BaseTemplate(ListItemType theTemplateType)
    { _templateType = theTemplateType; }     

    public ListItemType ListItemType
    { get { return _templateType; } }

    #region ITemplate Members

    public void InstantiateIn(Control container)
    {
        PlaceHolder ph = new PlaceHolder();
        container.Controls.Add(ph);
    
        Literal l = new Literal();
        switch (_templateType)
        {
            case ListItemType.Header:
            {                         
                ph.Controls.Add(new LiteralControl(@"<table><tr>"));
                InstantiateInHeader(ph);
                ph.Controls.Add(new LiteralControl(@"</tr>"));
                break;
            }
            case ListItemType.Footer:
            {
                ph.Controls.Add(new LiteralControl(@"<tr>"));
                InstantiateInFooter(ph);
                ph.Controls.Add(new LiteralControl(@"</tr></table>"));
                break;
            }
            case ListItemType.Item:
            {
                ph.Controls.Add(new LiteralControl(@"<tr>"));
                InstantiateInItem(ph);
                ph.Controls.Add(new LiteralControl(@"<td>"));

                Button select = new Button();
                select.ID = "btnSelect";
                select.CommandName = "SelectRow";
                select.Text = "Select";
                ph.Controls.Add(select);

                ph.Controls.Add(new LiteralControl(@"</td>"));
                ph.Controls.Add(new LiteralControl(@"</tr>"));
                ph.DataBinding += new EventHandler(ph_DataBinding);

                break;
            }
            case ListItemType.AlternatingItem:
            {
                ph.Controls.Add(new LiteralControl(@"<tr>"));
                InstantiateInAlternatingItem(ph);
                ph.Controls.Add(new LiteralControl(@"<td>"));

                Button select = new Button();
                select.ID = "btnSelect";
                select.CommandName = "SelectRow";
                select.Text = "Select";
                ph.Controls.Add(select);

                ph.Controls.Add(new LiteralControl(@"</td>"));
                ph.Controls.Add(new LiteralControl(@"</tr>"));
                ph.DataBinding+=new EventHandler(ph_DataBinding);
                break;

            }
            case ListItemType.SelectedItem:
            {
                ph.Controls.Add(new LiteralControl(@"<tr>"));
                InstantiateInItem(ph);
                ph.Controls.Add(new LiteralControl(@"<td>"));

                Button edit = new Button();
                edit.ID = "btnEdit";
                edit.CommandName = "EditRow";
                edit.Text = "Edit";
                ph.Controls.Add(edit);

                Button delete = new Button();
                delete.ID = "btnDelete";
                delete.CommandName = "DeleteRow";
                delete.Text = "Delete";
                ph.Controls.Add(delete);

                ph.Controls.Add(new LiteralControl(@"</td>"));
                ph.Controls.Add(new LiteralControl(@"</tr>"));
                ph.DataBinding += new EventHandler(ph_DataBinding);
                break;
            }
            case ListItemType.EditItem:
            {
                ph.Controls.Add(new LiteralControl(@"<tr>"));
                InstantiateInEdit(ph);

                ph.Controls.Add(new LiteralControl(@"<td>"));

                Button save = new Button();
                save.ID = "btnSave";
                save.CommandName = "SaveRow";
                save.Text = "Save";
                ph.Controls.Add(save);

                Button cancel = new Button();
                cancel.ID = "btnCancel";
                cancel.CommandName = "CancelRow";
                cancel.Text = "Cancel";
                ph.Controls.Add(cancel);

                ph.Controls.Add(new LiteralControl(@"</td>"));
                ph.Controls.Add(new LiteralControl(@"</tr>"));
                ph.DataBinding += new EventHandler(ph_DataBinding);
                break;
            }
            case ListItemType.Separator:
            {
                InstantiateInSeperator(ph);
                break;
            }                     
        }            
    }

    void ph_DataBinding(object sender, EventArgs e)
    {
        DataBindingOverride(sender, e);
    }

    /// <summary>
    /// the controls placed into the PlaceHolder will get wrapped in <table><tr>   </tr>. I.e. you need to provide the column names wrapped in <td></td> tags.
    /// </summary>
    /// <param name="header"></param>
    public abstract void InstantiateInHeader(PlaceHolder ph);
    /// <summary>
    /// the controls will have a column added after them and so require each column to be properly wrapped in <td></td> tags. The <tr></tr> is handled in the base class.
    /// </summary>
    /// <param name="ph"></param>
    public abstract void InstantiateInItem(PlaceHolder ph);
    /// <summary>
    /// the controls will have a column added after them and so require each column to be properly wrapped in <td></td> tags. The <tr></tr> is handled in the base class.
    /// </summary>
    /// <param name="ph"></param>
    public abstract void InstantiateInAlternatingItem(PlaceHolder ph);
    /// <summary>
    /// the controls will have a column added after them and so require each column to be properly wrapped in <td></td> tags. The <tr></tr> is handled in the base class.
    /// </summary>
    /// <param name="ph"></param>
    public abstract void InstantiateInEdit(PlaceHolder ph);
    /// <summary>
    /// Any html used in the footer will have </tr><table> appended to the end.
    /// <tr> will be appended to the front.
    /// </summary>
    /// <param name="ph"></param>
    public abstract void InstantiateInFooter(PlaceHolder ph); 
    /// <summary>
    /// the controls will have a column added after them and so require each column to be properly wrapped in <td></td> tags. The <tr></tr> is handled in the base class.
    /// Adds Delete and Edit Buttons after the table contents.
    /// </summary>
    /// <param name="ph"></param>
    public abstract void InstantiateInSelectedItem(PlaceHolder ph);
    /// <summary>
    /// The base class provides no <tr></tr> tags
    /// </summary>
    /// <param name="ph"></param>
    public abstract void InstantiateInSeperator(PlaceHolder ph);        
    /// <summary>
    /// Use this method to bind the controls to their data.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public abstract  void DataBindingOverride(object sender, EventArgs e);

    #endregion
}

Inheriting class:

public class NominalGroupTemplate : BaseTemplate 
{
    public NominalGroupTemplate(ListItemType theListItemType)
        : base(theListItemType) { }

    public override void InstantiateInHeader(PlaceHolder ph)
    {
        ph.Controls.Add(new LiteralControl(@"<td>ID</td><td>Group</td><td>IsPositive</td>"));
    }

    public override void InstantiateInItem(PlaceHolder ph)
    {
        ph.Controls.Add(new LiteralControl(@"<td>"));
        Label lblID = new Label();
        lblID.ID = "lblID";
        ph.Controls.Add(lblID);
        ph.Controls.Add(new LiteralControl(@"</td><td>"));
        Label lblGroup = new Label();
        lblGroup.ID = "lblGroup";
        ph.Controls.Add(lblGroup);
        ph.Controls.Add(new LiteralControl(@"</td><td>"));
        CheckBox chkIsPositive = new CheckBox();
        chkIsPositive.ID = "chkIsPositive";
        chkIsPositive.Enabled = false;
        ph.Controls.Add(chkIsPositive);
        ph.Controls.Add(new LiteralControl(@"</td>"));
    }

    public override void InstantiateInAlternatingItem(PlaceHolder ph)
    {
        InstantiateInItem(ph);
    }

    public override void InstantiateInEdit(PlaceHolder ph)
    {
        ph.Controls.Add(new LiteralControl(@"<td>"));
        Label lblID = new Label();
        lblID.ID = "lblID";
        ph.Controls.Add(lblID);
        ph.Controls.Add(new LiteralControl(@"</td><td>"));
        TextBox txtGroup = new TextBox();
        txtGroup.ID = "txtGroup";
        txtGroup.Visible = true;
        txtGroup.Enabled = true ;
        ph.Controls.Add(txtGroup);
        ph.Controls.Add(new LiteralControl(@"</td><td>"));
        CheckBox chkIsPositive = new CheckBox();
        chkIsPositive.ID = "chkIsPositive";
        chkIsPositive.Visible = true;
        chkIsPositive.Enabled = true ;
        ph.Controls.Add(chkIsPositive);
        ph.Controls.Add(new LiteralControl(@"</td>")); 
    }

    public override void InstantiateInFooter(PlaceHolder ph)
    {
        InstantiateInHeader(ph); 
    }

    public override void InstantiateInSelectedItem(PlaceHolder ph)
    {
        ph.Controls.Add(new LiteralControl(@"<td>"));
        Label lblID = new Label();
        lblID.ID = "lblID";
        ph.Controls.Add(lblID);
        ph.Controls.Add(new LiteralControl(@"</td><td>"));
        TextBox txtGroup = new TextBox();
        txtGroup.ID = "txtGroup";
        txtGroup.Visible = true;
        txtGroup.Enabled = false;
        ph.Controls.Add(txtGroup);
        ph.Controls.Add(new LiteralControl(@"</td><td>"));
        CheckBox chkIsPositive = new CheckBox();
        chkIsPositive.ID = "chkIsPositive";
        chkIsPositive.Visible = true;
        chkIsPositive.Enabled = false;
        ph.Controls.Add(chkIsPositive);
        ph.Controls.Add(new LiteralControl(@"</td>"));  
    }

    public override void InstantiateInSeperator(PlaceHolder ph)
    {             
    }

    public override void DataBindingOverride(object sender, EventArgs e)
    {
        PlaceHolder ph = (PlaceHolder)sender;
        DataListItem li = (DataListItem)ph.NamingContainer;
        int id = Convert.ToInt32(DataBinder.Eval(li.DataItem, "ID"));
        string group = (string)DataBinder.Eval(li.DataItem, "Group");
        bool isPositive = Convert.ToBoolean(DataBinder.Eval(li.DataItem, "IsPositive"));
        switch (this.ListItemType)
        {
            case ListItemType.Item:
            case ListItemType.AlternatingItem:
            {                         
                ((Label)ph.FindControl("lblID")).Text = id.ToString();
                ((Label)ph.FindControl("lblGroup")).Text = group;
                ((CheckBox)ph.FindControl("chkIsPositive")).Text = isPositive.ToString();
                break;
            }
            case ListItemType.EditItem:
            case ListItemType.SelectedItem:
            {
                ((TextBox)ph.FindControl("lblID")).Text = id.ToString();
                ((TextBox)ph.FindControl("txtGroup")).Text = group;
                ((CheckBox)ph.FindControl("chkIsPositive")).Text = isPositive.ToString();
                break;
            }   
        }
    }
}

From here I added the control to a page the code behind

 public partial class NominalGroupbroke : System.Web.UI.UserControl
{
    public void SetNominalGroupList(IList<BONominalGroup> theNominalGroups)
    {
        XElement data = Serialiser<BONominalGroup>.SerialiseObjectList(theNominalGroups);
        ViewState.Add("nominalGroups", data.ToString());
        dlNominalGroup.DataSource = theNominalGroups;
        dlNominalGroup.DataBind();
    }

    protected void Page_init()
    {
        dlNominalGroup.HeaderTemplate = new NominalGroupTemplate(ListItemType.Header);
        dlNominalGroup.ItemTemplate = new NominalGroupTemplate(ListItemType.Item);
        dlNominalGroup.AlternatingItemTemplate = new NominalGroupTemplate(ListItemType.AlternatingItem);
        dlNominalGroup.SeparatorTemplate = new NominalGroupTemplate(ListItemType.Separator);
        dlNominalGroup.SelectedItemTemplate = new NominalGroupTemplate(ListItemType.SelectedItem);
        dlNominalGroup.EditItemTemplate = new NominalGroupTemplate(ListItemType.EditItem);
        dlNominalGroup.FooterTemplate = new NominalGroupTemplate(ListItemType.Footer);
    } 

    protected void Page_Load(object sender, EventArgs e)
    {          
        dlNominalGroup.ItemCommand += new DataListCommandEventHandler(dlNominalGroup_ItemCommand);
    }

    void dlNominalGroup_Init(object sender, EventArgs e)
    {
        dlNominalGroup.HeaderTemplate = new NominalGroupTemplate(ListItemType.Header);
        dlNominalGroup.ItemTemplate = new NominalGroupTemplate(ListItemType.Item);
        dlNominalGroup.AlternatingItemTemplate = new NominalGroupTemplate(ListItemType.AlternatingItem);
        dlNominalGroup.SeparatorTemplate = new NominalGroupTemplate(ListItemType.Separator);
        dlNominalGroup.SelectedItemTemplate = new NominalGroupTemplate(ListItemType.SelectedItem);
        dlNominalGroup.EditItemTemplate = new NominalGroupTemplate(ListItemType.EditItem);
        dlNominalGroup.FooterTemplate = new NominalGroupTemplate(ListItemType.Footer);
    }

    void dlNominalGroup_DataBinding(object sender, EventArgs e)
    {
    }

    void deleteNominalGroup(int index)
    {
        XElement data = XElement.Parse(Convert.ToString( ViewState["nominalGroups"] ));
        IList<BONominalGroup> list = Serialiser<BONominalGroup>.DeserialiseObjectList(data);
        FENominalGroup.DeleteNominalGroup(list[index].ID);
        list.RemoveAt(index);
        data = Serialiser<BONominalGroup>.SerialiseObjectList(list);
        ViewState["nominalGroups"] = data.ToString();
        dlNominalGroup.DataSource = list;
        dlNominalGroup.DataBind();
    }

    void updateNominalGroup(DataListItem theItem)
    {
        XElement data = XElement.Parse(Convert.ToString(  ViewState["nominalGroups"]));
        IList<BONominalGroup> list = Serialiser<BONominalGroup>.DeserialiseObjectList(data);
        BONominalGroup old = list[theItem.ItemIndex];

        BONominalGroup n = new BONominalGroup();
        byte id = Convert.ToByte(((TextBox)theItem.FindControl("lblID")).Text);
        string group = ((TextBox)theItem.FindControl("txtGroup")).Text;
        bool isPositive = Convert.ToBoolean(((CheckBox)theItem.FindControl("chkIsPositive")).Text);
        n.ID = id;
        n.Group = group;
        n.IsPositive = isPositive;

        FENominalGroup.UpdateNominalGroup(old, n);

        list[theItem.ItemIndex] = n;
        data = Serialiser<BONominalGroup>.SerialiseObjectList(list);
        ViewState["nominalGroups"] = data.ToString();
    }

    void dlNominalGroup_ItemCommand(object source, DataListCommandEventArgs e)
    {
        DataList l = (DataList)source;
        switch (e.CommandName)
        {
            case "SelectRow":
            {
                if (l.EditItemIndex == -1)
                {
                    l.SelectedIndex = e.Item.ItemIndex;
                    l.EditItemIndex = -1;
                }
                break;
            }
            case "EditRow":
            {
                if (l.SelectedIndex == e.Item.ItemIndex)
                {
                    l.EditItemIndex = e.Item.ItemIndex;
                }
                break;
            }
            case "DeleteRow":
            {
                deleteNominalGroup(e.Item.ItemIndex);
                l.EditItemIndex = -1;
                try
                {
                    l.SelectedIndex = e.Item.ItemIndex;
                }
                catch
                {
                    l.SelectedIndex = -1;
                }
                break;
            }
            case "CancelRow":
            {
                l.SelectedIndex = l.EditItemIndex;
                l.EditItemIndex = -1;  
                break;
            }
            case "SaveRow":
            {
                updateNominalGroup(e.Item);
                try
                {
                    l.SelectedIndex = e.Item.ItemIndex;
                }
                catch 
                {
                    l.SelectedIndex = -1;
                }
                l.EditItemIndex = -1; 
                break;
            }
        }
    }   

Lots of code there, I'm afraid, but it should build.

Thanks if anyone manages to spot my silliness.

The BONominalGroup class (please ignore my crazy getHash override, I'm not proud of it).
IAudit can just be an empty interface here and all will be fine.
It used to inherit from another class, I have cleaned that out - so the serialization logic may be broken here.

public class BONominalGroup 
{  
    public BONominalGroup()
         

    #region Fields and properties
    private Int16 _ID;
    public Int16 ID
    {
        get { return _ID; }
        set { _ID = value; }
    }  
        
    private string _group;
    public string Group
    {
        get { return _group; }
        set { _group = value; }
    }

    private bool _isPositve;
    public bool IsPositive
    {
        get { return _isPositve; }
        set { _isPositve = value; }
    }
    #endregion

    public override bool Equals(object obj)
    {
        bool retVal = false;
        BONominalGroup ng = obj as BONominalGroup;
            
        if (ng!=null)
            if (ng._group == this._group &&
                ng._ID == this.ID &&
                ng.IsPositive == this.IsPositive)
            {
                retVal = true;
            }
        return retVal;
    } 
    public override int GetHashCode()
    {
        return ToString().GetHashCode();
    }    
    public override string ToString()
    {
        return "BONominalGroup{ID:" + this.ID.ToString() +
              ",Group:" + this.Group.ToString() +
              ",IsPositive:" + this.IsPositive.ToString() +
              "," + "}";
    }

    #region IXmlSerializable Members
    public override void ReadXml(XmlReader reader)
    {
        reader.ReadStartElement("BONominalGroup");
        this.ID = Convert.ToByte(reader.ReadElementString("id"));
        this.Group = reader.ReadElementString("group");
        this.IsPositive = Convert.ToBoolean(reader.ReadElementString("isPositive"));
        base.ReadXml(reader);
        reader.ReadEndElement();
    }

    public override void WriteXml(XmlWriter writer)
    {
        writer.WriteElementString("id", this.ID.ToString());
        writer.WriteElementString("group", this.Group);
        writer.WriteElementString("isPositive", this.IsPositive.ToString());
    //    writer.WriteStartElement("BOBase");
    //    base.WriteXml(writer);
        writer.WriteEndElement();
    }
    #endregion
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

舂唻埖巳落 2024-09-01 03:01:51

您有一个方法

void deleteNominalGroup(int index)

执行以下代码行(使用索引参数),

FENominalGroup.DeleteNominalGroup(list[index].ID);

我认为这个 list[index] 正在抛出越界异常。我认为这是因为您调用 ItemCommand 开关语句中的方法

case "DeleteRow":
    {
       deleteNominalGroup(e.Item.ItemIndex);

e.Item.ItemIndex 值导致了您的问题。您需要检查此值以及该项目不是页眉/页脚等。我建议(为了理智)将以下检查添加到您的 deleteNominalGroup 方法中

 void deleteNominalGroup(int index)
 {
      if ((index < 0) || (index > list.Count())
           return;

You have a method

void deleteNominalGroup(int index)

which executes the following line of code (using the index parameter)

FENominalGroup.DeleteNominalGroup(list[index].ID);

it is this list[index] which I think is throwing the out of bounds exception. I think this because you call the method in the ItemCommand swtich statement

case "DeleteRow":
    {
       deleteNominalGroup(e.Item.ItemIndex);

The e.Item.ItemIndex value is causing your problem. You will want to check this value and that the item isn't a header/footer etc. I would suggest (for sanity) adding the following check to your deleteNominalGroup method

 void deleteNominalGroup(int index)
 {
      if ((index < 0) || (index > list.Count())
           return;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文