Search code examples
c#winformscomboboxuser-controlsdesigner

Custom ComboBox: prevent designer from adding to Items


I have a custom combobox control that is supposed to show a list of webcams available.

The code is fairly tiny.

using System;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using DirectShowLib;

namespace CameraSelectionCB
{
    public partial class CameraComboBox : ComboBox
    {
        protected BindingList<string> Names;
        protected DsDevice[] Devices;
        public CameraComboBox()
        {
            InitializeComponent();
            Devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
            Names = new BindingList<string>(Devices.Select(d => d.Name).ToList());
            this.DataSource = Names;
            this.DropDownStyle = ComboBoxStyle.DropDownList;
        }
    }
}

However, I ran into a couple of bugs. First, whenever I place an instance of this combobox, designer generates the following code:

this.cameraComboBox1.DataSource = ((object)(resources.GetObject("cameraComboBox1.DataSource")));
this.cameraComboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cameraComboBox1.Items.AddRange(new object[] {
        "HP Webcam"});

Which results in an exception during runtime, since Items should not be modified when DataSource is set. This happens even if I don't touch Items property in the designer.

"HP Webcam" is the only camera present on my computer at the time.

How can I suppress this behaviour?


Solution

  • When you drop your control on a form the constructor code and any loading code will run. Any code in there that changes a property value will be executed in designtime and therefore will be written in the designer.cs of the form you dropped your control on.
    When programming controls you should always keep that in mind.

    I solved this by adding a property that I can use to check if the code executed in designtime or runtime.

    protected bool IsInDesignMode
    {
        get { return DesignMode || LicenseManager.UsageMode == LicenseUsageMode.Designtime; }
    }
    
    protected BindingList<string> Names;
    protected DsDevice[] Devices;
    public CameraComboBox()
    {
        InitializeComponent();
    
        if (InDesignMode == false)
        {
            // only do this at runtime, never at designtime...
            Devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
            Names = new BindingList<string>(Devices.Select(d => d.Name).ToList());
            this.DataSource = Names;
        }
        this.DropDownStyle = ComboBoxStyle.DropDownList;
    }
    

    Now the binding will only happen at runtime

    Dont forget to remove the generated code in the Designer.cs file when you try this