0

I'm trying to create my own drop down list to use on a web page and I just can't get it to work the way I need want.

In it's most basic form I can create a class, inherit from System.Web.UI.WebControls.DropDownList, register it on the page, add the markup and it will at least show a control on the page:

My Class:

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Text
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls

Namespace CustomDropdown
    <DefaultProperty("Text"), ToolboxData("<{0}:DropDownListWithAttributes runat=server></{0}:DropDownListWithAttributes>")>
    Public Class DropDownListWithAttributes
        Inherits System.Web.UI.WebControls.DropDownList

    End Class
End Namespace

Page Register:

<%@ Register TagPrefix="myControls" Namespace="CustomDropdown" %>

Markup:

<myControls:DropDownListWithAttributes ID="ddlMyTestCustomDDL" runat="server"></myControls:DropDownListWithAttributes>

enter image description here

But that's it. That's as far as I can get. I cannot access it from code behind at all. It's like it doesn't exist. I need to be able to fill it with items, trigger events, etc... All the things a normal drop down list would be able to do.

The markup seems to think it can have events: enter image description here

But when I add one the designer breaks: enter image description here

So I do not get normal ddl functionality, I'm unable to access the control from code behind, adding any kind of event breaks stuff...I'm at a loss on how to make this work :(

5
  • Have you tried to clean and re compile your project after creating this Custom Control? Commented Oct 17, 2020 at 6:14
  • Yes. I Build/Rebuild/Clean and Rebuild. I guess I just don't understand the whole process of creating these types of server controls and what they are and aren't capable of...sigh Commented Oct 17, 2020 at 6:32
  • 1
    Is the custom control in a separate project? If so, it might need <Assembly: TagPrefix("CustomDropdown", "myControls")> before the Namespace CustomDropdown declaration. It would also need Imports System.Security.Permissions and the attributes AspNetHostingPermission(SecurityAction.Demand, Level:=AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level:=AspNetHostingPermissionLevel.Minimal) in addition to the ToolboxData attribute. Commented Oct 17, 2020 at 13:45
  • I had it in the same project as my web pages. But I figured I'd give it a try and move it to it's own project. I added the assembly and security like Andrew suggested and that fixed it from breaking but it still wasn't accessible in the code behind. I cleaned, rebuilt a dozen times but no luck. So I started removing stuff from Andrew's suggestion and adding it back...all the while cleaning and rebuilding. All of a sudden I got a good reference in the designer file and it's not accessible in code behind. Commented Oct 18, 2020 at 1:45
  • You say it wasn't accessible in your codebehind but are you able to add a "OnSelectedIndexChanged" even handler in the markup, and have the codebehind code generated for you? Commented Oct 19, 2020 at 4:26

1 Answer 1

1

Well, with Andrew's suggestion and moving it to it's own project, it seems to be working now. Here's what it looks like:

C# Class Library: DropDownWithAttributes with a single .cs file: DropDownListWithAttributes.cs

using System;
using System.ComponentModel;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

[assembly: TagPrefix("DropDownWithAttributes", "myControl")]
namespace DropDownWithAttributes
{
    [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [DefaultProperty("Text")]
    [ToolboxData("<{0}:ServerControl1 runat=server></{0}:ServerControl1>")]
    public class DropDownListWithAttributes : DropDownList
    {
        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        protected override object SaveViewState()
        {
            // create object array for Item count + 1
            object[] allStates = new object[this.Items.Count + 1];

            // the +1 is to hold the base info
            object baseState = base.SaveViewState();
            allStates[0] = baseState;

            Int32 i = 1;
            // now loop through and save each Style attribute for the List
            foreach (ListItem li in this.Items)
            {
                Int32 j = 0;
                string[][] attributes = new string[li.Attributes.Count][];
                foreach (string attribute in li.Attributes.Keys)
                {
                    attributes[j++] = new string[] { attribute, li.Attributes[attribute] };
                }
                allStates[i++] = attributes;
            }
            return allStates;
        }

        protected override void LoadViewState(object savedState)
        {
            if (savedState != null)
            {
                object[] myState = (object[])savedState;

                // restore base first
                if (myState[0] != null)
                    base.LoadViewState(myState[0]);

                Int32 i = 1;
                foreach (ListItem li in this.Items)
                {
                    // loop through and restore each style attribute
                    foreach (string[] attribute in (string[][])myState[i++])
                    {
                        li.Attributes[attribute[0]] = attribute[1];
                    }
                }
            }
        }
    }
}

I added the project to my solution and added a reference to DropDownWithAttributes from my web project:

enter image description here

Registered on my page:

<%@ Register TagPrefix="myControl" Namespace="DropDownWithAttributes" Assembly="DropDownWithAttributes" %>

Added the control on the page:

<myControl:DropDownListWithAttributes ID="ddlWithAttribute" runat="server" OnSelectedIndexChanged="ddlWithAttribute_SelectedIndexChanged"></myControl:DropDownListWithAttributes>

That's where things broke before....it's looking better now:

 '''<summary>
    '''ddlWithAttribute control.
    '''</summary>
    '''<remarks>
    '''Auto-generated field.
    '''To modify move field declaration from designer file to code-behind file.
    '''</remarks>
    Protected WithEvents ddlWithAttribute As Global.DropDownWithAttributes.DropDownListWithAttributes

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.