How to word wrap tooltips in C# [duplicate] - c#

How to wordwrap text that need to be appear in ToolTip

It looks like it isn't supported directly:
How do I word-wrap the Tooltip that is displayed?
Here is a method using Reflection to
achieve this.
[ DllImport( "user32.dll" ) ]
private extern static int SendMessage( IntPtr hwnd, uint msg,
int wParam, int lParam);
object o = typeof( ToolTip ).InvokeMember( "Handle",
BindingFlags.NonPublic | BindingFlags.Instance |
BindingFlags.GetProperty,
null, myToolTip, null );
IntPtr hwnd = (IntPtr) o;
private const uint TTM_SETMAXTIPWIDTH = 0x418;
SendMessage( hwnd, TTM_SETMAXTIPWIDTH, 0, 300 );
Rhett Gong

Another way, is to create a regexp that wraps automatically.
WrappedMessage := RegExReplace(LongMessage,"(.{50}\s)","$1`n")
link

This is a piece I wrote recently, I know its not the best but it works. You need to extend the ToolTip Control as follows:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
public class CToolTip : ToolTip
{
protected Int32 LengthWrap { get; private set; }
protected Control Parent { get; private set; }
public CToolTip(Control parent, int length)
: base()
{
this.Parent = parent;
this.LengthWrap = length;
}
public String finalText = "";
public void Text(string text)
{
var tText = text.Split(' ');
string rText = "";
for (int i = 0; i < tText.Length; i++)
{
if (rText.Length < LengthWrap)
{
rText += tText[i] + " ";
}
else
{
finalText += rText + "\n";
rText = tText[i] + " ";
}
if (tText.Length == i+1)
{
finalText += rText;
}
}
}
base.SetToolTip(Parent, finalText);
}
}
And you will use it like:
CToolTip info = new CToolTip(Control,LengthWrap);
info.Text("It looks like it isn't supported directly. There is a workaround at
http://windowsclient.net/blogs/faqs/archive/2006/05/26/how-do-i-word-wrap-the-
tooltip-that- is-displayed.aspx:");

You can set the size of the tooltip using e.ToolTipSize property, this will force word wrapping:
public class CustomToolTip : ToolTip
{
public CustomToolTip () : base()
{
this.Popup += new PopupEventHandler(this.OnPopup);
}
private void OnPopup(object sender, PopupEventArgs e)
{
// Set custom size of the tooltip
e.ToolTipSize = new Size(200, 100);
}
}

For WPF, you can use the TextWrapping property:
<ToolTip>
<TextBlock Width="200" TextWrapping="Wrap" Text="Some text" />
</ToolTip>

Related

Stop ComboBox Autocomplete feature from happening

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);
}
}

Tabpage header stays below arrow buttons after moving

