当enableViewState = false

时间:2016-01-20 10:13:34

标签: c# asp.net postback

我有一个DropDownList控件,它实际上并不想启用ViewState,因为服务器上可以随时提供项目列表。

在这种情况下,回发后显然会显示一个空的Items列表,但同时我希望触发SelectedIndexChanged事件(使用AutoPostBack)

DropDownList控件实际上是作为复合控件的一部分动态创建的,复合控件创建了任意数量的DDL - 其中一些项源自ASPX文件(复合控件内容),其他项目绑定到数据源。我希望这种复杂性不是问题的根源。

我的想法是我应该将列表数据绑定到初始PageLoad上的Items集合,并在PostBacks上重新绑定 late ,但我不确定何时。如果在PostBack上再次出现空SelectedIndexChanged列表,我也不确定是否会调用Items事件处理程序。

因为它是CompositeControl的一部分,我想知道是否应该在Control State中存储一些额外的信息。是否可以在Conposite Control Save/LoadControlStateSave/LoadViewStateRaisePostDataChangedEventRaisePostbackEvent中实施某些内容?

也许我应该在PostBack早期再次重新绑定Item列表,例如在PageLoad之前?

任何指针都将受到赞赏。

由于

下面提供的代码(删除大部分与问题无关的内容)

页面ASPX 请注意,我想动态填充{Group,Location,Division和BusinessUnit} DropDownLists的ListItems,而不将项目转储到ViewState,但{Enabled} DDL是下面定义的静态项目。

<cc1:FilterBar ID="FilterBar1" runat="server" CssClass="filterbar" OnFilterChanged="OnFilterChanged">
    <cc1:Filter ID="Group" Label="Group" Type="DropDownList" />
    <cc1:Filter ID="Location" Label="[Location]" Type="DropDownList" />
    <cc1:Filter ID="Division" Label="[Division]" Type="DropDownList" />
    <cc1:Filter ID="BusinessUnit" Label="[Business Unit]" Type="DropDownList" />
    <cc1:Filter ID="Enabled" Label="Users" Type="DropDownList">
        <asp:ListItem Value="X" Text="All"></asp:ListItem>
        <asp:ListItem Value="1" Text="Active Only"></asp:ListItem>
        <asp:ListItem Value="0" Text="Archived Only"></asp:ListItem>
    </cc1:Filter>
</cc1:FilterBar>

页面代码背后

    protected void Page_Load(object sender, EventArgs e)
    {
        //if (!Page.IsPostBack) // whether to restire BindFilterBar() to first load or not?
        BindFilterBar();
    }

    protected void BindFilterBar()
    {
        var h = new FilterBarBindHelper(FilterBar1);
        h.AutoBindLocation(Filter.UserLocation.ID);
        h.AutoBindDivision(Filter.UserDivision.ID);
        h.AutoBindBusinessUnit(Filter.UserBusinessUnit.ID);
        h.AutoBindGroup(Filter.UserGroup.ID);

        var filter = FilterBar1.GetFilterByID("Enabled");
        filter.SelectedValue = Filter.UserEnabledAsChar.ToString();
    }

    protected void OnFilterChanged(object sender, FilterChangedEventArgs e)
    {
        Debug.WriteLine($"[CompletionResults.aspx] OnFilterChanged(e={{FilterID={e.FilterID}; NewValue={e.NewValue} NewText={e.NewText}}})");

     switch(e.FilterID)
        {
            case "Enabled":
                Filter.UserEnabledAsChar = e.NewValue;
                break;

            case "Group":
                if (e.NewValueAsInt == null)
                    Filter.UserGroup.Reset();
                else
                    Filter.UserGroup.Set((int)e.NewValueAsInt, e.NewText);
                break;

            case "Division":
                if (e.NewValueAsInt == null)
                    Filter.UserDivision.Reset();
                else
                    Filter.UserDivision.Set((int)e.NewValueAsInt, e.NewText);
                break;

            case "BusinessUnit":
                if (e.NewValueAsInt == null)
                    Filter.UserBusinessUnit.Reset();
                else
                    Filter.UserBusinessUnit.Set((int)e.NewValueAsInt, e.NewText);
                break;

            case "Location":
                if (e.NewValueAsInt == null)
                    Filter.UserLocation.Reset();
                else
                    Filter.UserLocation.Set((int)e.NewValueAsInt, e.NewText);
                break;

            default:
                return;
        }

        // Update Selection Text
        BindSelectionText();

        // Update the Grid
        BindGrid();
    }

    /// <summary>
    /// User has selected a new Page number from the UserGrid
    /// </summary>
    protected void OnPageChanged(object sender, EventArgs args)
    {
        Filter.ShowAllRows = false;
        Filter.PageIndex = UserGrid.PageIndex;
        BindGrid();
    }

    protected void OnAction(object sender, ToolbarActionClickedEventArgs args)
    {
        if (args.ActionValue == "email")
            OnEmail();
    }

