How to prevent TextBox auto scrolls when append text? - c#

I have a multi-line TextBox with a vertical scrollbar that logs data from real-time processing. Currently, whenever a new line is added by textBox.AppendText(), the TextBox scrolls to the bottom so you can see the last entry, this great. But I have a checkbox to indicate whether TextBox is allowed to auto-scroll. Is there any way to do this?
Note:
I want to use the TextBox because the added text has multi-lines and alignment by whitespace, so it's not simple to use with a ListBox or a ListView.
I tried to add a new line by textBox.Text += text, but the TextBox constantly scrolls to the top.
If we have a solution to do that, then one more question is how to prevent the TextBox auto scrolls when the user uses the scrollbar to view somewhere else in the TextBox while the TextBox appends text?
private void OnTextLog(string text)
{
if (chkAutoScroll.Checked)
{
// This always auto scrolls to the bottom.
txtLog.AppendText(Environment.NewLine);
txtLog.AppendText(text);
// This always auto scrolls to the top.
//txtLog.Text += Environment.NewLine + text;
}
else
{
// I want to append the text without scrolls right here.
}
}
Update 1: As saggio suggests, I also think the solution to this problem is to determine the position of the first character in the current text that is displayed in the TextBox before appending text and restoring it after that. But how to do this? I tried to record the current cursor position like this, but it did not help:
int selpoint = txtLog.SelectionStart;
txtLog.AppendText(Environment.NewLine);
txtLog.AppendText(text);
txtLog.SelectionStart = selpoint;
Update 2 (the issue was resolved): I found a solution that can solve my issue here on Stack Overflow. I have optimized their code to suit my case as follows:
// Constants for extern calls to various scrollbar functions
private const int SB_VERT = 0x1;
private const int WM_VSCROLL = 0x115;
private const int SB_THUMBPOSITION = 0x4;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll")]
private static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
[DllImport("user32.dll")]
private static extern bool PostMessageA(IntPtr hWnd, int nBar, int wParam, int lParam);
[DllImport("user32.dll")]
private static extern bool GetScrollRange(IntPtr hWnd, int nBar, out int lpMinPos, out int lpMaxPos);
private void AppendTextToTextBox(TextBox textbox, string text, bool autoscroll)
{
int savedVpos = GetScrollPos(textbox.Handle, SB_VERT);
textbox.AppendText(text + Environment.NewLine);
if (autoscroll)
{
int VSmin, VSmax;
GetScrollRange(textbox.Handle, SB_VERT, out VSmin, out VSmax);
int sbOffset = (int)((textbox.ClientSize.Height - SystemInformation.HorizontalScrollBarHeight) / (textbox.Font.Height));
savedVpos = VSmax - sbOffset;
}
SetScrollPos(textbox.Handle, SB_VERT, savedVpos, true);
PostMessageA(textbox.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * savedVpos, 0);
}
private void OnTextLog(string text)
{
AppendTextToTextBox(txtLog.Text, Environment.NewLine + text, chkAutoScroll.Checked);
}
Another way:
private const int SB_VERT = 0x1;
private const int WM_VSCROLL = 0x115;
private const int SB_THUMBPOSITION = 0x4;
private const int SB_BOTTOM = 0x7;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll")]
private static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
[DllImport("user32.dll")]
private static extern bool PostMessageA(IntPtr hWnd, int nBar, int wParam, int lParam);
private void AppendTextToTextBox(TextBox textbox, string text, bool autoscroll)
{
int savedVpos = GetScrollPos(textbox.Handle, SB_VERT);
textbox.AppendText(text + Environment.NewLine);
if (autoscroll)
{
PostMessageA(textbox.Handle, WM_VSCROLL, SB_BOTTOM, 0);
}
else
{
SetScrollPos(textbox.Handle, SB_VERT, savedVpos, true);
PostMessageA(textbox.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * savedVpos, 0);
}
}
I post these solutions for those who have a similar issue. Thanks for cgyDeveloper's source code.
Does anyone have a more straightforward way?

