Stop ComboBox Autocomplete feature from happening - c#

I want to stop any trace of autocomplete from happening with my ComboBox.
Is it even possible to stop the Windows Form ComboBox object from auto-completing? Right now when I type the first three characters of something and click another ComboBox to type in the new field, the first ComboBox does not change and keeps those three typed letters. However, if I resize the form then it tries to autocomplete the ComboBox (if there is a matching record that STARTS with the text I typed). Also, the ComboBox's this happens to are Anchored: Left, Right. I have a bad feeling the only way to stop this behavior is to subclass the ComboBox and do something in the resize event or whatever... :/
Here are the settings for what I think are the only properties dealing with autocomplete...
Note: The "Collection" in the AutoCompleteCustomSource has an empty list when I click the three dots to the right.
To Reproduce This Issue:
Create a form and place a standard ComboBox control on it. Then place another one right below it. You will do nothing to the second ComboBox (only used to have a second control to tab to in the example).
In the ComboBox properties find the Items collection and add the following...
testing123
blah321
foobar
In the ComboBox properties find the Anchor property and change to Left, Right.
Run the application.
Test 1: In the ComboBox type bl and press the tab key to get to the next ComboBox. You will see no change.
Test 2: In the ComboBox type bl and resize the form by dragging the right side to make it a little wider. You will see the ComboBox has now been auto filled with blah321.

Found what I was looking for over at https://stackoverflow.com/a/25696213/1039753!
I guess there is no way to stop it without subclassing or making an extension class/method to do it. What I was looking for was "auto complete" when I guess I should have been looking for "auto select". Knowing what to search for is key! This code works great, to use it you would do something like...
ComboBoxAutoSelectEx.AutoSelectOff(ComboBox1);
I could not see any performance hit either. It just looks like magic. I have slightly altered the code from that answer to add the required structure needed.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Opulos.Core.Win32;
namespace MyAppsNamespace {
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
// Extension class to disable the auto-select behavior when a combobox is in DropDown mode.
public static class ComboBoxAutoSelectEx {
public static void AutoSelectOff(this ComboBox combo) {
Data.Register(combo);
}
public static void AutoSelectOn(this ComboBox combo) {
Data data = null;
if (Data.dict.TryGetValue(combo, out data)) {
data.Dispose();
Data.dict.Remove(combo);
}
}
private class Data {
// keep a reference to the native windows so they don't get disposed
internal static Dictionary<ComboBox, Data> dict = new Dictionary<ComboBox, Data>();
// a ComboBox consists of 3 windows (combobox handle, text edit handle and dropdown list handle)
ComboBox combo;
NW nwList = null; // handle to the combobox's dropdown list
NW2 nwEdit = null; // handle to the edit window
internal void Dispose() {
dict.Remove(this.combo);
this.nwList.ReleaseHandle();
this.nwEdit.ReleaseHandle();
}
public static void Register(ComboBox combo) {
if (dict.ContainsKey(combo))
return; // already registered
Data data = new Data() { combo = combo };
Action assign = () => {
if (dict.ContainsKey(combo))
return; // already assigned
COMBOBOXINFO info = COMBOBOXINFO.GetInfo(combo); // new COMBOBOXINFO();
//info.cbSize = Marshal.SizeOf(info);
//COMBOBOXINFO2.SendMessageCb(combo.Handle, 0x164, IntPtr.Zero, out info);
dict[combo] = data;
data.nwList = new NW(combo, info.hwndList);
data.nwEdit = new NW2(info.hwndEdit);
};
if (!combo.IsHandleCreated)
combo.HandleCreated += delegate { assign(); };
else
assign();
combo.HandleDestroyed += delegate {
data.Dispose();
};
}
}
private class NW : NativeWindow {
ComboBox combo;
public NW(ComboBox combo, IntPtr handle) {
this.combo = combo;
AssignHandle(handle);
}
private const int LB_FINDSTRING = 0x018F;
private const int LB_FINDSTRINGEXACT = 0x01A2;
protected override void WndProc(ref Message m) {
if (m.Msg == LB_FINDSTRING) {
m.Msg = LB_FINDSTRINGEXACT;
}
base.WndProc(ref m);
if (m.Msg == LB_FINDSTRINGEXACT) {
String find = Marshal.PtrToStringAuto(m.LParam);
for (int i = 0; i < combo.Items.Count; i++) {
Object item = combo.Items[i];
if (item.Equals(find)) {
m.Result = new IntPtr(i);
break;
}
}
}
}
}
private class NW2 : NativeWindow {
public NW2(IntPtr handle) {
AssignHandle(handle);
}
private const int EM_SETSEL = 0x00B1;
private const int EM_GETSEL = 0x00B0;
protected override void WndProc(ref Message m) {
if (m.Msg == EM_SETSEL) {
// if this code is not here, then the entire combobox text is selected
// which looks ugly, especially when there are multiple combo boxes.
//
// if this method returns immediately, then the caret position is set
// to (0, 0). However, it seems that calling EM_GETSEL has a side effect
// that the caret position is mostly maintained. Sometimes it slips back
// to (0, 0).
SendMessage(Handle, EM_GETSEL, IntPtr.Zero, IntPtr.Zero);
//int selStart = (sel & 0x00ff);
//int selEnd = (sel >> 16) & 0x00ff;
//Debug.WriteLine("EM_GETSEL: " + selStart + " nEnd: " + selEnd);
return;
}
base.WndProc(ref m);
}
[DllImportAttribute("user32.dll", SetLastError=true)]
private static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
}
}
[StructLayout(LayoutKind.Sequential)]
public struct COMBOBOXINFO {
public Int32 cbSize;
public RECT rcItem;
public RECT rcButton;
public int buttonState;
public IntPtr hwndCombo;
public IntPtr hwndEdit;
public IntPtr hwndList;
public static COMBOBOXINFO GetInfo(ComboBox combo) {
COMBOBOXINFO info = new COMBOBOXINFO();
info.cbSize = Marshal.SizeOf(info);
SendMessageCb(combo.Handle, 0x164, IntPtr.Zero, out info);
return info;
}
[DllImport("user32.dll", EntryPoint = "SendMessageW", CharSet = CharSet.Unicode)]
private static extern IntPtr SendMessageCb(IntPtr hWnd, int msg, IntPtr wp, out COMBOBOXINFO lp);
}
}

