In C# winforms, is there a way to not show the dashed focus outline border that shows around a trackbar control when it is being used?
Details: This outline looks kinda tacky to me, so I'm just shooting for aesthetics to not show it.
Thanks,
Adam
ShowFocusCues didn't work for me, but this did:
internal class NoFocusTrackBar : System.Windows.Forms.TrackBar
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
public extern static int SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
private static int MakeParam(int loWord, int hiWord)
{
return (hiWord << 16) | (loWord & 0xffff);
}
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus(e);
SendMessage(this.Handle, 0x0128, MakeParam(1, 0x1), 0);
}
}
See documentation on WM_UPDATEUISTATE for how this works (basically sending a message to turn the dumb thing off the trackbar gets the focus).
I know it's an old question but this is simpler if anyone interested:
public class TrackBarWithoutFocus : TrackBar
{
private const int WM_SETFOCUS = 0x0007;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_SETFOCUS)
{
return;
}
base.WndProc(ref m);
}
}
private void trackBar1_MouseLeave(object sender, EventArgs e)
{
button2.Select();
}
really old but i made a button with visible set to false and selected that one
when leaving trackbar area
Related
I was looking on this forum earlier to help with this issue i am having. Basically I am dynamically creating a form from a class which i want to be draggable around the screen without the title bars. The code i came across is :
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int HT_CAPTION = 0x2;
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool ReleaseCapture();
private void window_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
However when i try to compile I get the following error:
Error 1 The name 'Handle' does not exist in the current
context C:\Users\xxxxxx\Documents\Visual Studio
2013\Projects\practiceProgressBar2\practiceProgressBar2\Notifications.cs 109 29 practiceProgressBar2
Does anyone know what I am doing wrong as I have been tackling this all day
Change:
SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
To:
SendMessage(((Form)sender).Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
If you have other controls, like Labels, pointing to that same handler, then you could use this instead to make it drag when you also drag the Labels:
SendMessage(((Control)sender).FindForm().Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
Try overriding the form's WndProc method instead.
public const int HTCAPTION = 0x2;
public const int WM_NCHITTEST = 0x84;
public const int HTCLIENT = 1;
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_NCHITTEST)
{
if (m.Result.ToInt32() == HTCLIENT)
m.Result = (IntPtr)HTCAPTION;
}
}
I'm working on a program, who need to detect when the user press the keyboard or use his mouse, even if the program is minimized or not focused.
I think I have to use the windows API, keybd_event (user32), but I don't know how to use the "listener" of this event. I have something like that:
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags,UIntPtr dwExtraInfo);
void PressKey(byte keyCode)
{
//My code here
}
I did some research, but it's the first time I have to use DllImport, so I don't know how to continue ...
Thanks
(Ps:Sorry about my bad English, this is not my native language :) )
(PPs: I've read all of your answers, but it takes a while to read every link, so I'll work on it tonight, but I think I will find the answer. Anyway, thanks for the links everybody ;) )
Edit: So I just finished my code and it's work :) It looks something like:
[DllImport("user32.dll")]
public static extern Boolean GetLastInputInfo(ref tagLASTINPUTINFO plii);
public struct tagLASTINPUTINFO
{
public uint cbSize;
public Int32 dwTime;
}
private void timerTemps_Inactif_Tick(object sender, EventArgs e)
{
tagLASTINPUTINFO LastInput = new tagLASTINPUTINFO();
Int32 IdleTime;
LastInput.cbSize = (uint)Marshal.SizeOf(LastInput);
LastInput.dwTime = 0;
if (GetLastInputInfo(ref LastInput))
{
IdleTime = System.Environment.TickCount - LastInput.dwTime;
if (IdleTime > 10000)
{
//My code here
}
}
}
Thanks for the help guys ;)
You will need to hook into Windows OS with SetWindowsHookEx function. You should read the article Keyloggers: How they work and how to detect them posted by SecureList to get a understanding ofthe process.
I have always got a good performance by using RegisterHotKey/UnregisterHotKey functions. Sample code:
[DllImport("User32")]
public static extern bool RegisterHotKey(
IntPtr hWnd,
int id,
int fsModifiers,
int vk
);
[DllImport("User32")]
public static extern bool UnregisterHotKey(
IntPtr hWnd,
int id
);
public const int MOD_SHIFT = 0x4;
public const int MOD_CONTROL = 0x2;
public const int MOD_ALT = 0x1;
public const int WM_HOTKEY = 0x312;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HOTKEY && m.WParam == (IntPtr)0)
{
IntPtr lParamCTRLA = (IntPtr)4259842;
IntPtr lParamB = (IntPtr)4325376;
if (m.LParam == lParamCTRLA)
{
MessageBox.Show("CTRL+A was pressed");
}
else if (m.LParam == lParamB)
{
MessageBox.Show("B was pressed");
}
}
base.WndProc(ref m);
}
private void Form1_Load(object sender, EventArgs e)
{
this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);
RegisterHotKey(this.Handle, 0, MOD_CONTROL, (int)Keys.A);
RegisterHotKey(this.Handle, 0, 0, (int)Keys.B);
}
private void Form1_FormClosing(Object sender, FormClosingEventArgs e)
{
UnregisterHotKey(this.Handle, 0);
}
You can "register" as many keys (or combination of keys) as you want by emulating the shown structure. All the registered keys will get inside the condition if (m.Msg == WM_HOTKEY && m.WParam == (IntPtr)0); if they are pressed at all (independently upon the program currently being selected). The easiest way to know the specific key/combination being pressed is relying on m.LParam (I got the two values I am including after a quick test with the given keys). You can do a quick research to find out a list of LParam or further constant modifiers (wheel of the mouse, for example).
The final code:
[DllImport("user32.dll")]
public static extern Boolean GetLastInputInfo(ref tagLASTINPUTINFO plii);
public struct tagLASTINPUTINFO
{
public uint cbSize;
public Int32 dwTime;
}
private void timerTemps_Inactif_Tick(object sender, EventArgs e)
{
tagLASTINPUTINFO LastInput = new tagLASTINPUTINFO();
Int32 IdleTime;
LastInput.cbSize = (uint)Marshal.SizeOf(LastInput);
LastInput.dwTime = 0;
if (GetLastInputInfo(ref LastInput))
{
IdleTime = System.Environment.TickCount - LastInput.dwTime;
if (IdleTime > 10000)
{
//My code here
}
}
}
How do I achieve this in a WinForms container control when the scroll bars are visible?
Highlighted here (Google Chrome browser):
EDIT: This cursor is the only one that is visible on a screenshot. I hope it's clear what i mean.
EDIT:
Tried this on my control. Does not work.
const int WM_MBUTTONDOWN = 0x207;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_MBUTTONDOWN)
DefWndProc(ref m);
else
base.WndProc(ref m);
}
Here's what I have so far. It exits "reader mode" if I release the middle button, and I haven't implemented scrolling within the control (I used a textbox), but it may give you something to start with.
[DllImport("comctl32.dll", SetLastError=true, EntryPoint="#383")]
static extern void DoReaderMode(ref READERMODEINFO prmi);
public delegate bool TranslateDispatchCallbackDelegate(ref MSG lpmsg);
public delegate bool ReaderScrollCallbackDelegate(ref READERMODEINFO prmi, int dx, int dy);
[StructLayout(LayoutKind.Sequential)]
public struct READERMODEINFO
{
public int cbSize;
public IntPtr hwnd;
public int fFlags;
public IntPtr prc;
public ReaderScrollCallbackDelegate pfnScroll;
public TranslateDispatchCallbackDelegate fFlags2;
public IntPtr lParam;
}
[StructLayout(LayoutKind.Sequential)]
public struct MSG
{
public IntPtr hwnd;
public UInt32 message;
public IntPtr wParam;
public IntPtr lParam;
public UInt32 time;
public POINT pt;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int left, top, right, bottom;
}
private bool TranslateDispatchCallback(ref MSG lpMsg)
{
return false;
}
private bool ReaderScrollCallback(ref READERMODEINFO prmi, int dx, int dy)
{
// TODO: Scroll around within your control here
return false;
}
private void EnterReaderMode()
{
READERMODEINFO readerInfo = new READERMODEINFO
{
hwnd = this.textBox1.Handle,
fFlags = 0x00,
prc = IntPtr.Zero,
lParam = IntPtr.Zero,
fFlags2 = new TranslateDispatchCallbackDelegate(this.TranslateDispatchCallback),
pfnScroll = new ReaderScrollCallbackDelegate(this.ReaderScrollCallback)
};
readerInfo.cbSize = Marshal.SizeOf(readerInfo);
DoReaderMode(ref readerInfo);
}
private void textBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Middle)
{
EnterReaderMode();
}
}
The RichTextBox control does it by default when you press the mouse wheel button.
Edit: Sorry I misunderstood and thought you were asking about doing it within a textbox not a container control
First, sorry for my bad english :)
Second, I can know when the form is being moved/resized, using this code:
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_WINDOWPOSCHANGING)
{
WINDOWPOS winPos = new WINDOWPOS();
winPos = (WINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(WINDOWPOS));
//Here I just need to change the values of the WINDOWPOS structure
Marshal.StructureToPtr(winPos, m.LParam, true);
}
}
The WM_WINDOWPOSCHANGING message is sent also when the user is minimizing or maximizing the window. But how I can know when the user is maximizing/minimizing, not moving/resizing? I tried get the WindowState property, but it didn't work :(
The code of the WINDOWPOS structure is:
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public int flags;
}
Any help?
You get WM_SYSCOMMAND when the user clicks one of the buttons in the title bar: http://msdn.microsoft.com/en-us/library/ms646360(VS.85).aspx
You can trap the WM_SYSCOMMAND by overriding WndProc(). But it can easily be done as well with an event handler for the Resize event:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
mPrevState = this.WindowState;
}
FormWindowState mPrevState;
protected override void OnResize(EventArgs e) {
base.OnResize(e);
if (mPrevState != this.WindowState) {
mPrevState = this.WindowState;
// Do something
//..
}
}
}
I'm working on a control to tie together the view from one ListView to another so that when the master ListView is scrolled, the child ListView view is updated to match.
So far I've been able to get the child ListViews to update their view when the master scrollbar buttons are clicked. The problem is that when clicking and dragging the ScrollBar itself, the child ListViews are not updated. I've looked at the messages being sent using Spy++ and the correct messages are getting sent.
Here is my current code:
public partial class LinkedListViewControl : ListView
{
[DllImport("User32.dll")]
private static extern bool SendMessage(IntPtr hwnd, UInt32 msg, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll")]
private static extern bool ShowScrollBar(IntPtr hwnd, int wBar, bool bShow);
[DllImport("user32.dll")]
private static extern int SetScrollPos(IntPtr hWnd, int wBar, int nPos, bool bRedraw);
private const int WM_HSCROLL = 0x114;
private const int SB_HORZ = 0;
private const int SB_VERT = 1;
private const int SB_CTL = 2;
private const int SB_BOTH = 3;
private const int SB_THUMBPOSITION = 4;
private const int SB_THUMBTRACK = 5;
private const int SB_ENDSCROLL = 8;
public LinkedListViewControl()
{
InitializeComponent();
}
private readonly List<ListView> _linkedListViews = new List<ListView>();
public void AddLinkedView(ListView listView)
{
if (!_linkedListViews.Contains(listView))
{
_linkedListViews.Add(listView);
HideScrollBar(listView);
}
}
public bool RemoveLinkedView(ListView listView)
{
return _linkedListViews.Remove(listView);
}
private void HideScrollBar(ListView listView)
{
//Make sure the list view is scrollable
listView.Scrollable = true;
//Then hide the scroll bar
ShowScrollBar(listView.Handle, SB_BOTH, false);
}
protected override void WndProc(ref Message msg)
{
if (_linkedListViews.Count > 0)
{
//Look for WM_HSCROLL messages
if (msg.Msg == WM_HSCROLL)
{
foreach (ListView view in _linkedListViews)
{
SendMessage(view.Handle, WM_HSCROLL, msg.WParam, IntPtr.Zero);
}
}
}
}
}
Based on this post on the MS Tech Forums I tried to capture and process the SB_THUMBTRACK event:
protected override void WndProc(ref Message msg)
{
if (_linkedListViews.Count > 0)
{
//Look for WM_HSCROLL messages
if (msg.Msg == WM_HSCROLL)
{
Int16 hi = (Int16)((int)msg.WParam >> 16);
Int16 lo = (Int16)msg.WParam;
foreach (ListView view in _linkedListViews)
{
if (lo == SB_THUMBTRACK)
{
SetScrollPos(view.Handle, SB_HORZ, hi, true);
int wParam = 4 + 0x10000 * hi;
SendMessage(view.Handle, WM_HSCROLL, (IntPtr)(wParam), IntPtr.Zero);
}
else
{
SendMessage(view.Handle, WM_HSCROLL, msg.WParam, IntPtr.Zero);
}
}
}
}
// Pass message to default handler.
base.WndProc(ref msg);
}
This will update the location of the child ListView ScrollBar but does not change the actual view in the child.
So my questions are:
Is it possible to update the child ListViews when the master ListView ScrollBar is dragged?
If so, how?
I wanted to do the same thing, and after searching around I found your code here, which helped, but of course didn't solve the problem. But after playing around with it, I have found a solution.
The key came when I realized that since the scroll buttons work, that you can use that to make the slider work. In other words, when the SB_THUMBTRACK event comes in, I issue repeated SB_LINELEFT and SB_LINERIGHT events until my child ListView gets close to where the master is. Yes, this isn't perfect, but it works close enough.
In my case, my master ListView is called "reportView", while my child ListView is called "summaryView". Here's my pertinent code:
public class MyListView : ListView
{
public event ScrollEventHandler HScrollEvent;
protected override void WndProc(ref System.Windows.Forms.Message msg)
{
if (msg.Msg==WM_HSCROLL && HScrollEvent != null)
HScrollEvent(this,new ScrollEventArgs(ScrollEventType.ThumbTrack, (int)msg.WParam));
base.WndProc(ref msg);
}
}
And then the event handler itself:
reportView.HScrollEvent += new ScrollEventHandler((sender,e) => {
if ((ushort) e.NewValue != SB_THUMBTRACK)
SendMessage(summaryView.Handle, WM_HSCROLL, (IntPtr) e.NewValue, IntPtr.Zero);
else {
int newPos = e.NewValue >> 16;
int oldPos = GetScrollPos(reportView .Handle, SB_HORZ);
int pos = GetScrollPos(summaryView.Handle, SB_HORZ);
int lst;
if (pos != newPos)
if (pos<newPos && oldPos<newPos) do { lst=pos; SendMessage(summaryView.Handle,WM_HSCROLL,(IntPtr)SB_LINERIGHT,IntPtr.Zero); } while ((pos=GetScrollPos(summaryView.Handle,SB_HORZ)) < newPos && pos!=lst);
else if (pos>newPos && oldPos>newPos) do { lst=pos; SendMessage(summaryView.Handle,WM_HSCROLL,(IntPtr)SB_LINELEFT, IntPtr.Zero); } while ((pos=GetScrollPos(summaryView.Handle,SB_HORZ)) > newPos && pos!=lst);
}
});
Sorry about the odd formatting of the while loops there, but that's how I prefer to code things like that.
The next problem was getting rid of the scroll bars in the child ListView. I noticed you had a method called HideScrollBar. This didn't really work for me. I found a better solution in my case was leaving the scroll bar there, but "covering" it up instead. I do this with the column header as well. I just slide my child control up under the master control to cover the column header. And then I stretch the child to fall out of the panel that contains it. And then to provide a bit of a border along the edge of my containing panel, I throw in a control to cover the visible bottom edge of my child ListView. It ends up looking rather nice.
I also added an event handler to sync changing column widths, as in:
reportView.ColumnWidthChanging += new ColumnWidthChangingEventHandler((sender,e) => {
summaryView.Columns[e.ColumnIndex].Width = e.NewWidth;
});
While this all seems a bit of a kludge, it works for me.
This is conjecture just to get the mental juices flowing so take it as you will:
In the scroll handler for the master list, can you call the scroll handler for the child list (passing the sender and eventargs from the master)?
Add this to your Form load:
masterList.Scroll += new ScrollEventHandler(this.masterList_scroll);
Which references this:
private void masterList_scroll(Object sender, System.ScrollEventArgs e)
{
childList_scroll(sender, e);
}
private void childList_scroll(Object sender, System.ScrollEventArgs e)
{
childList.value = e.NewValue
}
I would create my own class, inheriting from ListView to expose the Vertical and Horizontal scroll events.
Then I would do create scroll handlers in my form to synchronize the two controls
This is sample code which should allow a listview to publish scroll events:
public class MyListView : System.Windows.Forms.ListView
{
const int WM_HSCROLL = 0x0114;
const int WM_VSCROLL = 0x0115;
private ScrollEventHandler evtHScroll_m;
private ScrollEventHandler evtVScroll_m;
public event ScrollEventHandler OnHScroll
{
add
{
evtHScroll_m += value;
}
remove
{
evtHScroll_m -= value;
}
}
public event ScrollEventHandler OnHVcroll
{
add
{
evtVScroll_m += value;
}
remove
{
evtVScroll_m -= value;
}
}
protected override void WndProc(ref System.Windows.Forms.Message msg)
{
if (msg.Msg == WM_HSCROLL && evtHScroll_m != null)
{
evtHScroll_m(this,new ScrollEventArgs(ScrollEventType.ThumbTrack, msg.WParam.ToInt32()));
}
if (msg.Msg == WM_VSCROLL && evtVScroll_m != null)
{
evtVScroll_m(this, new ScrollEventArgs(ScrollEventType.ThumbTrack, msg.WParam.ToInt32()));
}
base.WndProc(ref msg);
}
Now handle the scroll events in your form:
Set up a PInvoke method to be able to send a windows message to a control:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int SendMessage(IntPtr hWnd, [MarshalAs(UnmanagedType.U4)] int iMsg, int iWParam, int iLParam);
Set up your event handlers (lstMaster and lstChild are two listboxes):
lstMaster.OnVScroll += new ScrollEventHandler(this.lstMaster_OnVScroll);
lstMaster.OnHScroll += new ScrollEventHandler(this.lstMaster_OnHScroll);
const int WM_HSCROLL = 0x0114;
const int WM_VSCROLL = 0x0115;
private void lstMaster_OnVScroll(Object sender, System.ScrollEventArgs e)
{
SendMessage(lstChild.Handle,WM_VSCROLL,(IntPtr)e.NewValue, IntPtr.Zero);
}
private void lstMaster_OnHScroll(Object sender, System.ScrollEventArgs e)
{
SendMessage(lstChild.Handle,WM_HSCROLL,(IntPtr)e.NewValue, IntPtr.Zero);
}
A naive solution to your problem can be handling the paint message in the parent list view and checking if the linked list views are displaying the correct data. If they don't, then update them to display the correct data by calling the EnsureVisible method.