This seems pretty straight forward but I may be missing something. Use append text to scroll to the position if Autochecked is true and just add the text if you do not wish to scroll.
Update...I was missing something. You want to set the selection point and then scroll to the caret. See below.
if (chkAutoScroll.Checked)
{
// This always auto scrolls to the bottom.
txtLog.AppendText(Environment.NewLine);
txtLog.AppendText(text);
// This always auto scrolls to the top.
//txtLog.Text += Environment.NewLine + text;
}
else
{
int caretPos = txtLog.Text.Length;
txtLog.Text += Environment.NewLine + text;
txtLog.Select(caretPos, 0);
txtLog.ScrollToLine(txtLog.GetLineIndexFromCharacterIndex(caretPos));
}

You have to do it something like this,
textBox1.AppendText("Your text here");
// this selects the index zero as the location of your caret
textBox1.Select(0, 0);
// Scrolls to the caret :)
textBox1.ScrollToCaret();
Tested and working on VS2010 c# Winforms, i dont know about WPF but google probably has the answer for you.

The desired actions are:
To turn on autoscrolling when the scrollbar is dragged to the bottom.
To turn off autoscrolling when the scollbar is dragged anywhere else.
create the following class
public class AutoScrollTextBox : TextBox
{
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;
}
protected override void OnTextChanged(TextChangedEventArgs e)
{
bool isScrolledToEnd = VerticalOffset + ViewportHeight == ExtentHeight;
base.OnTextChanged(e);
CaretIndex = Text.Length;
if (isScrolledToEnd)
{
ScrollToEnd();
}
}
}
And replace the TextBox with AutoScrollTextBox in your XML and append to the TextToDisplay binding as stuff arrives for display
<local:AutoScrollTextBox Text="{Binding TextToDisplay }" />

Related

WPF Window fixed width mouse cursor

I am building a WPF 4.5 Application that has controls that enable the User to "Lock" and "Unlock" the Application's Height.
In order to lock the Height, I am following this StackOverflow answer regarding setting the MinHeight and MaxHeight to the same value.
In order to unlock the Height, I set MinHeight=0 and MaxHeight=double.PositiveInfinity
This all appears to be working fine.
The problem I'm encountering that I haven't been able to solve is that when the height is "Locked", when I mouseover the right edge of the Application Window, the cursor turns into the horizontal resize cursor.
Is there a way I can disable that so that the cursor stays as the regular pointer in WPF?
I am on WPF 4.5.
I saw this post that has answers showing how to do it in Win32: WPF: Make window unresizeable, but keep the frame?.
This post is over 3 years old, and I was just wondering (hoping) maybe WPF has evolved since then.
Thank you very much in advance!
Philip
On your startup Window (MainWindow.xaml), try making a binding for the Window's ResizeMode property and then modifying it to 'NoResize' when you don't want it to be resizable. To make it resizable, change it to 'CanResize'.
Hope that helps!
You need to set MinWidth = MaxWidth = Width = your desired width as mentioned in this StackOverflow answer regarding setting the MinHeight and MaxHeight to the same value.
In addition you need to hook the winproc for your window and process the WM_NCHITTEST message.
#region Vertical Resize Only
// ReSharper disable InconsistentNaming
private const int WM_NCHITTEST = 0x0084;
private const int HTBORDER = 18;
private const int HTBOTTOM = 15;
private const int HTBOTTOMLEFT = 16;
private const int HTBOTTOMRIGHT = 17;
private const int HTLEFT = 10;
private const int HTRIGHT = 11;
private const int HTTOP = 12;
private const int HTTOPLEFT = 13;
private const int HTTOPRIGHT = 14;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr DefWindowProc(
IntPtr hWnd,
int msg,
IntPtr wParam,
IntPtr lParam);
// ReSharper restore InconsistentNaming
#endregion Vertical Resize Only
public CanConfigurationDialog()
{
InitializeComponent();
Loaded += MainWindowLoaded;
}
#region Vertical Resize Only
private void MainWindowLoaded(object sender, RoutedEventArgs e)
{
try
{
// Obtain the window handle for WPF application
var mainWindowPtr = new WindowInteropHelper(this).Handle;
var mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr);
mainWindowSrc?.AddHook(WndProc);
}
catch (Exception)
{
;
}
}
private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Override the window hit test
// and if the cursor is over a resize border,
// return a standard border result instead.
if (msg == WM_NCHITTEST)
{
handled = true;
var htLocation = DefWindowProc(hwnd, msg, wParam, lParam).ToInt32();
switch (htLocation)
{
case HTTOP:
case HTTOPLEFT:
case HTTOPRIGHT:
htLocation = HTTOP;
break;
case HTBOTTOM:
case HTBOTTOMLEFT:
case HTBOTTOMRIGHT:
htLocation = HTBOTTOM;
break;
case HTLEFT:
case HTRIGHT:
htLocation = HTBORDER;
break;
}
return new IntPtr(htLocation);
}
return IntPtr.Zero;
}
#endregion Vertical Resize Only
This will prevent the horizontal resize cursor from being displayed!
Q.E.D.

