Created
July 24, 2023 18:20
-
-
Save CamelCaseName/792e9b782df5b7abfb92727b36596464 to your computer and use it in GitHub Desktop.
c# WinForms CheckListBox with 3 different colors and no double click!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Drawing; | |
using System.Windows.Forms; | |
namespace CustomComponents | |
{ | |
[SupportedOSPlatform("Windows")] | |
public static class Winutils | |
{ | |
public const int WM_LBUTTONDOWN = 0x201; | |
public const int WM_LBUTTONDBLCLK = 0x203; | |
public const int WM_PAINT = 0x00f; | |
public const int WM_ERASEBKGND = 0x00e; | |
public const int WM_MOUSEMOVE = 0x200; | |
} | |
/// <summary> | |
/// Borrowed from https://stackoverflow.com/questions/2130934/how-change-the-color-of-selecteditem-in-checkedlistbox-in-windowsforms | |
/// Creates a coloured Rectangle in each element, depending on checked state. | |
/// </summary> | |
public class ColoredCheckedListBox : CheckedListBox | |
{ | |
/// <summary> | |
/// List containing all indices that are part of the search result | |
/// </summary> | |
public List<int> ColorList1 = new(); | |
/// <summary> | |
/// list containing all indices that are duplicates fo the english string | |
/// </summary> | |
public List<string> ColorList2 = new(); | |
/// <summary> | |
/// Use double buffering, removes flicker | |
/// </summary> | |
protected new bool DoubleBuffered = true; | |
/// <summary> | |
/// A Override for the default OnDrawItem which replaces the background with a coloured rectangle given a List of indices | |
/// </summary> | |
/// <param name="e">The DrawItemEventArgs which will be manipulated</param> | |
protected override void OnDrawItem(DrawItemEventArgs e) | |
{ | |
var e2 = | |
new DrawItemEventArgs | |
( | |
e.Graphics, | |
e.Font, | |
e.Bounds, | |
e.Index, | |
e.State, | |
e.ForeColor, //colour yellow if it is part of the search, else colour normally | |
e.Index > -1 ? | |
ColorList1.Contains(e.Index) ? | |
Color.DarkOrange : | |
ColorList2.Contains(Items[e.Index].ToString() ?? string.Empty) ? | |
Color.FromArgb(130, 80, 130) : | |
CheckedIndices.Contains(e.Index) ? | |
Color.FromArgb(80, 130, 80) : | |
Color.FromArgb(130, 80, 80) | |
: | |
e.BackColor | |
); | |
base.OnDrawItem(e2); | |
} | |
/// <summary> | |
/// Hack to get exactly the behaviour we want (https://stackoverflow.com/a/3897126) adapted and expanded. | |
/// Only allows double clicks on the far left of the control, or only single clicks elsewhere. | |
/// </summary> | |
/// <param name="m"> The windows Message to be used</param> | |
protected override void WndProc(ref Message m) | |
{ | |
// Filter WM_LBUTTONDBLCLK and MW_LBUTTONDOWN | |
if (m.Msg != Winutils.WM_LBUTTONDBLCLK && m.Msg != Winutils.WM_LBUTTONDOWN) | |
{ | |
base.WndProc(ref m); | |
} | |
else if (m.Msg == Winutils.WM_LBUTTONDOWN) //our own handle | |
{ | |
//get mouse cursor position from message https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttondown | |
byte[] bytes = BitConverter.GetBytes(m.LParam.ToInt64()); | |
short x = BitConverter.ToInt16(bytes, 0); | |
short y = BitConverter.ToInt16(bytes, 2); | |
//create point from cursor pos. low word is x, high word is y | |
var CursorPosition = new Point(x, y); | |
//if a new item would be selected, we can do that. or if the cursor is on one of the check marks. but else we do nothing | |
if (SelectedIndex != IndexFromPoint(CursorPosition) || x < 14) | |
{ | |
base.WndProc(ref m); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment