简体   繁体   中英

Subclass of combo box works in code but not in designer vs2017

I have visual studio 2017, creating custom controls like a custom combo box that extends combo box fails loading from the designer tool box. It works fine using code to generate the custom combo box, add it as a control, and move on...The default auto complete in combo box isn't adequate so I used another one to search substrings and be more flexible in auto suggest/append mode.

If I load another project that does the same thing it works fine, so I am not sure what the issue is for me. I have tried both 64/32 bit, re-wrote the control a dozen times, clean and re-build, it shows in the toolbox, confirm it works fine using code to build and add the control.

Why won't VS2017 let me drag it from the tool box onto my form, it always gives the error: "Failed to load toolbox item 'SuggestComboBox'. It will be removed from the toolbox.

I've tried many other posts solutions and none of them seem to work. How is it possible the solution compiles, code adds the control and works fine, but the toolbox/designer keep failing when I use the GUI? This is problematic because I can't use the designer, but it's impossible to see what could be wrong.

Any ideas? <-- I also ran a working sample project off the internet, copied the file that does the same thing (subclass combo box) into my project and it fails too...is this maybe a vs2017 bug or some kind of step I missed setting this up?

using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Linq.Expressions;
using System.Windows.Forms;

//@note DataItem is a custom class stored in combo box to have key/value pairs
namespace System.Windows.Forms
{
[ToolboxItem(true)]
partial class SuggestComboBox : ComboBox
{
    #region fields and properties

    private readonly ListBox _suggLb = new ListBox { Visible = false, TabStop = false };
    private readonly BindingList<DataItem> _suggBindingList = new BindingList<DataItem>();

    public int SuggestBoxHeight
    {
        get { return _suggLb.Height; }
        set { if (value > 0) _suggLb.Height = value; }
    }
    #endregion

    /// <summary>
    /// ctor
    /// </summary>
    public SuggestComboBox() 
    {
        _suggLb.DataSource = _suggBindingList;
        _suggLb.Click += SuggLbOnClick;

        ParentChanged += OnParentChanged;
    }

    /// <summary>
    /// the magic happens here ;-)
    /// </summary>
    /// <param name="e"></param>
    protected override void OnTextChanged(EventArgs e)
    {
        base.OnTextChanged(e);

        if (!Focused) return;

        _suggBindingList.Clear();
        _suggBindingList.RaiseListChangedEvents = false;

        //do a better comparison then just 'starts with'
        List<DataItem> results = new List<DataItem>();
        foreach(object item in Items)
        {
            //data item or regular
            if( item.ToString().ToLower().Contains( Text.Trim().ToLower()))
            {
                results.Add((DataItem)item);
            }                    
        }

        //add to suggestion box (@todo may need data items...)
        foreach (DataItem result in results)
        {
            _suggBindingList.Add(result);
        }

        _suggBindingList.RaiseListChangedEvents = true;
        _suggBindingList.ResetBindings();

        _suggLb.Visible = _suggBindingList.Any();

        if (_suggBindingList.Count == 1 &&
                    _suggBindingList.Single().ToString().Length == Text.Trim().Length)
        {
            Text = _suggBindingList.Single().ToString();
            Select(0, Text.Length);
            _suggLb.Visible = false;
        }

        //handle zindex issue of suggestion box
        this.BringToFront();
        _suggLb.BringToFront();

    }

    #region size and position of suggest box

    /// <summary>
    /// suggest-ListBox is added to parent control
    /// (in ctor parent isn't already assigned)
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OnParentChanged(object sender, EventArgs e)
    {
        Parent.Controls.Add(_suggLb);
        Parent.Controls.SetChildIndex(_suggLb, 0);
        _suggLb.Top = Top + Height - 3;
        _suggLb.Left = Left + 3;
        _suggLb.Width = Width - 20;
        _suggLb.Font = new Font("Segoe UI", 9);
    }

    protected override void OnLocationChanged(EventArgs e)
    {
        base.OnLocationChanged(e);
        _suggLb.Top = Top + Height - 3;
        _suggLb.Left = Left + 3;
    }

    protected override void OnSizeChanged(EventArgs e)
    {
        base.OnSizeChanged(e);
        _suggLb.Width = Width - 20;
    }

    #endregion

    #region visibility of suggest box

    protected override void OnLostFocus(EventArgs e)
    {
        // _suggLb can only getting focused by clicking (because TabStop is off)
        // --> click-eventhandler 'SuggLbOnClick' is called
        if (!_suggLb.Focused)
            HideSuggBox();
        base.OnLostFocus(e);
    }

    private void SuggLbOnClick(object sender, EventArgs eventArgs)
    {
        Text = _suggLb.Text;
        Focus();
    }

    private void HideSuggBox()
    {
        _suggLb.Visible = false;
    }

    protected override void OnDropDown(EventArgs e)
    {
        HideSuggBox();
        base.OnDropDown(e);
    }

    #endregion

    #region keystroke events

    /// <summary>
    /// if the suggest-ListBox is visible some keystrokes
    /// should behave in a custom way
    /// </summary>
    /// <param name="e"></param>
    protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
    {
        if (!_suggLb.Visible)
        {
            base.OnPreviewKeyDown(e);
            return;
        }

        switch (e.KeyCode)
        {
            case Keys.Down:
                if (_suggLb.SelectedIndex < _suggBindingList.Count - 1)
                    _suggLb.SelectedIndex++;
                return;
            case Keys.Up:
                if (_suggLb.SelectedIndex > 0)
                    _suggLb.SelectedIndex--;
                return;
            case Keys.Enter:
                Text = _suggLb.Text;
                Select(0, Text.Length);
                _suggLb.Visible = false;
                return;
            case Keys.Escape:
                HideSuggBox();
                return;
        }

        base.OnPreviewKeyDown(e);
    }

    private static readonly Keys[] KeysToHandle = new[] { Keys.Down, Keys.Up, Keys.Enter, Keys.Escape };
    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        // the keysstrokes of our interest should not be processed be base class:
        if (_suggLb.Visible && KeysToHandle.Contains(keyData))
            return true;
        return base.ProcessCmdKey(ref msg, keyData);
    }
    #endregion
}
}

Thanks Reza Aghaei, your suggestion along with something I learned as well is x64/x86 builds are a problem for user controls. You either need a separate project for your user controls, build them with x86 and load them into your project (always using 32 bit) but since mine was the same project and I had x64 targeted the designer croacked.

Since everything else still ran fine from code, to executable, to designer forms that already had my control/user control code included it was nearly impossible to figure out what's wrong.

Build for 32 bit and delete EVERYTHING then re-compile. Problem solved, only took a handful of hours :S. VS2017.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM