Search code examples
c#winformslistboxdevexpress

C# winform ListBox Unselect by Item


I have a problem with click cancel

using System.Windows.Forms;

namespace WindowsFormsApp2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            lbItems.Items.Add("1");
            lbItems.Items.Add("2");
            lbItems.Items.Add("3");
            lbItems.Items.Add("4");
            lbItems.Items.Add("5");
            lbItems.Items.Add("6");

            lbItems.MouseDown += LbItems_MouseDown;
            lbItems.SelectedValueChanging // not found
        }

        private void LbItems_MouseDown(object sender, MouseEventArgs e)
        {
          // I want to cancel click to the item in ListBox
        }
    }
}

I thought there was a SelectedValueChanging event that allows you to cancel the selection of an element and stay on the old one. Maybe replace the ListBox with another control from DevEXpress? But which one?


Solution

  • An alternative to using a third-party control would be to make your own extended ListBoxEx class that implements SelectedIndexChanging (make sure to swap it out manually in the MainForm.Designer.cs file.)

    class ListBoxEx : ListBox
    {
        private const int WM_LBUTTONDOWN = 0x0201;
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_LBUTTONDOWN)
            {
                var e = new SelectedValueChangingEventArgs(IndexFromPoint(new Point((int)m.LParam & 0xFFFF, (int)m.LParam >> 16)));
                SelectedValueChanging?.Invoke(this, e);
                if (e.Cancel) return;
            }
            base.WndProc(ref m);
        }
    
        public event EventHandler<SelectedValueChangingEventArgs>? SelectedValueChanging;
    }
    
    class SelectedValueChangingEventArgs : CancelEventArgs
    {
        public SelectedValueChangingEventArgs(int index) => Index = index;
        public int Index { get; }
    }
    

    Here's a minimal example of being able to select an item programmatically (i.e. by making selection indirectly using the NumericUpDownControl) while disallowing mouse selection. This might not be "exactly" what you're trying to achieve, but the point is to simply demonstrate having control of whether the mouse event causes selection or not.

    minimal example

    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            lbItems.Items.Add("1");
            lbItems.Items.Add("2");
            lbItems.Items.Add("3");
            lbItems.Items.Add("4");
            lbItems.Items.Add("5");
            lbItems.Items.Add("6");
    
            lbItems.SelectedValueChanging += LbItems_SelectedValueChanging;
            numericUpDown.ValueChanged += NumericUpDown_ValueChanged;
        }
        private void LbItems_SelectedValueChanging(object? sender, SelectedValueChangingEventArgs e)
        {
            e.Cancel = !_allowChange;
        }
        private void NumericUpDown_ValueChanged(object? sender, EventArgs e)
        {
            lbItems.SelectedIndex = lbItems.FindStringExact(numericUpDown.Value.ToString());
        }
        bool _allowChange = false; // Set true to allow mouse selection under certain conditions.
    }