Textbox - Maintain scroll bar position during text updates

I have to show information to the user that updates every 100 milliseconds, this means the contents of the textbox I show it in are constantly being changed and if they are scrolling through them when they are being changed the update will cause them to loose their scroll bar position
How do I prevent this? I've reduced the effect a lot by adding all text at once.
Current code:
string textboxStr = "";
foreach (string debugItem in debugItems)
{
textboxStr += debugItem + Environment.NewLine;
}
debugForm.Controls[0].Text = textboxStr;
Update 1:
Used the solution provided below and it's not working, the scroll bar still resets to its default position meaning you loose your position and your pointer resets too.
Implementation:
In class:
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool LockWindowUpdate(IntPtr hWndLock);
In function:
var originalPosition = ((TextBox)debugForm.Controls[0]).SelectionStart;
LockWindowUpdate(((TextBox)debugForm.Controls[0]).Handle);
debugForm.Controls[0].Text = textboxStr;
((TextBox)debugForm.Controls[0]).SelectionStart = originalPosition;
((TextBox)debugForm.Controls[0]).ScrollToCaret();
LockWindowUpdate(IntPtr.Zero);
Update 2:
Used the 2nd solution provided below and it's not working. The scroll bar still jumps to the top even mid way while scrolling. Then sometimes when you're not even on it the scroll bar will start jumping up and down (Every 100 ms, when it updates the text).
Implementation:
In class:
[DllImport("user32.dll")]
static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll")]
private static extern bool PostMessageA(IntPtr hWnd, int nBar, int wParam, int lParam);
private const int SB_VERT = 0x1;
private const int SB_THUMBPOSITION = 4;
private const int WM_VSCROLL = 0x115;
In function:
var currentPosition = GetScrollPos(debugForm.Controls[0].Handle, SB_VERT);
debugForm.Controls[0].Text = textboxStr;
SetScrollPos(debugForm.Controls[0].Handle, SB_VERT, currentPosition, false);
PostMessageA(debugForm.Controls[0].Handle, WM_VSCROLL, SB_THUMBPOSITION + 65535 * currentPosition, 0);
Example text:
Active Scene: Level0
--------------------------------------------------
Settings
Fps: 60
GameSize: {Width=600, Height=600}
FreezeOnFocusLost: False
ShowCursor: False
StaysOnTop: False
EscClose: True
Title:
Debug: True
DebugInterval: 100
--------------------------------------------------
Entities
Entity Name: Player
moveSpeed: 10
jumpSpeed: 8
ID: 0
Type: 0
Gravity: 1
Vspeed: 1
Hspeed: 0
X: 20
Y: 361
Z: 0
Sprites: System.Collections.Generic.List`1[GameEngine.Sprite]
SpriteIndex: 0
SpriteSpeed: 0
FramesSinceChange: 0
CollisionHandlers: System.Collections.Generic.List`1[GameEngine.CollisionHandler]
--------------------------------------------------
Key Events
Key: Left
State: DOWN
Key: Left
State: UP
Key: Right
State: DOWN
Key: Right
State: UP
Key: Up
State: DOWN
Key: Up
State: UP
You can store the SelectionStart then use ScrollToCaret after you update. Use LockWindowUpdate to stop the flicker. Something like this:
[DllImport("user32.dll")]
public static extern bool LockWindowUpdate(IntPtr hWndLock);
var originalPosition = textBox.SelectionStart;
LockWindowUpdate(textBox.Handle);
// ---- do the update here ----
textBox.SelectionStart = originalPosition;
textBox.ScrollToCaret();
LockWindowUpdate(IntPtr.Zero);
As long as the textbox doesn't change size (which it doesn't sound like it will) this should work fine. The other option is to use EM_LINESCROLL to store and set the scrollbar value for the textbox.. but that's more involved.
EDIT:
Since that didn't work.. here's another option.
First, some Windows APIs:
[DllImport("user32.dll")]
static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll")]
private static extern bool PostMessageA(IntPtr hWnd, int nBar, int wParam, int lParam);
..and some values:
private const int SB_VERT = 0x1;
private const int SB_THUMBPOSITION = 4;
private const int WM_VSCROLL = 0x115;
You can now do this:
var currentPosition = GetScrollPos(textBox.Handle, SB_VERT);
// ---- update the text here ----
SetScrollPos(textBox.Handle, SB_VERT, currentPosition, false);
PostMessageA(textBox.Handle, WM_VSCROLL, SB_THUMBPOSITION + 65535 * currentPosition, 0);
This works perfectly for me. The only problem I have is that it jumps around sometimes purely because my randomly generated string of characters has widely varying widths. As long as yours is roughly similar after each update, it should be fine.
After searching and never finding a legitimate solution that works with and without focus as well as horizontally and vertically, I stumbled across an API solution that works (at least for my platform - Win7 / .Net4 WinForms).
using System;
using System.Runtime.InteropServices;
namespace WindowsNative
{
/// <summary>
/// Provides scroll commands for things like Multiline Textboxes, UserControls, etc.
/// </summary>
public static class ScrollAPIs
{
[DllImport("user32.dll")]
internal static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll")]
internal static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
[DllImport("user32.dll")]
internal static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
public enum ScrollbarDirection
{
Horizontal = 0,
Vertical = 1,
}
private enum Messages
{
WM_HSCROLL = 0x0114,
WM_VSCROLL = 0x0115
}
public static int GetScrollPosition(IntPtr hWnd, ScrollbarDirection direction)
{
return GetScrollPos(hWnd, (int)direction);
}
public static void GetScrollPosition(IntPtr hWnd, out int horizontalPosition, out int verticalPosition)
{
horizontalPosition = GetScrollPos(hWnd, (int)ScrollbarDirection.Horizontal);
verticalPosition = GetScrollPos(hWnd, (int)ScrollbarDirection.Vertical);
}
public static void SetScrollPosition(IntPtr hwnd, int hozizontalPosition, int verticalPosition)
{
SetScrollPosition(hwnd, ScrollbarDirection.Horizontal, hozizontalPosition);
SetScrollPosition(hwnd, ScrollbarDirection.Vertical, verticalPosition);
}
public static void SetScrollPosition(IntPtr hwnd, ScrollbarDirection direction, int position)
{
//move the scroll bar
SetScrollPos(hwnd, (int)direction, position, true);
//convert the position to the windows message equivalent
IntPtr msgPosition = new IntPtr((position << 16) + 4);
Messages msg = (direction == ScrollbarDirection.Horizontal) ? Messages.WM_HSCROLL : Messages.WM_VSCROLL;
SendMessage(hwnd, (int)msg, msgPosition, IntPtr.Zero);
}
}
}
With a multiline textbox (tbx_main) use like:
int horzPos, vertPos;
ScrollAPIs.GetScrollPosition(tbx_main.Handle, out horzPos, out vertPos);
//make your changes
//i did something like the following where m_buffer is a string[]
tbx_main.Text = string.Join(Environment.NewLine, m_buffer);
tbx_main.SelectionStart = 0;
tbx_main.SelectionLength = 0;
ScrollAPIs.SetScrollPosition(tbx_main.Handle, horzPos, vertPos);

How to Disable Autoscrolling in richtextbox in c#

i want to disable the scrolling feature of richtextbox in c#. i just want to make richtextbox to allow user to enter only in its size area, means no vertical scrolling for user. just like MS-word or open Office Pages.thanx in advance.
You should override WndProc and block WM_SETFOCUS.
protected override void WndProc(ref Message m)
{
if(m.Msg != WM_SETFOCUS)
base.WndProc(ref m);
}
Here is a tutorial about this : How to: C# - Prevent RichTextBox from auto scrolling
This worked for me.
First thing as you may have seen in other posts you need access to user32.dll from C#.
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hwndLock,Int32 wMsg,Int32 wParam, ref Point pt);
We need to make some constant declaration to make the SendMessage calls properly.
private const int WM_USER = 0x400;
private const int EM_HIDESELECTION = WM_USER + 63;
private const int WM_SETREDRAW = 0x000B;
private const int EM_GETSCROLLPOS = WM_USER + 221;
private const int EM_SETSCROLLPOS = WM_USER + 222;
Then, some public static methods to be used whenever we need to stop scrolling.
public static void Suspend(Control control)
{
Message msgSuspendUpdate = Message.Create(control.Handle, WM_SETREDRAW, IntPtr.Zero,
IntPtr.Zero);
NativeWindow window = NativeWindow.FromHandle(control.Handle);
window.DefWndProc(ref msgSuspendUpdate);
}
public static void Resume(Control control)
{
// Create a C "true" boolean as an IntPtr
IntPtr wparam = new IntPtr(1);
Message msgResumeUpdate = Message.Create(control.Handle, WM_SETREDRAW, wparam,
IntPtr.Zero);
NativeWindow window = NativeWindow.FromHandle(control.Handle);
window.DefWndProc(ref msgResumeUpdate);
control.Invalidate();
}
public static Point GetScrollPoint(Control control) {
Point point = new Point();
SendMessage(control.Handle, EM_GETSCROLLPOS, 0, ref point);
return point;
}
public static void SetScrollPoint(Control control, Point point)
{
SendMessage(control.Handle, EM_SETSCROLLPOS, 0, ref point);
}
The Suspend method stops the Control to make a redraw on the screen. The Resume method restarts redraws on the screen for the given Control.
The GetScrollPoint method gets the actual Point where the scroll caret is located. The SetScrollPoint puts the scroll caret at the given point.
How to use these methods? First, given a Control you need to stop autoscroll, make the call to Suspend, then to GetScrollPoint, (make what you need to do with the control, like highlight or append text) then SetScrollPoint and finally Resume.
In my case, I wanted to copy the entire line of a RichTextBox at any time when the cursor moves from line to line. (Doing so produce a scroll on long lines).
This is my working method:
private int intLastLine = -1;
private void richTextBoxSwitch_SelectionChanged(object sender, EventArgs e)
{
try
{
if (this.richTextBoxSwitch.TextLength > 0)
{
ControlBehavior.Suspend(this.richTextBoxSwitch);
Point point = ControlBehavior.GetScrollPoint(this.richTextBoxSwitch);
int intSelectionStartBackup = this.richTextBoxSwitch.SelectionStart;
int intSelectionLengthBackup = this.richTextBoxSwitch.SelectionLength;
int intCharIndex = this.richTextBoxSwitch.GetFirstCharIndexOfCurrentLine();
int intLine = this.richTextBoxSwitch.GetLineFromCharIndex(intCharIndex);
this.richTextBoxSwitch.SuspendLayout();
if (intLastLine != intLine)
{
intLastLine = intLine;
int intLength = this.richTextBoxSwitch.Lines[intLine].Length;
this.richTextBoxSwitch.Select(intCharIndex, intLength);
this.richTextBoxSwitch.BackColor = ColorMessageBackground;
strData = this.richTextBoxSwitch.SelectedText;
this.textBoxMessageSelected.Text = strData.Trim();
this.richTextBoxSwitch.Select(intSelectionStartBackup, intSelectionLengthBackup);
}
this.richTextBoxSwitch.ResumeLayout();
ControlBehavior.SetScrollPoint(this.richTextBoxSwitch, point);
ControlBehavior.Resume(this.richTextBoxSwitch);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
Hope this helps!

Create ListView ScrollBar Appeared Event

I have a ListView in which i want to create an event when the VScrollBar appears. I actully dont want a horizontal scrollbar and whenever the VScrollbar appears i want to resize the columns so that it fits the window. I already can check for the visiblity of a scrollbar but i dont know the name of the event which is triggered when the ScrollBars appear.
Here is my code :
private const int WS_VSCROLL = 0x200000;
private const int GWL_STYLE = -16;
[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hWnd, int Index);
private static bool IsScrollbarVisible(IntPtr hWnd)
{
bool bVisible = false;
int nMessage = WS_VSCROLL;
int nStyle = GetWindowLong(hWnd, GWL_STYLE);
bVisible = ((nStyle & nMessage) != 0);
return bVisible;
}
And Works Like this :
if (IsScrollbarVisible(listview.Handle))
{
columnHeader1.Width = listview.ClientRectangle.Width - (columnHeader2.Width + columnHeader3.Width);
}
Someone Please Help Me!
ClientSizeChanged Event will fire but to get it work correct we have to add BeginUpdate() and EndUpdate()..
This Code does everything :
private void listview_ClientSizeChanged(object sender, EventArgs e)
{
listview.BeginUpdate();
if (IsScrollbarVisible(listview.Handle))
{
columnHeader1.Width = listview.ClientRectangle.Width - (columnHeader2.Width + columnHeader3.Width);
}
listview.EndUpdate();
}

How to hide the vertical scroll bar in a .NET ListView Control in Details mode

I've got a ListView control in Details mode with a single column. It's on a form that is meant to only be used with the keyboard, mostly with the up/down arrows for scrolling and enter to select. So I don't really need to have the scroll bars and would just like them to not show for a cleaner look. However, when I set the ListView.Scrollable property to false, I can still move the selected item up and down, but as soon as it moves to an item not currently in view, the list won't move to show that item. I've tried using EnsureVisible to programmatically scroll the list, but it does nothing when in this mode.
Is there any way to manually move the list up and down to scroll, but without having the scrollbar present?
It's not easy but it can be done. If you try to hide the scroll bar through ShowScrollBar, the ListView will simply put it back again. So you have to do something more devious.
You will have to intercept the WM_NCCALCSIZE message, and in there, turn off the vertical scroll style. Whenever the listview tries to turn it on again, you will turn it off again in this handler.
public class ListViewWithoutScrollBar : ListView
{
protected override void WndProc(ref Message m) {
switch (m.Msg) {
case 0x83: // WM_NCCALCSIZE
int style = (int)GetWindowLong(this.Handle, GWL_STYLE);
if ((style & WS_VSCROLL) == WS_VSCROLL)
SetWindowLong(this.Handle, GWL_STYLE, style & ~WS_VSCROLL);
base.WndProc(ref m);
break;
default:
base.WndProc(ref m);
break;
}
}
const int GWL_STYLE = -16;
const int WS_VSCROLL = 0x00200000;
public static int GetWindowLong(IntPtr hWnd, int nIndex) {
if (IntPtr.Size == 4)
return (int)GetWindowLong32(hWnd, nIndex);
else
return (int)(long)GetWindowLongPtr64(hWnd, nIndex);
}
public static int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong) {
if (IntPtr.Size == 4)
return (int)SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
else
return (int)(long)SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
}
[DllImport("user32.dll", EntryPoint = "GetWindowLong", CharSet = CharSet.Auto)]
public static extern IntPtr GetWindowLong32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", CharSet = CharSet.Auto)]
public static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
public static extern IntPtr SetWindowLongPtr32(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)]
public static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, int dwNewLong);
}
This will give you a ListView without scroll bars that still scrolls when you use the arrow keys to change selection.
i did something more easy. i left scrollable to true and used a custom slider(colorSlider) that i found on codeproject and i drawed the slider over the position where the vscroller would appear and then used the ensureVisible function.
Call the ShowScrollBar API method.
If ShowScrollBar doesn't work, I'm not sure how to do it.
You could put the ListView in a panel and make the ListView wider than the panel so that the scrollbar is cut off (check SystemInformation.VerticalScrollBarWidth), but that's a horrifyingly ugly hack.
Since ShowScrollBar didn't work, maybe this helps:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
private const int WM_VSCROLL = 0x115;
private const int SB_LINEDOWN = 1;
public Form1()
{
InitializeComponent();
for (int i = 0; i < 100; i++)
listView1.Items.Add("foo" + i);
listView1.Scrollable = false;
}
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
SendMessage(listView1.Handle, WM_VSCROLL, SB_LINEDOWN, 0);
}
You can use ListView.Scrollable Property. Set it to false and Scroll bars won't appear!

Categories