Frage

I have two select lists in my ASP.NET site that are filled by the server with some elements.

// .aspx
<asp:dropdownlist id="abc" runat="server"></asp:dropdownlist>
<asp:dropdownlist id="def" runat="server"></asp:dropdownlist>

// .aspx.cs
abc.Items.Add(new ListItem("element1", "value1"));
def.Items.Add(new ListItem("element1", "value1"));

Due to too complicated reasons to explain right now, I also need to modify the options of the select lists with JavaScript, adding some values.

// In the <head> of the .aspx page
var abcList = document.getElementById("abc");
var defList = document.getElementById("def");
var newAbcElement = new Option("element2", "value2", false, false);
var newDefElement = new Option("element2", "value2", false, false);
abcList.options[abcList.length] = newAbcElement;
defList.options[defList.length] = newDefElement;

Of course, this will mess up Even Validation as soon as I send the form back to the server (be it by submitting or as a PostBack from some other form elements with AutoPostBack="true").

Invalid postback or callback argument. Event validation is enabled using in configuration or <%@ Page EnableEventValidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.

Now, I don't have the resources and budget to completely overhaul the whole page design, so: What is the fastest and easiest way to change the dropdownlist that does not mean I have to rewrite the whole thing?

So that the values added via JavaScript are recognized by my CodeBehind file when submitting the form?

War es hilfreich?

Lösung

Ok, here is one more option for you. You can add those items to your lists using AsyncPostBackTrigger.

Some hidden fields:

<asp:TextBox ID="newItemsForAbc" runat="server" style="display:none;"></asp:TextBox>
<asp:TextBox ID="newItemsForDef" runat="server" style="display:none;"></asp:TextBox>
<asp:Button ID="addNewItems" runat="server" OnClick="addNewItems_Click"
  style="display:none;" />

The Update Panel:

<asp:UpdatePanel runat="server" ID="UpdatePanel" UpdateMode="Conditional">
   <ContentTemplate>
     <asp:dropdownlist id="abc" runat="server"></asp:dropdownlist>
     <asp:dropdownlist id="def" runat="server"></asp:dropdownlist>
   </ContentTemplate>
   <Triggers>
     <asp:AsyncPostBackTrigger ControlID="addNewItems" EventName="Click" />
   </Triggers>
 </asp:UpdatePanel>

JS Function for doing an async post back:

<script type="text/javascript"> function UpdateStuff(value1, value2)
{
   var abcItems = document.getElementById("<%= newItemsForAbc.ClientID %>");
   var defItems = document.getElementById("<%= newItemsForDef.ClientID %>");
   abcItems.value=value1;
   defItems.value=value2;
   __doPostBack("<%= addNewItems.ClientID %>","");
}
</script>

Server-side function that handles button click:

protected void addNewItems_Click(object sender, EventArgs e)
{
    string[] n1 = newItemsForAbc.Text.Split(';');
    string[] n2 = newItemsForDef.Text.Split(';');

    foreach(string i in n1)
    {
         abc.Items.Add(new ListItem(i, i));
    }

    foreach(string i in n2)
    {
         def.Items.Add(new ListItem(i,i));
    } 
}

To Update Your Lists:

var newAbcElements = "Element1;Element2;Element3";
var newDefElements = "Element4;Element5";
UpdateStuff(newAbcElements, newDefElements);

Final note: This piece of code probably will not do the job for you as it is. You may need to change the way you store new items in a string, thus splitting/parsing would change too. You may even need different strings for displaying a list item and its actual value. But I believe you get the basic idea.

Andere Tipps

You can disable the ViewState entirely for the DropDownList.

<asp:dropdownlist id="abc" runat="server" EnableViewState="false"></asp:dropdownlist>

To your question update:

This changes the question quite a lot. The new question is answered here: Invalid postback or callback argument. Event validation is enabled using '<pages enableEventValidation="true"/>'

You have a few options.

First, you might rewrite your code so that the server side generates all possible items for the DropDownList and then in your JavaScript remove the unneeded items instead of adding new ones.

Second option is to create a custom class derived from System.Web.UI.WebControls.DropDownList. The class should contain the one method shown below. The important piece is that your custom class will not have the System.Web.UI.SupportsEventValidationAttribute added to it - so DropDownList base methods will skip the event validation automatically. Now replace the usage from <asp:dropdownlist> to your method.

In case you can't modify the .aspx code (or you have a ton of dropdownlists to replace) you might use tag mapping in your configuration.

namespace Project.MyWebControls
{
    public class MyDropDownList : System.Web.UI.WebControls.DropDownList
    { 
        protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection)
        {
            if (base.LoadPostData(postDataKey, postCollection))
                return true;

            // this means that the value selected was not present in the .Items collection
            string[] values = postCollection.GetValues(postDataKey);
            if (values == null || values.Length == 0)
                return false;

            // add the value to the Items collection so that it can be processed later on.
            this.Items.Add(new ListItem("Custom value created by JavaScript", values[0]));
            this.SetPostDataSelection(this.Items.Count - 1);
        }
    }
}

Note that depending on your code you might want to remove these custom values from the Items collection before rendering.

Sample for the .aspx file:

<%@ Register TagPrefix="my" Namespace="Project.MyWebControls" Assembly="Project" %>
<my:MyDropDownList runat="server" ...></my:MyDropDownList>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top