FilterBarBindHelper.cs

public class FilterBarBindHelper
{
    private readonly FilterBar _filterBar;
    private readonly OrganisationProperties _orgProps;

    public FilterBarBindHelper(FilterBar filterBar)
    {
        if (filterBar == null)
            throw new ArgumentNullException(nameof(filterBar));

        _filterBar = filterBar;
        _orgProps = ObjectCache.GetOrganisationProperties();
    }

    /// <summary>
    /// Binds Group list data to Filter, optionally creating the Filter if it doesn't exist
    /// </summary>
    /// <param name="selectedID">ID of currently selected Group to filter by (0 or null if none)</param>
    /// <param name="createFilter">Create the Filter if not found</param>
    public void AutoBindGroup(int? selectedID, bool createFilter = true)
    {
        // All Organisations have Groups.
        // Only populate if a FilterBar Filter with ID="Groups" can be found or if createFilter = true
        var f = _filterBar.GetFilterByID("Group");
        if (f == null)
            if (createFilter)
                f = CreateFilter("Group", "Group");
            else
                return;

        // Populate Filter list with items
        var src = GroupCache.Get();
        f.Items.Clear();
        f.Items.Add(Any());
        f.Items.AddRange(src.Select(s => new ListItem() { Value = s.StringID, Text = s.Name }).ToArray());

        // Assign localised name
        f.Label = _orgProps.GroupNm;

        // Select
        if((selectedID ?? 0) != 0)
            f.SelectedValue = selectedID.Value.ToString();

        _filterBar.RefreshFilter(f);
    }

    /// <summary>
    /// Create a FilterBar Filter and add it to the FilterBar
    /// </summary>
    /// <param name="filterID">ID of filter to add</param>
    /// <param name="label">Filter's label</param>
    /// <param name="type">Filter's type</param>
    /// <returns>New Filter</returns>
    private Filter CreateFilter(string filterID, string label, FilterType type = FilterType.DropDownList)
    {
        var f = new Filter() { ID = filterID, Type = type, Label = label };
        _filterBar.Filters.Add(f);
        return f;
    }

    private ListItem Any()
    {
        return new ListItem("Any", "X");
    }
}

Toolbar.cs

[
AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal),
DefaultProperty("Items"),
ParseChildren(true, "Items"),
ToolboxData("<{0}:Toolbar runat=server />"),
Designer(typeof(ToolbarDesigner))
]
public class Toolbar : CompositeControl
{
    private string _preText = "Actions: ";
    private bool _showRight = true;
    private readonly List<ToolbarItem> _list = new List<ToolbarItem>();

    public Toolbar()
    {
        PreText = "Actions: ";
        ObjectNameSingle = "Item";
        ObjectNamePlural = "Items";
        ShowRight = true;
    }

    protected override HtmlTextWriterTag TagKey { get { return HtmlTextWriterTag.Div; } }

    [
    Category("Behavior"),
    Description("The Item collection"),
    DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
    Editor(typeof(ToolbarCollectionEditor), typeof(UITypeEditor)),
    PersistenceMode(PersistenceMode.InnerDefaultProperty)
    ]
    public List<ToolbarItem> Items
    {
        get { return _list; }
    }

    //various properties (snip)

    protected override void RenderContents(HtmlTextWriter writer)
    {
        if(_leftSide != null)
            _leftSide.RenderControl(writer);
        if(_rightSide != null)
            _rightSide.RenderControl(writer);

        if(_leftSide == null && _rightSide == null && DesignMode)
            writer.Write("No Toolbar Items have been set up in designer");
    }   