The situation is as follows, I have a custom TabControl that paints the TabHeaders itself so I can choose colors etc.
The problem occurs when I have more TabHeaders then the TabControl can fit and the arrows (spin control) appears. Whenever I then cycle all the way to the right (so there are no more headers to the right) the tabheader that was behind the arrows is still partially there.
Image to demonstrate:
What I know:
If I manually call .Invalidate() so it repaints the problem will go away, however I can't find an event that is triggered by the arrow keys (it does not have a scroll event).
Events that won't work:
Click
Layout
Resize (don't even ask)
I had WndProc in mind (it has cases with get 'spin' which sounds like the spincontrol)
Custom tab control code:
class ColoredTabControl : TabControl
{
public Color ActiveTabColor
{
get
{
return _activeTabColor.Color;
}
set
{
_activeTabColor.Color = value;
this.Invalidate();
}
}
public Color DefaultTabColor
{
get
{
return _defaultTabColor.Color;
}
set
{
_defaultTabColor.Color = value;
this.Invalidate();
}
}
private SolidBrush _activeTabColor = new SolidBrush( Color.LightSteelBlue );
private SolidBrush _defaultTabColor = new SolidBrush( Color.LightGray );
private int _biggestTextHeight = 0;
private int _biggestTextWidth = 0;
public ColoredTabControl()
{
this.SetStyle( ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true );
}
protected override void OnPaint( PaintEventArgs e )
{
base.OnPaint( e );
var graphics = e.Graphics;
TabPage currentTab = this.SelectedTab;
if( TabPages.Count > 0 )
{
var biggestTextHeight = TabPages?.Cast<TabPage>()?.Max( r => TextRenderer.MeasureText( r.Text, r.Font ).Height );
var biggestTextWidth = TabPages?.Cast<TabPage>()?.Max( r => TextRenderer.MeasureText( r.Text, r.Font ).Width );
if( biggestTextHeight > _biggestTextHeight || biggestTextWidth > _biggestTextWidth )
{
_biggestTextWidth = ( int ) biggestTextWidth;
_biggestTextHeight = ( int ) biggestTextHeight;
this.ItemSize = new Size( _biggestTextWidth + 5, _biggestTextHeight + 10 );
}
}
for( int i = 0; i < TabPages.Count; i++ )
{
TabPage tabPage = TabPages[ i ];
Rectangle tabRectangle = GetTabRect( i );
SolidBrush brush = ( tabPage == currentTab ? _activeTabColor : _defaultTabColor );
graphics.FillRectangle( brush, tabRectangle );
TextRenderer.DrawText( graphics, tabPage.Text, tabPage.Font, tabRectangle, tabPage.ForeColor );
}
}
protected override void OnPaintBackground( PaintEventArgs e )
{
base.OnPaintBackground( e );
}
}
A bit of form code to repro the issue:
var tabControl = new ColoredTabControl() { Width = 340, Height = 300, Top = 100 };
tabControl.TabPages.Add( "text" );
tabControl.TabPages.Add( "another tab");
tabControl.TabPages.Add( "yet another" );
tabControl.TabPages.Add( "another one" );
tabControl.TabPages.Add( "another" );
tabControl.DefaultTabColor = Color.Red; //To see the issue clearly
Controls.Add( tabControl );
I ended up fixing it by hooking into WndProc event handler of the msctls_updown32 class. I did this by using a Win32 class I got from a codeproject tabcontrol project by Oscar Londono I had to adjust it a bit for my needs though.
Added code in the tabcontrol:
protected override void OnSelectedIndexChanged( EventArgs e )
{
base.OnSelectedIndexChanged( e );
this.Invalidate();
}
protected override void OnControlAdded( ControlEventArgs e )
{
base.OnControlAdded( e );
FindUpDown();
}
protected override void Dispose( bool disposing )
{
if(scUpDown != null)
{
scUpDown.SubClassedWndProc -= scUpDown_SubClassedWndProc;
}
base.Dispose( disposing );
}
bool bUpDown = false;
SubClass scUpDown = null;
private void FindUpDown()
{
bool bFound = false;
// find the UpDown control
IntPtr pWnd =
Win32.GetWindow( this.Handle, Win32.GW_CHILD );
while( pWnd != IntPtr.Zero )
{
// Get the window class name
char[] fullName = new char[ 33 ];
int length = Win32.GetClassName( pWnd, fullName, 32 );
string className = new string( fullName, 0, length );
if( className == Win32.MSCTLS_UPDOWN32 )
{
bFound = true;
if( !bUpDown )
{
// Subclass it
this.scUpDown = new SubClass( pWnd, true );
this.scUpDown.SubClassedWndProc +=
new SubClass.SubClassWndProcEventHandler(
scUpDown_SubClassedWndProc );
bUpDown = true;
}
break;
}
pWnd = Win32.GetWindow( pWnd, Win32.GW_HWNDNEXT );
}
if( ( !bFound ) && ( bUpDown ) )
bUpDown = false;
}
private int scUpDown_SubClassedWndProc( ref Message m )
{
switch(m.Msg)
{
case Win32.WM_LCLICK:
//Invalidate to repaint
this.Invalidate();
return 0;
}
return 0;
}
The other part of this class is still 100% the same as in the OP
Win32 class:
internal class Win32
{
/*
* GetWindow() Constants
*/
public const int GW_HWNDFIRST = 0;
public const int GW_HWNDLAST = 1;
public const int GW_HWNDNEXT = 2;
public const int GW_HWNDPREV = 3;
public const int GW_OWNER = 4;
public const int GW_CHILD = 5;
public const int WM_NCCALCSIZE = 0x83;
public const int WM_WINDOWPOSCHANGING = 0x46;
public const int WM_PAINT = 0xF;
public const int WM_CREATE = 0x1;
public const int WM_NCCREATE = 0x81;
public const int WM_NCPAINT = 0x85;
public const int WM_PRINT = 0x317;
public const int WM_DESTROY = 0x2;
public const int WM_SHOWWINDOW = 0x18;
public const int WM_SHARED_MENU = 0x1E2;
public const int WM_LCLICK = 0x201;
public const int HC_ACTION = 0;
public const int WH_CALLWNDPROC = 4;
public const int GWL_WNDPROC = -4;
//Class name constant
public const string MSCTLS_UPDOWN32 = "msctls_updown32";
[ DllImport("User32.dll",CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hwnd, char[] className, int maxCount);
[DllImport("User32.dll",CharSet = CharSet.Auto)]
public static extern IntPtr GetWindow(IntPtr hwnd, int uCmd);
}
#region SubClass Classing Handler Class
internal class SubClass : System.Windows.Forms.NativeWindow
{
public delegate int SubClassWndProcEventHandler(ref System.Windows.Forms.Message m);
public event SubClassWndProcEventHandler SubClassedWndProc;
private bool IsSubClassed = false;
public SubClass(IntPtr Handle, bool _SubClass)
{
base.AssignHandle(Handle);
this.IsSubClassed = _SubClass;
}
public bool SubClassed
{
get{ return this.IsSubClassed; }
set{ this.IsSubClassed = value; }
}
protected override void WndProc(ref Message m)
{
if (this.IsSubClassed)
{
if (OnSubClassedWndProc(ref m) != 0)
return;
}
base.WndProc(ref m);
}
private int OnSubClassedWndProc(ref Message m)
{
if (SubClassedWndProc != null)
{
return this.SubClassedWndProc(ref m);
}
return 0;
}
}
#endregion
If anyone has a better answer or a question feel free to answer/comment!
If anyone has a way or even thoughts on how to hook into the actual scroll event of the tabcontrol please answer/comment.
If you are curious to know how to get the scroll event of the tab header when you click on those scroll buttons, you can handle WM_HSCROLL event of the TabControl:
const int WM_HSCROLL = 0x0114;
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_HSCROLL)
this.Invalidate();
}
This way you can invalidate the control after scrolling using those buttons.
Also for the cases that user changed selected tab using keyboard, you can override OnSelectedIndexChanged and after calling base method, invalidate the control.

