I have a border-less windows form that i created a shadow behind it using the code below.
However when I click on the parent form the shadow disappears.
can anyone help me out on how to keep the shadow even when clicking on anther form/parent form?
The shaddow is visable against a diffrent window (chrome for example) but not against it's parent form
(I tried google but couldn't find anything)
Update
I do notice that if i minimize the window and maximize it again the shadow does come back
My Code
private const int CS_DROPSHADOW = 0x00020000;
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ClassStyle |= CS_DROPSHADOW;
return cp;
}
}
Thanks in advance
Pls try the below steps and revert back for any errors:
Add the below code to a new code file named DropShadow.cs;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Core
{
public class DropShadow
{
#region Shadowing
#region Fields
private bool _isAeroEnabled = false;
private bool _isDraggingEnabled = false;
private const int WM_NCHITTEST = 0x84;
private const int WS_MINIMIZEBOX = 0x20000;
private const int HTCLIENT = 0x1;
private const int HTCAPTION = 0x2;
private const int CS_DBLCLKS = 0x8;
private const int CS_DROPSHADOW = 0x00020000;
private const int WM_NCPAINT = 0x0085;
private const int WM_ACTIVATEAPP = 0x001C;
#endregion
#region Structures
[EditorBrowsable(EditorBrowsableState.Never)]
public struct MARGINS
{
public int leftWidth;
public int rightWidth;
public int topHeight;
public int bottomHeight;
}
#endregion
#region Methods
#region Public
[DllImport("dwmapi.dll")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);
[DllImport("dwmapi.dll")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
[DllImport("dwmapi.dll")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static extern int DwmIsCompositionEnabled(ref int pfEnabled);
[EditorBrowsable(EditorBrowsableState.Never)]
public static bool IsCompositionEnabled()
{
if (Environment.OSVersion.Version.Major < 6) return false;
bool enabled;
DwmIsCompositionEnabled(out enabled);
return enabled;
}
#endregion
#region Private
[DllImport("dwmapi.dll")]
private static extern int DwmIsCompositionEnabled(out bool enabled);
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
private static extern IntPtr CreateRoundRectRgn
(
int nLeftRect,
int nTopRect,
int nRightRect,
int nBottomRect,
int nWidthEllipse,
int nHeightEllipse
);
private bool CheckIfAeroIsEnabled()
{
if (Environment.OSVersion.Version.Major >= 6)
{
int enabled = 0;
DwmIsCompositionEnabled(ref enabled);
return (enabled == 1) ? true : false;
}
return false;
}
#endregion
#region Overrides
public void ApplyShadows(Form form)
{
var v = 2;
DwmSetWindowAttribute(form.Handle, 2, ref v, 4);
MARGINS margins = new MARGINS()
{
bottomHeight = 1,
leftWidth = 0,
rightWidth = 0,
topHeight = 0
};
DwmExtendFrameIntoClientArea(form.Handle, ref margins);
}
#endregion
#endregion
#endregion
}
}
In your form, add this line below InitializeComponent();
(new Core.DropShadow()).ApplyShadows(this);
Related
This is the first code I've written in c#, and my first question to Stackoverflow...apologies up front if I'm doing everything wrong! :-/
I've tried to implement the Public Class RTFScrolledToBottom written by LarsTech that was posted as answered the question here:
Get current scroll position from rich text box control?
In the public Form1() code block, this line is generating a CS1061 error:
rtfScrolledBottom1.ScrolledToBottom += rtfScrolledBottom1_ScrolledToBottom;
object does not contain a definition for ScrolledToBottom and no accessible extension method ScrolledToBottom accepting a first argument of type object could be found (are you missing a using directive or an assembly reference?)
Thanks in advance for any assistance pointing me to what I'm screwing up!!
Cheers!
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private object rtfScrolledBottom1;
public Form1()
{
InitializeComponent();
int rtfScrolledBottom1_ScrolledToBottom = 0;
rtfScrolledBottom1.ScrolledToBottom += rtfScrolledBottom1_ScrolledToBottom;
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
}
}
public class RTFScrolledBottom : RichTextBox
{
public event EventHandler ScrolledToBottom;
private const int WM_VSCROLL = 0x115;
private const int WM_MOUSEWHEEL = 0x20A;
private const int WM_USER = 0x400;
private const int SB_VERT = 1;
private const int EM_SETSCROLLPOS = WM_USER + 222;
private const int EM_GETSCROLLPOS = WM_USER + 221;
[DllImport("user32.dll")]
private static extern bool GetScrollRange(IntPtr hWnd, int nBar, out int lpMinPos, out int lpMaxPos);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);
public bool IsAtMaxScroll()
{
int minScroll;
int maxScroll;
GetScrollRange(this.Handle, SB_VERT, out minScroll, out maxScroll);
Point rtfPoint = Point.Empty;
SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref rtfPoint);
return (rtfPoint.Y + this.ClientSize.Height >= maxScroll);
}
protected virtual void OnScrolledToBottom(EventArgs e)
{
if (ScrolledToBottom != null)
ScrolledToBottom(this, e);
}
protected override void OnKeyUp(KeyEventArgs e)
{
if (IsAtMaxScroll())
OnScrolledToBottom(EventArgs.Empty);
base.OnKeyUp(e);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_VSCROLL || m.Msg == WM_MOUSEWHEEL)
{
if (IsAtMaxScroll())
OnScrolledToBottom(EventArgs.Empty);
}
base.WndProc(ref m);
}
}
}
You have defined rtfScrolledBottom1 as object and object doesn't have any event. You need to define it as RTFScrolledBottom. You also can drop an instance of the RTFScrolledBottom control from toolbox and use it like any other control.
Alternative solution
As an alternative to the solution which you found in the linked post, here is another solution which Works with RichTextBox without creating a derived control, while you can put the logic in a derived control and make it more reusable, like what has done in the linked post.
You can handle VScroll event of the RichTextBox and get the scroll position by calling GetScrollInfo method. Then in the SCROLLINFO if nPage + nPos == nMax, it means the scroll is at bottom:
[StructLayout(LayoutKind.Sequential)]
struct SCROLLINFO {
public int cbSize;
public ScrollInfoMask fMask;
public int nMin;
public int nMax;
public uint nPage;
public int nPos;
public int nTrackPos;
}
public enum ScrollInfoMask : uint {
SIF_RANGE = 0x1,
SIF_PAGE = 0x2,
SIF_POS = 0x4,
SIF_DISABLENOSCROLL = 0x8,
SIF_TRACKPOS = 0x10,
SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS),
}
[DllImport("user32.dll")]
private static extern bool GetScrollInfo(IntPtr hwnd, SBOrientation fnBar,
ref SCROLLINFO lpsi);
public enum SBOrientation : int { SB_HORZ = 0x0, SB_VERT = 0x1 }
private void richTextBox1_VScroll(object sender, EventArgs e)
{
var info = new SCROLLINFO() {
cbSize = (Marshal.SizeOf<SCROLLINFO>()),
fMask = ScrollInfoMask.SIF_ALL
};
GetScrollInfo(richTextBox1.Handle, SBOrientation.SB_VERT, ref info);
if (info.nPage + info.nPos == info.nMax)
{
//VScroll is at bottom
}
}
I'm new to c#/winforms and i wanted to get mouse state as an int to check it in an "if" statement. (For exemple, left click)
So I found a global mouse hook [Here][1], wich works great.
But i don't understand how i can get the mouse state as an int, i searched for a long time on forums and wikis.
I've an error when i create an int in the hookCallback, where the click state is checked (If i understanded as well)
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
MouseHook.Start();
MouseHook.MouseAction += ne
w EventHandler(Event);
}
private void Event(object sender, EventArgs e) { Console.WriteLine("Left mouse click!"); }
}
public static class MouseHook
{
public static event EventHandler MouseAction = delegate { };
public static void Start()
{
_hookID = SetHook(_proc);
}
public static void stop()
{
UnhookWindowsHookEx(_hookID);
}
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
MouseAction(null, new EventArgs());
******** public int LeftClick = 1; *********
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
}
Add my class to your project
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Windows.Input;
namespace Hector.Framework.Utils
{
public class Peripherals
{
public class Mouse
{
public static int X
{
get => Cursor.Position.X;
}
public static int Y
{
get => Cursor.Position.Y;
}
public static void MoveToPoint(int X, int Y)
{
Win32.SetCursorPos(X, Y);
}
public static void Hide()
{
Cursor.Hide();
}
public static void Show()
{
Cursor.Show();
}
public static bool IsHidden
{
get => Cursor.Current == null;
}
/// <summary>
/// ButtonNumber: 0-None 1-Left 2-Middle 3-Right 4-XButton1 5-XButton2
/// </summary>
public static bool MouseButtonIsDown(int ButtonNumber)
{
bool outValue = false;
bool isLeft = Control.MouseButtons == MouseButtons.Left;
bool isRight = Control.MouseButtons == MouseButtons.Right;
bool isMiddle = Control.MouseButtons == MouseButtons.Middle;
bool isXButton1 = Control.MouseButtons == MouseButtons.XButton1;
bool isXButton2 = Control.MouseButtons == MouseButtons.XButton2;
switch (ButtonNumber)
{
case 0:
outValue = false;
break;
case 1:
outValue = isLeft;
break;
case 2:
outValue = isMiddle;
break;
case 3:
outValue = isRight;
break;
case 4:
outValue = isXButton1;
break;
case 5:
outValue = isXButton2;
break;
}
return outValue;
}
/// <summary>
/// This function is in Alpha Phase
/// </summary>
/// <param name="FocusedControl">The control that is scrolled; If the control has no focus, it will be applied automatically</param>
/// <param name="FontSize">This is used to calculate the number of pixels to move, its default value is 20</param>
static int delta = 0;
static int numberOfTextLinesToMove = 0;
static int numberOfPixelsToMove = 0;
public static bool GetWheelValues(Control FocusedControl, out int Delta, out int NumberOfTextLinesToMove, out int NumberOfPixelsToMove, int FontSize = 20)
{
try
{
if (FocusedControl == null) throw new NullReferenceException("The FocusedControl can not bel null");
if (!FocusedControl.Focused) FocusedControl.Focus();
FocusedControl.MouseWheel += (object sender, MouseEventArgs e) =>
{
delta = e.Delta;
numberOfTextLinesToMove = e.Delta * SystemInformation.MouseWheelScrollLines / 120;
numberOfPixelsToMove = numberOfTextLinesToMove * FontSize;
};
Delta = delta;
NumberOfTextLinesToMove = numberOfTextLinesToMove;
NumberOfPixelsToMove = numberOfPixelsToMove;
return true;
}
catch
{
Delta = 0;
NumberOfTextLinesToMove = 0;
NumberOfPixelsToMove = numberOfPixelsToMove;
return false;
}
}
private class Win32
{
[DllImport("User32.Dll")]
public static extern long SetCursorPos(int x, int y);
[DllImport("User32.Dll")]
public static extern bool ClientToScreen(IntPtr hWnd, ref POINT point);
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
}
}
}
}
}
Then where you need to check the mouse's status, write the following:
bool MouseLeftButton = Hector.Framework.Utils.Peripherals.Mouse.MouseButtonIsDown(1);
Remember: While selected button is pressed, bool is true, when button released, bool is false
The ButtonNumbers:
0 - None,
1 - Left,
2 - Middle,
3 - Right,
4 - XButton1,
5 - XButton2
I would like to use the numlock button for something other than numlock. So basically I would like to turn off numlock when it is pressed and keep it off. I can capture the button press but it still toggles on/off. I want it off, always. Any suggestions?
Not sure WHY anyone would like to know WHY I want this to be done but here is the reason: I have a bluetooth numeric keypad that I want to use to control a machine. Does that justify the question?
After a couple hours of research I came across the following code which did the trick:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class SetNumlockKeyOn
{
[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
internal int type;
internal short wVk;
internal short wScan;
internal int dwFlags;
internal int time;
internal IntPtr dwExtraInfo;
int dummy1;
int dummy2;
internal int type1;
internal short wVk1;
internal short wScan1;
internal int dwFlags1;
internal int time1;
internal IntPtr dwExtraInfo1;
int dummy3;
int dummy4;
}
[DllImport("user32.dll")]
static extern int SendInput(uint nInputs, IntPtr pInputs, int cbSize);
public static void SetNumlockOn()
{
if (Control.IsKeyLocked(Keys.NumLock)) return;
const int mouseInpSize = 28;//Hardcoded size of the MOUSEINPUT tag !!!
INPUT input = new INPUT();
input.type = 0x01; //INPUT_KEYBOARD
input.wVk = 0x90; //VK_NUMLOCK
input.wScan = 0;
input.dwFlags = 0; //key-down
input.time = 0;
input.dwExtraInfo = IntPtr.Zero;
input.type1 = 0x01;
input.wVk1 = 0x90;
input.wScan1 = 0;
input.dwFlags1 = 2; //key-up
input.time1 = 0;
input.dwExtraInfo1 = IntPtr.Zero;
IntPtr pI = Marshal.AllocHGlobal(mouseInpSize * 2);
Marshal.StructureToPtr(input, pI, false);
int result = SendInput(2, pI, mouseInpSize); //Hardcoded size of the MOUSEINPUT tag !!!
//if (result == 0 || Marshal.GetLastWin32Error() != 0)
// Console.WriteLine(Marshal.GetLastWin32Error());
Marshal.FreeHGlobal(pI);
}
}
Here's an example:
public static class NativeMethods
{
public const byte VK_NUMLOCK = 0x90;
public const uint KEYEVENTF_EXTENDEDKEY = 1;
public const int KEYEVENTF_KEYUP = 0x2;
[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
public static void SimulateKeyPress(byte keyCode)
{
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
public partial class Form1 : Form
{
private bool protectKeys; // To protect from inifite keypress chain reactions
public Form1()
{
InitializeComponent();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (protectKeys)
return;
if (e.KeyCode == Keys.NumLock &&
!(new Microsoft.VisualBasic.Devices.Keyboard().NumLock))
{
protectKeys = true;
NativeMethods.SimulateKeyPress(NativeMethods.VK_NUMLOCK);
protectKeys = false;
}
}
}
In Windows Explorer (at least in Win7) when you hover the mouse over a column header, a filter box with an arrow appears that lets you filter the results in the ListView, so for example you can only show files starting with "A" or files > 128 MB. Can this feature be enabled in the basic ListView control in C# without subclassing or modifying the ListView?
Here's some code to play with. Add a new class to your project and paste the code shown below. Compile. Drop the new ListViewEx control from the top of the toolbox onto your form. In the form constructor, call the SetHeaderDropdown() method to enable the button. Implement the HeaderDropdown event to return a control to display. For example:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
listViewEx1.SetHeaderDropdown(0, true);
listViewEx1.HeaderDropdown += listViewEx1_HeaderDropdown;
}
void listViewEx1_HeaderDropdown(object sender, ListViewEx.HeaderDropdownArgs e) {
e.Control = new UserControl1();
}
}
The below code has a flaw, the popup is displayed in a form. Which can't be too small and takes the focus away from the main form. Check this answer on hints how to implement a control that can be displayed as a toplevel window without needing a form. The code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
class ListViewEx : ListView {
public class HeaderDropdownArgs : EventArgs {
public int Column { get; set; }
public Control Control { get; set; }
}
public event EventHandler<HeaderDropdownArgs> HeaderDropdown;
public void SetHeaderDropdown(int column, bool enable) {
if (column < 0 || column >= this.Columns.Count) throw new ArgumentOutOfRangeException("column");
while (HeaderDropdowns.Count < this.Columns.Count) HeaderDropdowns.Add(false);
HeaderDropdowns[column] = enable;
if (this.IsHandleCreated) SetDropdown(column, enable);
}
protected void OnHeaderDropdown(int column) {
var handler = HeaderDropdown;
if (handler == null) return;
var args = new HeaderDropdownArgs() { Column = column };
handler(this, args);
if (args.Control == null) return;
var frm = new Form();
frm.FormBorderStyle = FormBorderStyle.FixedSingle;
frm.ShowInTaskbar = false;
frm.ControlBox = false;
args.Control.Location = Point.Empty;
frm.Controls.Add(args.Control);
frm.Load += delegate { frm.MinimumSize = new Size(1, 1); frm.Size = frm.Controls[0].Size; };
frm.Deactivate += delegate { frm.Dispose(); };
frm.StartPosition = FormStartPosition.Manual;
var rc = GetHeaderRect(column);
frm.Location = this.PointToScreen(new Point(rc.Right - SystemInformation.MenuButtonSize.Width, rc.Bottom));
frm.Show(this.FindForm());
}
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
if (this.Columns.Count == 0 || Environment.OSVersion.Version.Major < 6 || HeaderDropdowns == null) return;
for (int col = 0; col < HeaderDropdowns.Count; ++col) {
if (HeaderDropdowns[col]) SetDropdown(col, true);
}
}
private Rectangle GetHeaderRect(int column) {
IntPtr hHeader = SendMessage(this.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
RECT rc;
SendMessage(hHeader, HDM_GETITEMRECT, (IntPtr)column, out rc);
return new Rectangle(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
}
private void SetDropdown(int column, bool enable) {
LVCOLUMN lvc = new LVCOLUMN();
lvc.mask = LVCF_FMT;
lvc.fmt = enable ? LVCFMT_SPLITBUTTON : 0;
IntPtr res = SendMessage(this.Handle, LVM_SETCOLUMN, (IntPtr)column, ref lvc);
}
protected override void WndProc(ref Message m) {
Console.WriteLine(m);
if (m.Msg == WM_NOTIFY) {
var hdr = (NMHDR)Marshal.PtrToStructure(m.LParam, typeof(NMHDR));
if (hdr.code == LVN_COLUMNDROPDOWN) {
var info = (NMLISTVIEW)Marshal.PtrToStructure(m.LParam, typeof(NMLISTVIEW));
OnHeaderDropdown(info.iSubItem);
return;
}
}
base.WndProc(ref m);
}
private List<bool> HeaderDropdowns = new List<bool>();
// Pinvoke
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, ref LVCOLUMN lvc);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, out RECT rc);
[DllImport("user32.dll")]
private static extern IntPtr SetParent(IntPtr hWnd, IntPtr hParent);
private const int LVM_SETCOLUMN = 0x1000 + 96;
private const int LVCF_FMT = 1;
private const int LVCFMT_SPLITBUTTON = 0x1000000;
private const int WM_NOTIFY = 0x204e;
private const int LVN_COLUMNDROPDOWN = -100 - 64;
private const int LVM_GETHEADER = 0x1000 + 31;
private const int HDM_GETITEMRECT = 0x1200 + 7;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct LVCOLUMN {
public uint mask;
public int fmt;
public int cx;
public string pszText;
public int cchTextMax;
public int iSubItem;
public int iImage;
public int iOrder;
public int cxMin;
public int cxDefault;
public int cxIdeal;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct POINT {
public int x, y;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct RECT {
public int left, top, right, bottom;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct NMHDR {
public IntPtr hwndFrom;
public IntPtr idFrom;
public int code;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct NMLISTVIEW {
public NMHDR hdr;
public int iItem;
public int iSubItem;
public uint uNewState;
public uint uOldState;
public uint uChanged;
public POINT ptAction;
public IntPtr lParam;
}
}
It might be tricky to implement the same type of interface, but you could have your ListView respond to the contents of a TextBox by handling the TextBox's TextChanged event and filtering the list based on the contents. If you put the list in a DataTable then filtering will be easy and you can repopulate your ListView each time the filter changes.
Of course this depends on how many items are in your list.
I'm using p/invoke to call EnableScrollBar from user32.dll (MSDN reference). I noticed that when the scrollbar is enabled, it seems to draw as though no theme is applied and then re-drawn with the theme applied. I've only tested with Windows 7 so far. Is there
any way to stop this from happening?
EDIT: Here's some code to show what happens (dump into a form with scrollbars):
private class Native
{
[DllImport("user32.dll")]
public static extern bool EnableScrollBar(IntPtr hWnd, uint wSBflags, uint wArrows);
public static class SBArrows
{
public const uint ESB_ENABLE_BOTH = 0;
public const uint ESB_DISABLE_BOTH = 3;
public const uint ESB_DISABLE_LEFT = 1;
public const uint ESB_DISABLE_RIGHT = 2;
public const uint ESB_DISABLE_UP = 1;
public const uint ESB_DISABLE_DOWN = 2;
public const uint ESB_DISABLE_LTUP = 1;
public const uint ESB_DISABLE_RTDN = 2;
}
public static class SBFlags
{
public const uint SB_HORZ = 0;
public const uint SB_VERT = 1;
public const uint SB_CTL = 2;
public const uint SB_BOTH = 3;
}
}
private bool Switch = false;
protected override void OnMouseDown(MouseEventArgs e)
{
Native.EnableScrollBar(this.Handle, Native.SBFlags.SB_HORZ, this.Switch ? Native.SBArrows.ESB_DISABLE_BOTH : Native.SBArrows.ESB_ENABLE_BOTH);
this.Switch = !this.Switch;
}
Final Solution
Native.SendMessage(this.Handle, Native.WindowMessages.WM_SETREDRAW, new IntPtr(0), IntPtr.Zero);
Native.EnableScrollBar(this.Handle, Native.SBFlags.SB_HORZ, Native.SBArrows.ESB_ENABLE_BOTH);
Native.SendMessage(this.Handle, Native.WindowMessages.WM_SETREDRAW, new IntPtr(1), IntPtr.Zero);
I don't like this solution much. It does however work:
protected override void OnMouseDown(MouseEventArgs e) {
Native.LockWindowUpdate(this.Handle);
Native.EnableScrollBar(this.Handle, Native.SBFlags.SB_HORZ, this.Switch ? Native.SBArrows.ESB_DISABLE_BOTH : Native.SBArrows.ESB_ENABLE_BOTH);
//this.Invalidate();
Native.LockWindowUpdate(IntPtr.Zero);
this.Switch = !this.Switch;
}