    public void RebuildChildControls()
    {
        // Indicate that the child controls need rebuilding
        // Ref: http://yourdotnetdesignteam.blogspot.co.uk/2008/09/life-cycle-of-aspnet-controls_28.html "Composite Controls" section:
        //      "Note 1: When the Composite Control is displayed normally, 'CreateChildControls' is called AFTER the 'Load' method.
        //       However, when a post back event occurs, 'CreateChildControls' is called AFTER the 'Init' method. 
        //       This certainly makes the 'CreateChildControls' method an "interesting" aspect of the Life Cycle."
        // So on postback, the calling method should call RebuildChildControls() after repopulating/modifying Filter Items
        ChildControlsCreated = false;
        //RecreateChildControls(); this will happen in due course anyway
    }

    // Controls in Composite Control
    private ToolbarActionContainer _leftSide;
    private WebControl _rightSide;
    private ToolbarActionItem _liPreText;
    private Literal _litPreText;
    private HtmlGenericControl _spanRowCount;
    private HtmlGenericControl _spanPageCount;
    private DropDownList _ddlPage;
    private Literal _litPageCount;

    protected override void CreateChildControls()
    {
        Controls.Clear();

        _leftSide = new ToolbarActionContainer();   // UL
        _rightSide = new WebControl(HtmlTextWriterTag.Div);

        _liPreText = new ToolbarActionItem(ToolbarActionType.PreText);
        _litPreText = new Literal() { Text = "Actions: " };

        // Create the Toolbar Action Items
        var actionItems = new List<ToolbarActionItem>(_list.Count);
        foreach (var item in _list)
        {
            if (item.Visible)
            {
                var li = CreateToolbarActionItemControls(item);
                actionItems.Add(li);
            }
        }

        _spanRowCount = new HtmlGenericControl("span");  // "NNN entitie(s) found";
        _spanPageCount = new HtmlGenericControl("span");  // "Page [DDL] of [LIT]";
        _ddlPage = new DropDownList() { ID = "PageDDL", AutoPostBack = true, EnableViewState = false };
        _litPageCount = new Literal();


        _spanPageCount.Controls.Add(new Literal() { Text = "Page " });
        _spanPageCount.Controls.Add(_ddlPage);
        _spanPageCount.Controls.Add(new Literal() { Text = " of " });
        _spanPageCount.Controls.Add(_litPageCount);

        _liPreText.Controls.Add(_litPreText);

        _leftSide.Controls.Add(_liPreText);
        foreach(var item in actionItems)
            _leftSide.Controls.Add(item);

        _rightSide.Controls.Add(_spanRowCount);
        _rightSide.Controls.Add(_spanPageCount);
        Controls.Add(_leftSide);
        Controls.Add(_rightSide);

        _ddlPage.SelectedIndexChanged += PageDDL_SelectedIndexChanged;

        base.CreateChildControls();
        ChildControlsCreated = true;

        UpdateRowCountText();   // Assigns the RowCount text to the span control _spanPageCount
        UpdatePageCountText();  // The Y in "Page X of Y"
        ApplyStandardClassNames();
        CreatePageDDLItems();   // Populates Items in PageDDL (if required)
        AssignPageDDLSelectedValue(); // Assigns the current PageDDL value (if required)
    }   

    protected virtual ToolbarActionItem CreateToolbarActionItemControls(ToolbarItem item)
    {
        // Create List Item and add CssClass if required
        var li = CreateToolbarActionItem(ToolbarActionType.Action);
        if (item.HasCssClass)
            li.CssClass = item.CssClass;

        if (item.TextOnly)
        {
            // Text Only Action Items are added as literal text
            li.Controls.Add(new Literal() { Text = item.Text });
        }
        else
        {
            var btn = new LinkButton() { Text = item.Text, ToolTip = item.ToolTip, CssClass = item.CssClass };

            if (item.HasURLLink)
                btn.Attributes.Add("href", item.URLLink);
            else
            {
                btn.Click += LinkButton_Clicked;
                _map.Add(btn, item);    // used if posting back
        //      btn.Attributes.Add("href", "#");

        //      var js = MakeButtonJavaScript(item);
        //      if (js != string.Empty)
        //          btn.Attributes.Add("onclick", "javascript:" + js);
                if(!string.IsNullOrEmpty(item.PrePostbackJSFunction))
                    btn.OnClientClick = $"return {item.PrePostbackJSFunction}(this);";

            }
            li.Controls.Add(btn);
        }

        return li;
    }       