TrackBar with Moving Percentage Label

I cobbled together a custom TrackBar with a percentage representing the current Slider position using the answers from here and here
My custom control is as follows:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.Runtime.InteropServices;
namespace CustomControls
{
public partial class TrackBarPercent : TrackBar
{
/// <summary>
/// Initializes a new instance of <see cref="TrackBarPercent"/>.
/// </summary>
public TrackBarPercent() : base()
{
InitializeComponent();
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
private Font _percentFont = SystemFonts.DefaultFont;
private Color _percentColor = Color.Black;
private SolidBrush _drawBrush = new SolidBrush(Color.Black);
/// <summary>
/// Gets or sets the font of the percent text.
/// </summary>
[Description("Gets or sets the font of the percent text.")]
[Browsable(true)]
public Font PercentFont
{
get { return _percentFont; }
set { _percentFont = value; }
}
/// <summary>
/// Gets or sets the color of the percent text.
/// </summary>
[Description("Gets or sets the color of the percent text.")]
[Browsable(true)]
public Color PercentColor
{
get { return _percentColor; }
set { _percentColor = value; _drawBrush = new SolidBrush(_percentColor); }
}
private Rectangle Slider
{
get
{
try
{
RECT rc = new RECT();
SendMessageRect(this.Handle, TBM_GETTHUMBRECT, IntPtr.Zero, ref rc);
return new Rectangle(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
}
catch
{
return new Rectangle();
}
}
}
private const int TBM_GETTHUMBRECT = 0x400 + 25;
private struct RECT { public int left, top, right, bottom; }
[DllImport("user32.dll", EntryPoint = "SendMessageW")]
private static extern IntPtr SendMessageRect(IntPtr hWnd, int msg, IntPtr wp, ref RECT lp);
private int lastValue = 0;
protected override void WndProc(ref Message m)
{
try
{
base.WndProc(ref m);
if (m.Msg == 0x0F)
{
if (this.Value != lastValue)
{
lastValue = this.Value;
this.Invalidate();
}
using (Graphics graphics = Graphics.FromHwnd(Handle))
{
DrawPercentText(graphics);
}
}
}
catch { }
}
private void DrawPercentText(Graphics g)
{
try
{
Point pctTxtPoint;
if (this.Orientation == System.Windows.Forms.Orientation.Horizontal)
{
pctTxtPoint = new Point((Slider.Left + Slider.Right) / 2, Slider.Bottom);
}
else
{
pctTxtPoint = new Point(Slider.Right + 5, Slider.Top - 2);
}
double percent = (double)this.Value * 100.0 / (double)this.Maximum;
string pctStr = string.Format("{0:0.##}%", percent);
g.DrawString(pctStr, _percentFont, _drawBrush, pctTxtPoint);
}
catch { }
}
[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);
}
}
}
This works, for the most part, but the text gets redrawn every time I hover my mouse over the slider causing the text to look bold. This effect goes away when another control gets focus. Additionally, I'm getting periodic exceptions thrown by the control that I do not understand.
I keep track of the last value that was set for this control so that it invalidates the view if the value has changed. I needed this to prevent the control from drawing the percentage text over the previous text. I don't think this approach was very elegant but I'm not sure how to go about doing it better.
How can I fix this code up so that the text doesn't become "bold" and fix the exceptions I'm getting?

Setting value of a textfield to not go lower than zero

How do i set a textfield so it cant go lower than 0?
If you are using Windows Forms you can simply use the NumericUpDown, it also exposes Minimum and Maximum value fields.
If for some reason you will need to roll your own, you will probably need to attach yourself to the event which is fired when the text is changed. If the content of the text field is numeric and is lower than 0, then simply override the text with 0 or whatever value you wish to provide.
win form code :-
private void btnArrowUp_Click(object sender, EventArgs e)
{
int val = 0;
if (Convert.ToInt32(textBoxValue.Text) <= 1000) //convert the textBox value to integer and check for your Upper Limit (here i have set it to 1000)
{
// if so, increment by your step (i used 1)
val = Convert.ToInt32(textBoxValue.Text);
val += 1;
textBoxValue.Text = val.ToString();
labelErrorMessage.Visible = false;
}
else
{
// otherwise, give a message and reset to your Default (i used 0)
textBoxValue.Text = "0";
labelErrorMessage.Text = "1000 (Zero) is the Max limit !";
labelErrorMessage.Visible = true;
}
}
private void btnArrowDown_Click(object sender, EventArgs e)
{
int val = 0;
if (Convert.ToInt32(textBoxValue.Text) > 0) //convert the textBox value to integer and check for your Lower Limit (here i have set it to 0)
{
// if so, decrement by your step (i used 1)
val = Convert.ToInt32(textBoxValue.Text);
val -= 1;
textBoxValue.Text = val.ToString();
labelErrorMessage.Visible = false;
}
else
{
// otherwise, give a message and reset to your Default (i used 0)
textBoxValue.Text = "0";
labelErrorMessage.Text = "0 (Zero) is the lowest limit !";
labelErrorMessage.Visible = true;
}
}
Use NumericUpDown instead of text field and set Minimum = 0 or follow this
Add Balloon.cs
public enum TooltipIcon
{
None,
Info,
Warning,
Error
}
public class Balloon
{
private Control m_parent;
private string m_text = "FMS Balloon Tooltip Control Display Message";
private string m_title = "FMS Balloon Tooltip Message";
private TooltipIcon m_titleIcon = TooltipIcon.None;
private const int ECM_FIRST = 0x1500;
private const int EM_SHOWBALLOONTIP = ECM_FIRST + 3;
[DllImport("User32", SetLastError = true)]
private static extern int SendMessage(
IntPtr hWnd,
int Msg,
int wParam,
IntPtr lParam);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct EDITBALLOONTIP
{
public int cbStruct;
public string pszTitle;
public string pszText;
public int ttiIcon;
}
public Balloon()
{
}
public Balloon(Control parent)
{
m_parent = parent;
}
public void Show()
{
EDITBALLOONTIP ebt = new EDITBALLOONTIP();
ebt.cbStruct = Marshal.SizeOf(ebt);
ebt.pszText = m_text;
ebt.pszTitle = m_title;
ebt.ttiIcon = (int)m_titleIcon;
IntPtr ptrStruct = Marshal.AllocHGlobal(Marshal.SizeOf(ebt));
Marshal.StructureToPtr(ebt, ptrStruct, false);
System.Diagnostics.Debug.Assert(m_parent != null, "Parent control is null", "Set parent before calling Show");
int ret = SendMessage(m_parent.Handle, EM_SHOWBALLOONTIP, 0, ptrStruct);
Marshal.FreeHGlobal(ptrStruct);
}
public void Show(string text, Control parent, string title, TooltipIcon icon)
{
}
public string Title
{
get
{
return m_title;
}
set
{
m_title = value;
}
}
public TooltipIcon TitleIcon
{
get
{
return m_titleIcon;
}
set
{
m_titleIcon = value;
}
}
public string Text
{
get
{
return m_text;
}
set
{
m_text = value;
}
}
public Control Parent
{
get
{
return m_parent;
}
set
{
m_parent = value;
}
}
}
Add the following code to your Form
private readonly Balloon _balloonTip = new Balloon();
public Form1()
{
InitializeComponent();
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = HandledNumerics(sender, e);
}
private bool HandledNumerics(object sender, KeyPressEventArgs e)
{
var handled = !(Char.IsDigit(e.KeyChar) || (e.KeyChar == (char)Keys.Back) || (e.KeyChar == (char)Keys.Delete));
if (handled)
{
ShowBalloon("Warning", "Invalid Input!\nOnly numeric value is acceptable", (TextBox)sender);
}
return handled;
}
private void ShowBalloon(string title, string text, Control parent, TooltipIcon icon = TooltipIcon.Warning)
{
_balloonTip.Title = title;
_balloonTip.Text = text;
_balloonTip.Parent = parent;
_balloonTip.TitleIcon = icon;
_balloonTip.Show();
}
And get the result just like
simple way, just create a funcion that verifies is the value is bellow 0 and call it when the text changes, or in your down_click function if the text field is locked to keybord input.
private void bellowZero()
{
if (Convert.ToInt32(textBox1.Text) < 0)
{
textBox1.Text = "0";
}
}

How do I control two listboxes using a Vertical Scrollbar?

I've got a Windows Form that has 6 listboxes in it.
I'm trying to find / make a code that would make them scroll together. So I dropped a Vertical Scroll Bar onto the form, then put in the following code:
private void vScrollR_Scroll(object sender, ScrollEventArgs e)
{
int i = vScrollR.Value;
lstcr1.SelectedIndex = i;
lstpr1.SelectedIndex = i;
lstsr1.SelectedIndex = i;
lstcr2.SelectedIndex = i;
lstpr2.SelectedIndex = i;
lstsr2.SelectedIndex = i;
}
For some reason though, it won't work (i always returns 0). Am I going about this the wrong way? Is there any other way to achieve what I want? Perhaps, there's a method I need first?
Many thanks to all who will answer.
Change SelectedIndex to TopIndex. I just tried this and it works.
To keep the UI in sync while updating, you can use Control.BeginUpdate and Control.EndUpdate
listBox1.BeginUpdate();
listBox2.BeginUpdate();
listBox1.TopIndex =
listBox2.TopIndex = ++x;
listBox1.EndUpdate();
listBox2.EndUpdate();
Try to Create a Separate Class that Inherits from Listbox.
I hope that this will help you.
using System;
using System.Windows.Forms;
public class myScrollingListBox : ListBox
{
// Event declaration
public delegate void myScrollingListBoxDelegate(object Sender, myScrollingListBoxScrollArgs e);
public event myScrollingListBoxDelegate Scroll;
// WM_VSCROLL message constants
private const int WM_VSCROLL = 0x0115;
private const int SB_THUMBTRACK = 5;
private const int SB_ENDSCROLL = 8;
protected override void WndProc(ref Message m)
{
// Trap the WM_VSCROLL message to generate the Scroll event
base.WndProc(ref m);
if (m.Msg == WM_VSCROLL)
{
int nfy = m.WParam.ToInt32() & 0xFFFF;
if (Scroll != null && (nfy == SB_THUMBTRACK || nfy == SB_ENDSCROLL))
Scroll(this, new myScrollingListBoxScrollArgs(this.TopIndex, nfy == SB_THUMBTRACK));
}
}
public class myScrollingListBoxScrollArgs
{
// Scroll event argument
private int mTop;
private bool mTracking;
public myScrollingListBoxScrollArgs(int top, bool tracking)
{
mTop = top;
mTracking = tracking;
}
public int Top
{
get { return mTop; }
}
public bool Tracking
{
get { return mTracking; }
}
}
}

Categories