-1

I have a bit of a situation. Im new to asp but old hat with .net winforms. I am currently generating asp pages dynamically. Recently I was asked to put a filter dropdown into a column header. So I created a method that generates the template and the column and adds the Label for the name and the drop down. No big deal. Originally I couldn't get the event to raise so I set it to AutoPostBack = true and the event fired but the value isn't being retained.

My Debugging revealed some interesting information. When I first select a value in the dropdown list. I noticed the databind fires then the SaveViewState goes of (Which I over rode to solve multiple problems at once), then the OnSelectedValuechange Fires which has the right value in it but the Save Viewstate has already passed. then the Databind event occurs a second time and the original value is lost because of the recreation of the control.

So I guess my question here is: Is there a way to raise the event without the AutoPostBack Being set to true?

OR

Is there a way to dictate when Save and load viewstate fire?

OR

is there a way to force the OnSelectedValueChanged event to fire sooner?

Or am I missing something?

Here is the code for creating the Template:

public class GTemplate : Control, ITemplate
{
    protected Control InternalControl;
    private TemplateType tempType;
    internal string InnerControlDataSource;
    internal string DataTextField;
    internal string DataValueField;
    internal string InnerControlName;
    internal string HeaderText;
    internal string ItemsDataField;
    public EventHandler EventItem;
    ControlType innerControl;



    public GTemplate(TemplateType tt,WSControlItem Item,EventHandler EventItem)
    {
        innerControl = (ControlType)Convert.ToInt16(Item.GetAttributeValueByID("InnerControlType"));
        InnerControlName = Item.GetAttributeValueByID("InnerControlName");
        innerBlocking = PageControl;

        this.EventItem = EventItem;
        InnerControlDataSource = Item.DataSourceName;

        DataTextField = Item.GetAttributeValueByID("DataTextField");
        DataValueField = Item.GetAttributeValueByID("DataValueField");
        ItemsDataField = Item.GetAttributeValueByID("datafield");
        HeaderText = Item.Text;
        EventItem += EventItem;
        tempType = tt;


    }


    public void InstantiateIn(Control container)
    {
            switch (tempType)
            {

                case TemplateType.Header:

                    switch (innerControl)
                    {
                        case ControlType.DropDownList:
                            GLabel glbl = new GLabel();
                            glbl.Text = HeaderText;
                            container.Controls.Add(glbl);
                            GDropDownList ddl = new GDropDownList();
                            ddl.ID = InnerControlName;
                            ddl.isFilter = true;
                            ddl.DataSourceID = InnerControlDataSource;
                            ddl.DataTextField = DataTextField;
                            ddl.DataValueField = DataValueField;
                            ddl.AutoPostBack = true;

                            ddl.SelectedIndexChanged += new EventHandler(EventItem);
                            container.Controls.Add(ddl);

                            break;

                    }
                    break;
                case TemplateType.EditItem:
                    GLabel lbl = new GLabel();
                    lbl.ID = "Label_" + InnerControlName;
                    lbl.DataBinding += new EventHandler(tb1_DataBinding);
                    lbl.Text = "'<%# Eval(" + ItemsDataField + ") %>'";
                    container.Controls.Add(lbl);
                    break;
            }

    }

    protected void tb1_DataBinding(object sender, EventArgs e)

    {

        GLabel txtdata = (GLabel)sender;

        GridViewRow container = (GridViewRow)txtdata.NamingContainer;

        object dataValue = DataBinder.Eval(container.DataItem, ItemsDataField);

        if (dataValue != DBNull.Value)

        {

            txtdata.Text = dataValue.ToString();

        }
    }
}

As you can probably tell I've tried several solutions and spent a couple days trying to figure this out. One thing I did notice is if I remove the event the value passes to and from my save and view load state overrides with no issue.

Here is where they are added to the grid:

                    GTemplateField gtf = new GTemplateField(Item, Control_LoadBehavior);
                    GGridView ggv3 = (GGridView)Container;


                    gtf.HeaderText = Item.Text;
                    gtf.HeaderTemplate = new GTemplate(TemplateType.Header, Item, Control_LoadBehavior);

                    gtf.ItemTemplate = new GTemplate(TemplateType.EditItem, Item, Control_LoadBehavior);


                    ggv3.Columns.Add(gtf);

And last but not least the subclassed(I had to to keep common Properties between my controls so I could override the viewstate) DropdownList:

/// <summary>
/// A custom DropDownList class that extends the functionality of its base class and includes additional properties.
/// </summary>
public class GDropDownList: DropDownList
{
    public bool isFilter { get; set; }

    /// <summary>
    /// The default constructor for a GDropDownList object.
    /// </summary>
    public GDropDownList()
        : base()
    {

    }