    protected virtual ToolbarActionItem CreateToolbarActionItem(ToolbarActionType type)
    {
        return new ToolbarActionItem(type);
    }

    private void CreatePageDDLItems()
    {
        // No DDL control created yet?
        if (!ChildControlsCreated)
            return;

        var pageCount = PageCount;

        // Current count is already correct?
        if (pageCount == _ddlPage.Items.Count - 1) // -1 = "all"
            return;

        _ddlPage.Items.Clear();
        _spanPageCount.Visible = (pageCount > 1);   // Show this section only if multipage

        // Not multi page?
        if (pageCount <= 1)
            return;

        var li = new ListItem("All", "all");
        _ddlPage.Items.Add(li);

        for (var i = 0; i < pageCount; i++)
        {
            li = new ListItem((i + 1).ToString());
            _ddlPage.Items.Add(li);
        }

        // AssignPageDDLSelectedValue() is already called whenever CreatePageDDLItems() is called!
        //AssignPageDDLSelectedValue();
    }

    private void AssignPageDDLSelectedValue()
    {
        if (!ChildControlsCreated)
            return;

        if (ShowAllPages)
            _ddlPage.SelectedValue = "all";
        else
            _ddlPage.SelectedValue = CurrentPage.ToString();
    }

    private void LinkButton_Clicked(object sender, EventArgs e)
    {
        System.Diagnostics.Debug.Assert(sender is LinkButton);
        var button = sender as LinkButton;
        var item = _map[button];

        // Raise event with item's value
        OnActionButtonClicked(item.Value);
    }

    private void PageDDL_SelectedIndexChanged(object sender, System.EventArgs e)
    {
        System.Diagnostics.Debug.Assert(sender == _ddlPage);
        var v = _ddlPage.SelectedValue;
        var newShowAllPages = (v == "all");
        var newPage = newShowAllPages ? 0 : int.Parse(v);

        // No Change?
        if (newShowAllPages == ShowAllPages &&
            (!newShowAllPages && (newPage == CurrentPage)))
            return;

        // Assign and raise event
        ShowAllPages = newShowAllPages;
        CurrentPage = newPage;
        OnPageChanged(newShowAllPages, newPage);
    }

    private void OnActionButtonClicked(string id)
    {
        var  evt = ActionClicked;

        // check there are subscribers, and trigger if necessary
        if (evt != null)
          evt(this, new ToolbarActionClickedEventArgs(id));
    }

    private void OnPageChanged(bool showAll, int newPageNumber)
    {
        var  evt = PageChanged;

        // check there are subscribers, and trigger if necessary
        if (evt != null)
          evt(this, new ToolbarPageChangedEventArgs(showAll, newPageNumber));
    }
}

public class ToolbarPageChangedEventArgs : EventArgs
{
    public bool ShowAllPages { get; }
    public int NewPageNumber { get; }

    internal ToolbarPageChangedEventArgs(bool showAllPages, int newPageNumber)
    {
        ShowAllPages = showAllPages;
        NewPageNumber = newPageNumber;
    }
}

public class ToolbarActionClickedEventArgs : EventArgs
{
    public string ActionValue { get; }

    internal ToolbarActionClickedEventArgs(string value)
    {
        ActionValue = value;
    }
}

public delegate void ToolbarPageChangedEventHandler(object sender, ToolbarPageChangedEventArgs args);
public delegate void ToolbarActionClickedEventHandler(object sender, ToolbarActionClickedEventArgs args);

ToolbarItem.cs

[TypeConverter(typeof(ExpandableObjectConverter))]
public class ToolbarItem
{
    public ToolbarItem() : this(string.Empty, string.Empty, string.Empty, string.Empty)
    {
    }

    public ToolbarItem(string text, string value, string jslink, string urllink)
    {
        Text = text;
        Value = value;
        JSLink = jslink;
        URLLink = urllink;
        CssClass = string.Empty;
        ToolTip = string.Empty;
        PrePostbackJSFunction = string.Empty;
        Visible = true;
    }

    .... snip ...
}

public enum ToolbarActionType
{
    None = 0,
    PreText = 1,
    Action = 2,
}

0 个答案:

没有答案