Пользовательский шаблонист ASP.NET выбрасывает аргумент вне диапазона (индекс) при нажатии кнопки - PullRequest
0 голосов
/ 17 марта 2010

У меня есть класс BaseTemplate

public abstract class BaseTemplate : ITemplate

Это добавляет элементы управления и предоставляет абстрактные методы для реализации в наследующем классе. Затем наследующий класс добавляет свой HTML в соответствии с источником данных и управляет связыванием данных.

Это все работает нормально - у меня появляется элемент управления с правильно проанализированным html.

Проблема в том, что базовый класс добавляет в шаблон элементы управления, которые имеют свои собственные аргументы CommandName; идея заключается в том, что класс, реализующий пользовательский шаблонный список данных, будет обеспечивать логику установки выбранных и редактируемых индексов. Этот класс также управляет связыванием данных и т. Д. Он устанавливает все шаблоны в списке данных в методе 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

код

Базовый класс:

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
}

1 Ответ

4 голосов
/ 25 марта 2010

У вас есть метод

void deleteNominalGroup(int index)

, который выполняет следующую строку кода (используя параметр индекса)

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

именно это list[index], я думаю, выбрасывает исключение вне границ. Я думаю, что это потому, что вы вызываете метод в ItemCommand swtich заявлении

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

Значение e.Item.ItemIndex вызывает вашу проблему. Вы захотите проверить это значение, и что этот элемент не является верхним / нижним колонтитулом и т. Д. Я бы предложил (для здравого смысла) добавить следующую проверку в deleteNominalGroup метод

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