    internal EventHandler InnerEvent;

    /// <summary>
    /// Returns the text property of the control.
    /// </summary>
    public string ReturnValue
    {
        get { return SelectedValue; }
    }

    /// <summary>
    /// Currently, this variable is not being used.
    /// </summary>
    public string ReturnSetting;

    /// <summary>
    /// Returns the text property of the control. To set the value, see SetViewStateData.
    /// </summary>
    public string GetViewStateData
    {
        get { return SelectedValue; }

    }

    /// <summary>
    /// Sets the text property of the control. To get the value, see GetViewStateData.
    /// </summary>
    public string SetViewStateData
    {
        set { SelectedValue = value; }
    }

    /// <summary>
    /// Currently, this property is not being used.
    /// </summary>
    public string GetComparitiveValue
    {
        get { return ""; }
    }

    protected override void OnSelectedIndexChanged(EventArgs e)
    {
        string i = SelectedValue;//i need to store the value if its not blank here, Where the fuck do I store it?
        base.OnSelectedIndexChanged(e);
    }

    public override void DataBind()
    {

            base.DataBind();

        if (isFilter)
            Items.Insert(0, new ListItem("Select Filter", ""));


    }

}

}

  • do you have a `Page_Load` event handler.. if so are you checking for `If(IsPostBack){ }`.. sounds like a PostBack issue just from reading your title.. – MethodMan Jul 01 '16 at 19:37
  • I tackled that problem early on. All the controls are being created in a !ispostback block. I think it's a timing issue. The databind seems to be firing then saveviewstate then the selectedindexchange fires (having the right value) then the load viewstate and another databind. – Scott Wade Jul 02 '16 at 23:49
  • it's not a timing issue it's understanding the `Page Life Cycle` as well as what events get triggered and always triggered in regards to if a property has the `Causes PostBack` set.. you should have a `if(!isPostBack){} else {}` and also a way to rebind before the page is rendered.. check into `Pre_Render` events that you can create on your own as well but you would have to know as well as understand when and where to use it as well as call it. – MethodMan Jul 03 '16 at 16:35
  • I have the if(!ispostback) in place already. It is managing all of my control creation inside the Page init. I am not explicitly calling .Databind for this control anywhere in the application. It seems to be happening somewhere else possibly as part of the gridview. Databind. I'm retaining the values of multiple other controls with no issue. I cannot for the life of me figure out why the drop down list inside a gridview header is behaving differently. Could you explain why that would occur? – Scott Wade Jul 04 '16 at 18:34
  • @MethodMan I tested the PreRender to see if the value was still contained within the control It wasn't. Something between the OnSelectedIndexChanged and the DataBind is clearing the value. I suspect its because this dropdown is being used as a grid filter inside the grid header and the Grid is being reconstructed with the new DataSet the ctrl just ceases to exist. I have a friend who gave me an Idea. Ill let you know if it pans out. – Scott Wade Jul 05 '16 at 14:25
  • @MethodMan It panned out, see the answer attached – Scott Wade Jul 05 '16 at 15:49

1 Answers1

0

So after some research and a bunch more trial and error I discovered the Control was being destroyed when the OnSelectedValueChange was being fired and the SQL dataset repopulating the datasource. So I put a wrapper around the Session state as suggested in this post [link]'Session' does not exist in the current context and all is working.

Here is the Code I adapted:

public class MySession
{
    // private constructor
    private MySession()
    {
        Filters = new List<PageValueItem>();
    }

    // Gets the current session.
    public static MySession Current
    {
        get
        {
            MySession session =
              (MySession)HttpContext.Current.Session["__MySession__"];
            if (session == null)
            {
                session = new MySession();
                HttpContext.Current.Session["__MySession__"] = session;
            }
            return session;
        }

    }

    public static void SaveFilterValue(string ID, string value)
    {
        MySession session =
              (MySession)HttpContext.Current.Session["__MySession__"];
        if (session == null)
        {
            session = new MySession();
            session.Filters.Add(new PageValueItem(ID, value));
            HttpContext.Current.Session["__MySession__"] = session;
        }
        else
        {
            session.Filters.Add(new PageValueItem(ID, value));
            HttpContext.Current.Session["__MySession__"] = session;
        }
    }

    public static string GetFilterValue(string ID)
    {
        string retVal = null;

        MySession session =
              (MySession)HttpContext.Current.Session["__MySession__"];
        if (session != null)
        {
            foreach(PageValueItem pvi in session.Filters)
            {
                if(pvi.ID == ID)
                {
                    retVal = pvi.Value;

                }
            }

        }

        return retVal;

    }

    private List<PageValueItem> Filters;
}

PageValueItem is just an object that stores the ID of the DropDownList and the value.

Community
  • 1
  • 1