Related

Disable WinForms ListViewItem Tooltip for long texts

I have created ListView and added two item with long text.
when I select first item second item`s text is clipped, for example "MyIte....".
So when move mouse pointer under this item, I see toolTip with all text.
How to disable this tooltip?
Set property ListView.ShowItemToolTips = false doesn't help.
ListView shows item tooltips when receives a WM_Notify message with TTN_NEEDTEXT lparam. So to disable tooltips, you can process ListView messages and if the control received that message, neglect it.
You can inherit your ListView and override WndProc, but as another option, you can register a NativeWindow to receive your ListView messages and this way you can filter messages.
Implementation
public class ListViewToolTipHelper : NativeWindow
{
private ListView parentListView;
private const int WM_NOTIFY = 78;
private const int TTN_FIRST = -520;
private const int TTN_NEEDTEXT = (TTN_FIRST - 10);
public struct NMHDR
{
public IntPtr hwndFrom;
public IntPtr idFrom;
public Int32 code;
}
public bool TooltipEnabled { get; set; }
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_NOTIFY && !TooltipEnabled)
{
var nmHdr = (NMHDR) m.GetLParam(typeof(NMHDR));
if (nmHdr.code == TTN_NEEDTEXT)
return;
}
base.WndProc(ref m);
}
public ListViewToolTipHelper(ListView listView)
{
this.parentListView = listView;
this.AssignHandle(listView.Handle);
}
}
Usage
To disable tooltips for a ListView you can simply create an instance of above class:
ListViewToolTipHelper helper;
helper = new ListViewToolTipHelper(this.listView1);
To enable tooltips again:
helper.TooltipEnabled = true;
Another workaround
You can disable the tooltip for ListView using this workaround, but the side effect is all other tooltips in form also will be disabled this way.
ToolTip toolTip = new ToolTip();
toolTip.SetToolTip(this.listView1, "dummy text");
toolTip.Active = false;

How can I prevent a form from stealing focus while still receiving mouse clicks?

I'm attempting to create a custom AutoCompleteTextBox control in WinForms. The AutoComplete provided by the basic TextBox provides results only with (string).StartsWith as opposed to (string).Contains.
I am displaying the Auto-Complete search results in a ListBox docked in a separate Form. I can prevent the Form from stealing focus initially using via:
protected override bool ShowWithoutActivation
{
get { return true; }
}
Then, I can prevent the Form from gaining focus entirely by overriding the WndProc method via:
protected override void WndProc( ref Message m )
{
base.WndProc( ref m );
switch ( m.Msg )
{
case WM_MOUSEACTIVATE:
m.Result = ( IntPtr ) MA_NOACTIVATEANDEAT;
break;
default:
break;
}
When I do this, the ListBox contained in the Form will receive MouseMoved events, but not MouseClicked events.
Chaning MA_NOACTIVATEANDEAT to just MA_NOACTIVATE will pass the mouse events to the ListBox, but then will cause the clicks on the ListBox to steal focus from the Form the ListBox resides in - passing it to the 'floating' Form the ListBox is in.
Is there any way I can prevent the 'floating' Form from steeling focus from the 'main' Form while still getting MouseClick events within the ListBox?
Convert your floating form into a Usercontrol as below :-
Pull a ListBox on it to & hook onto Click event to simulate your scenario of Focus.
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication3
{
public partial class InactiveForm : UserControl
{
private const int WS_EX_TOOLWINDOW = 0x00000080;
private const int WS_EX_NOACTIVATE = 0x08000000;
private const int WS_EX_TOPMOST = 0x00000008;
[DllImport("user32")]
public static extern int SetParent
(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32")]
public static extern int ShowWindow
(IntPtr hWnd, int nCmdShow);
protected override CreateParams CreateParams
{
get
{
CreateParams p = base.CreateParams;
p.ExStyle |= (WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST);
p.Parent = IntPtr.Zero;
return p;
}
}
public InactiveForm()
{
InitializeComponent();
}
public new void Show()
{
if (this.Handle == IntPtr.Zero) base.CreateControl();
SetParent(base.Handle, IntPtr.Zero);
ShowWindow(base.Handle, 1);
}
private void OnListBoxClicked(object sender, EventArgs e)
{
MessageBox.Show("Clicked List Box on floating control");
}
}
}
Code in the MainForm (with a button and its click handler attached):-
This invokes the floating control with ListBox.
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
InactiveForm f = new InactiveForm();
f.Show();
}
}
}
When you show the UserControl (borderless form) as your floating form, you will notice that it wont receive focus even if you clicked (selected) any of its children. In this case, the child is a ListBox on the usercontrol.
Refer here and here.
In addtion to previous answer by Angshuman Agarwal:
If you want the main form does not deactive when the UserControl show as floating form, modify some code to your UserControl:
private Control _mControl;
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
public new void Show(Control c)
{
if (c == null) throw new ArgumentNullException();
_mControl = c;
if (this.Handle == IntPtr.Zero) base.CreateControl();
SetParent(base.Handle, IntPtr.Zero);
ShowWindow(base.Handle, 1);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x86) //WM_NCACTIVATE
{
if (m.WParam != IntPtr.Zero) //activate
{
SendMessage(_mControl.Handle, 0x86, (IntPtr)1, IntPtr.Zero);
}
this.DefWndProc(ref m);
return;
}
base.WndProc(ref m);
}
I've created something similiar and my solution is similar to what lAbstract suggests. The floatin form has an event DoReturnFocus wich the custom TextBox (the AutoCompleteTextBox control in this case) subscribes to, and simply sets focus back to itself. To prevent the main form to appear in front of the floating form I set the main form as the Owner of the floating form, as owned forms are never displayed behind their owner form..
More on Form.Owner Property

TableLayoutPanel responds very slowly to events

In my application I really needed to place a lot of controls (label, textbox, domainupdown) in a nice order. So I went ahead and used some nested TableLayoutPanel. The problem now is, this form responds very slow to most of events (resize, maximize, minimize and ...) it takes really up to 5 seconds for controls within the tables to get resized, redrawed to the new size of form.
I am putting a finger in my eye now! If this form is that slow on my home PC (i7#4GHz and a good graphic card) what it will do tommorow on the old P4 computer at work?
I even tried to use the code below but it does absoloutly nothing, if it is not slowing it down more!
private void FilterForm_ResizeBegin(object sender, EventArgs e)
{
foreach(TableLayoutPanel tlp in panelFilters.Controls)
{
if(tlp != null)
{
tlp.SuspendLayout();
}
}
}
private void FilterForm_ResizeEnd(object sender, EventArgs e)
{
foreach (TableLayoutPanel tlp in panelFilters.Controls)
{
if (tlp != null)
{
tlp.ResumeLayout();
}
}
}
Please let me know if there is a trick to make tablelayoutpanel to work faster...or if you know a better approach to lay down about hundred of controls nicely aligned.
Use this code.
public class CoTableLayoutPanel : TableLayoutPanel
{
protected override void OnCreateControl()
{
base.OnCreateControl();
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.CacheText, true);
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= NativeMethods.WS_EX_COMPOSITED;
return cp;
}
}
public void BeginUpdate()
{
NativeMethods.SendMessage(this.Handle, NativeMethods.WM_SETREDRAW, IntPtr.Zero, IntPtr.Zero);
}
public void EndUpdate()
{
NativeMethods.SendMessage(this.Handle, NativeMethods.WM_SETREDRAW, new IntPtr(1), IntPtr.Zero);
Parent.Invalidate(true);
}
}
public static class NativeMethods
{
public static int WM_SETREDRAW = 0x000B; //uint WM_SETREDRAW
public static int WS_EX_COMPOSITED = 0x02000000;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); //UInt32 Msg
}
If you create a new class derived from TableLayoutPanel and set the ControlStyles such that DoubleBuffered is true, your performance will improve dramatically.
public class MyPanel : TableLayoutPanel
{
public MyPanel()
{
this.SetStyle(ControlStyles.DoubleBuffer, true);
}
}

Is it possible to define a left-handed ComboBox (ie. scrollbar on the left) in a winforms application?

I have a WinForms application that is being used on tablet PC's with touch screens. The application is developed with Visual Studio 2008 and used version 3.5 of the .Net framework. I have had a request from a left-handed client to put the scrollbar of the ComboBoxes on the left-hand side of the dropdown area rather than the right, but I am not sure how to do this, or if it is even possible to do. Has anyone done this before or know how it can be done?
There is a solution here using Win32 API calls for modifying the ComboBox: http://www.codeguru.com/csharp/csharp/cs_controls/custom/print.php/c15261
About halfway down, below the 'Aligning ComoBox Objects' heading.
There is also a link to some sample code at the end of the page.
Example - Left scrollbar & left text
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ComboBoxMod
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmMain());
}
}
public partial class frmMain : Form
{
private ComboBoxMod.ComboBox cbTest; //this is the modified combo box
private System.Windows.Forms.Button btnToggleAlign;
private System.ComponentModel.IContainer components = null;
public frmMain()
{
this.cbTest = new ComboBoxMod.ComboBox();
this.btnToggleAlign = new Button();
InitialiseComponent();
for (int i = 0; i < 50; i++)
{
cbTest.Items.Add(i);
}
}
void btnToggleAlign_Click(object sender, EventArgs e)
{
if (this.cbTest.ScrollAlignment == ComboBox.Alignment.Right) //If Right Aligned
{
this.cbTest.ScrollAlignment = ComboBox.Alignment.Left; //Set To Left
}
else
{
this.cbTest.ScrollAlignment = ComboBox.Alignment.Right; //Set To Right
}
}
private void InitialiseComponent()
{
this.SuspendLayout();
this.cbTest.FormattingEnabled = true;
this.cbTest.Location = new System.Drawing.Point(12, 12);
this.cbTest.Name = "cbTest";
this.cbTest.Size = new System.Drawing.Size(180, 21);
this.cbTest.TabIndex = 0;
this.btnToggleAlign.Location = new System.Drawing.Point(12, 42);
this.btnToggleAlign.Name = "btnScrollAlign";
this.btnToggleAlign.Size = new System.Drawing.Size(180, 23);
this.btnToggleAlign.TabIndex = 0;
this.btnToggleAlign.Text = "Toggle Scrollbar Alignment";
this.btnToggleAlign.UseVisualStyleBackColor = true;
this.btnToggleAlign.Click += new EventHandler(btnToggleAlign_Click);
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(200, 75);
this.Controls.Add(this.cbTest);
this.Controls.Add(this.btnToggleAlign);
this.Name = "frmMain";
this.Text = "frmMain";
this.ResumeLayout(false);
}
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
}
public class ComboBox : System.Windows.Forms.ComboBox //Inherits ComboBox
{
[DllImport("user32", CharSet = CharSet.Auto)]
public extern static int GetWindowLong(IntPtr hwnd, int nIndex); //Retrieve Info About Specified Window
[DllImport("user32")]
public static extern int SetWindowLong(IntPtr hwnd, int nIndex, int dwNewLong); //Change An Attribute Of Specified Window
[DllImport("user32.dll")]
public static extern int GetComboBoxInfo(IntPtr hWnd, ref COMBOBOXINFO pcbi); //Retrieve Info About Specified Combo Box
[StructLayout(LayoutKind.Sequential)]
public struct COMBOBOXINFO //Contains ComboBox Status Info
{
public Int32 cbSize;
public RECT rcItem;
public RECT rcButton;
public ComboBoxButtonState caState;
public IntPtr hwndCombo;
public IntPtr hwndEdit;
public IntPtr hwndList;
}
[StructLayout(LayoutKind.Sequential)] //Describes Width, Height, And Location Of A Rectangle
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
public enum ComboBoxButtonState //Determines Current State Of ComboBox
{
STATE_SYSTEM_NONE = 0,
STATE_SYSTEM_INVISIBLE = 0x00008000,
STATE_SYSTEM_PRESSED = 0x00000008
}
/// <summary>
/// Alignment Enum For Left & Right
/// </summary>
public enum Alignment
{
Left = 0,
Right = 1
}
/// <summary>
/// Align ScrollBar
/// </summary>
public Alignment ScrollAlignment
{
get
{
return Scroll; //Get Value
}
set
{
if (Scroll == value) //If Not Valid Value
return;
Scroll = value; //Set Value
AlignScrollbar(); //Call AlignScroll Method
}
}
private const int GWL_EXSTYLE = -20; //ComboBox Style
private const int WS_EX_RIGHT = 4096; //Right Align Text
private const int WS_EX_LEFTSCROLLBAR = 16384; //Left ScrollBar
private const int WS_EX_RIGHTSCROLLBAR = 128; //Right ScrollBar
private IntPtr handle; //Handle Of ComboBox
private Alignment Scroll; //Alignment Options For ScrollBar
public ComboBox()
{
handle = CASGetHandle(this); //Get Handle Of ComboBox
Scroll = Alignment.Right; //default alignment
}
/// <summary>
/// Retrieves ComboBox Handle
/// </summary>
/// <param name="CASCombo"></param>
/// <returns></returns>
public IntPtr CASGetHandle(ComboBox CASCombo)
{
COMBOBOXINFO CASCBI = new COMBOBOXINFO(); //New ComboBox Settings Object
CASCBI.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(CASCBI); //Call In Correct Size
GetComboBoxInfo(CASCombo.Handle, ref CASCBI); //Obtain Handle
return CASCBI.hwndList; //Return Handle
}
/// <summary>
/// Align The ComboBox ScrollBar
/// </summary>
private void AlignScrollbar()
{
if (handle != IntPtr.Zero) //If Valid Handle
{
int style = GetWindowLong(handle, GWL_EXSTYLE); //Get ComboBox Style
switch (Scroll)
{
case Alignment.Left:
style = WS_EX_LEFTSCROLLBAR; //Align ScrollBare To The Left
break;
case Alignment.Right:
style = WS_EX_RIGHTSCROLLBAR; //Align ScrollBare To The Right
break;
}
SetWindowLong(handle, GWL_EXSTYLE, style); //Apply On ComboBox
}
}
}
}
in combobox control there is right to left property, just set it to true
That cannot be done in WinForms. Although you can come up with your own solution of control, representing the required structure.

How can I remove the selection border on a ListViewItem

I'm using SetWindowTheme and SendMessage to make a .net listview look like a vista style listview, but the .net control still has a dotted selection border around the selected item:
Selected items in the explorer listview don't have that border around them. How can I remove it?
Windows Explorer:
Edit: Solution:
public static int MAKELONG(int wLow, int wHigh)
{
int low = (int)LOWORD(wLow);
short high = LOWORD(wHigh);
int product = 0x00010000 * (int)high;
int makeLong = (int)(low | product);
return makeLong;
}
SendMessage(olv.Handle, WM_CHANGEUISTATE, Program.MAKELONG(UIS_SET, UISF_HIDEFOCUS), 0);
Telanors solution worked for me. Here's a slightly more self-contained version.
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class MyListView : ListView
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
private const int WM_CHANGEUISTATE = 0x127;
private const int UIS_SET = 1;
private const int UISF_HIDEFOCUS = 0x1;
public MyListView()
{
this.View = View.Details;
this.FullRowSelect = true;
// removes the ugly dotted line around focused item
SendMessage(this.Handle, WM_CHANGEUISTATE, MakeLong(UIS_SET, UISF_HIDEFOCUS), 0);
}
private int MakeLong(int wLow, int wHigh)
{
int low = (int)IntLoWord(wLow);
short high = IntLoWord(wHigh);
int product = 0x10000 * (int)high;
int mkLong = (int)(low | product);
return mkLong;
}
private short IntLoWord(int word)
{
return (short)(word & short.MaxValue);
}
}
Doing this the NON P/Invoke way...
Override your ListView control and add the following:
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
Message m = Message.Create(this.Handle, 0x127, new IntPtr(0x10001), new IntPtr(0));
this.WndProc(ref m);
}
protected override void OnEnter(EventArgs e)
{
base.OnEnter(e);
Message m = Message.Create(this.Handle, 0x127, new IntPtr(0x10001), new IntPtr(0));
this.WndProc(ref m);
}
Setting the HotTracking property to true hides the focus rectangle. This repro-ed the Explorer style on my Win7 machine:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
class MyListView : ListView {
public MyListView() {
this.HotTracking = true;
}
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
SetWindowTheme(this.Handle, "explorer", null);
}
[DllImport("uxtheme.dll", CharSet = CharSet.Auto)]
public extern static int SetWindowTheme(IntPtr hWnd, string appname, string subidlist);
}
Beware that getting the items underlined is a side-effect.
Does setting the ListView.ShowFocusCues property to false help?
I know this is rather old, and Windows Forms is antiquated now, but it's still in use and it's still an issue. Worse, none of these solution are elegant, and some don't even work at all.
Here's a very simple solution, when you create your own control that inherits the ListView, then just override the WndProc to never allow focus. It gets rid of all focus-related dotted selection boxes, item selection, subitem selection, etc...
using System.Windows.Forms;
public partial class NoSelectionListView : ListView
{
public NoSelectionListView()
{
InitializeComponent();
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0007) //WM_SETFOCUS
{
return;
}
base.WndProc(ref m);
}
}
It does not seem that there is a particular way to change ListViewItem styles using Windows Forms.
Sometimes there is no way to change some Win32 control behaviors using managed code. The only way is to do some P/Invoke to modify specific behaviors. I find this really tricky but you have no other choice. I often faced this situation when developing Windows Mobile UIs (justly with ListView).
So I have no direct answer to your question but I am pretty sure that if it is not possible using Windows Forms, you can surely do with P/Invoke. The only clues I can give you:
Platform Invoke Tutorial
List View documentation
For me turning focus off didn't work until the control was shown.
I did this:
bool HideFocus { get; set; }
bool _hasEnter;
void OnEnter(object sender, EventArgs e)
{
if (!_hasEnter)
{
_hasEnter = true;
// Selection at startup wont change the actual focus
if (this.SelectedIndices.Count > 0)
this.Items[this.SelectedIndices[0]].Focused = true;
// Hide focus rectangle if requested
if (this.ShowFocusCues && this.HideFocus)
{
var lParam1 = MakeLong(UIS_SET, UISF_HIDEFOCUS);
SendMessage(this.Handle, WM_CHANGEUISTATE, lParam1, 0);
}
}
}
See https://stackoverflow.com/a/15768802/714557 above for the MakeLong call.
Also, any selected items before the control is shown, won't set the selection focus.
I basically used the "Set Focus" event to know that the control was shown and that it was actually getting focus, to make the corretions.

Categories