C# WinForms TabStrip control: no accelerator - c#

I am using a tab strip control on a WinForms form. I make use of keyboard accelerators as much as possible. When I set the Text property of a TabPage to e.g. &Documents, the text on the tab is literally &Documents instead of the letter D being underlined.
The help about TabStrip and TabPage doesn't cover this topic. The property ShowKeyboardCues is read-only. Google is helpless.
Can anyone give me a hint how to show accelerators?

How can I set up keyboard shortcuts for a Windows Forms TabControl? gives tips on setting up keyboard shortcuts for it.. In terms of showing an accelerator though, you'll have to draw them yourself
Set the tabControl's DrawMode to OwnerDrawFixed then do some code to draw the tabs, for example (I had to try hard to make it this ugly)
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
//Change appearance of tabcontrol
Brush backBrush = Brushes.Red;
Brush foreBrush = Brushes.Blue;
e.Graphics.FillRectangle(backBrush, e.Bounds);
Rectangle r = e.Bounds;
r = new Rectangle(r.X, r.Y + 3, r.Width, r.Height - 3);
e.Graphics.DrawString("my label", e.Font, foreBrush, r);
var sz = e.Graphics.MeasureString("my ", e.Font);
e.Graphics.DrawString("_", Font, foreBrush, r.X + sz.Width - 2, r.Y + 2);
}
Joking aside, setting up some ugly colors does help you see where the bounds of the drawing area are etc. I'm sure you'll tart it up..

Neither of these controls supports that functionality. It is possible to simulate it, but it is a long and complicated task that I would not recommend because it is non-standard functionality. As a result it is unlikely that anyone would expect it to occur. On the other hand, changing tabs using Ctrl+Tab is standard behaviour so is already automatically supported.
If you did want to do this, you would need to:
Subclass the Control
Override the painting and draw the text on the tab yourself
Get a preview of the keydown event and use that to determine if the key combination you wanted was pressed
Select the correct tab programmatically based on the keypress that you have intercepted
As I say, I would not recommend this because it is not normal behaviour for that control and because the complexity means that it is likely to be buggy. But it is possible...

Related

how to use a textbox but having an underscore line and blinking cursor?

I've created Windows forms and I'm using the textbox control for input, but I like to use it without border and other layout for textbox etc. I just want to use a underscore line and blinking cursor.
I played with the borderStyle (Fixed3D, None), backcolor=InactiveBorder etc. But I still do net get the underline... like this-> _____________ result like this: This is underline______________
I think Backcolor=InactiveBorder and BorderStyle=None is ok to use, but how to get the underline and blinking cursor?
Requirement:
blinking cursor and underline. (The doesn't blink by default, I just see a vertical line))
To fake this, you could add a label below the text box with the content being _____________________. My preferred solution would be to create a simple custom control that just draws a line.
Doesn't the caret on your system blink by default? It does on my system if the focus is on the text box.
If the caret doesn't blink by default, go to the Windows Control Panel and check your Keyboard Settings there - this is the place where you can adjust the caret blink rate.
For creating a underline for your textbox you can do like this,
First add a panel which is in the height of text box's height + underline's height.
Now add your textbox inside of that panel and set its dock to TOP.
Then set the textbox's border to none.
Now set the backcolor of the panel, according to the color need of underline.
Update:
This is VB code, i hope that you can easily convert it into c#
[ Concept: You just need to set the border for all of your textboxes as none.then In forms paint event track those text boxes and draw a line under it. ]
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles Me.Paint
Using xPen As Pen = New Pen(Color.Blue)
' Here we are using LINQ to filter the controls.
' If you don't want it, you just check all the controls by using typeof
' inside the For Each loop.
For Each xTxtBox In Me.Controls.OfType(Of TextBox)()
e.Graphics.DrawLine(xPen,
xTxtBox.Location.X,
xTxtBox.Location.Y + xTxtBox.Height,
xTxtBox.Location.X + xTxtBox.Width,
xTxtBox.Location.Y + xTxtBox.Height)
Next
End Using
End Sub
Use Masked TextBox and set Focus , e.g. maskedtextbox1.Focus(); <== this is for the blinking cursor and the masked textbox to the underline !
try :
To set logical focus to an input control
FocusManager.SetFocusedElement(this, textboxJack);
To set keyboard focus to an input control
Keyboard.Focus(textboxJill);
and for the masked textbox you can set a mask that will not be changed when you delete the text from it not like the simple textbox :)
Good luck
To do this, I would recommend creating a custom control (which is accomplished in the WinForms world by inheriting from one of the provided control classes). That custom control would then:
Provide its own drawing logic (by overriding OnPaint) in order to draw the underline and skip drawing anything else you don't want to see (e.g., the borders of the control).
Create its own caret when it receives the focus, and destroy that caret when it loses the focus. You'll find all the details on how to do this in my answer here.
You can also configure the blink rate of the caret by calling the SetCaretBlinkTime function. But note that this is not recommended, as it changes the global system setting and therefore affects other applications. It is best to do as Thorsten suggests and modify the setting on your machine if you wish to see something different. You should always respect a user's settings. There's a reason that they (or someone else) set up their system to not blink the caret.
Naturally, you will need to use P/Invoke to call these Win32 API functions related to caret management from a C# application. That shouldn't be too difficult if you know what you're doing. If you need a complete solution, consider setting a bounty on this question to persuade me to write one up for you.
I faced the same issue and built something that works fine:
public class TextBox : System.Windows.Forms.TextBox
{
public TextBox()
{
BorderStyle = BorderStyle.None;
Text = "__________"; //Sometime this doesn't work while creating the control in design mode ; don't know why
}
//protected override void OnFontChanged(EventArgs e)
//{
// base.OnFontChanged(e);
// RefreshHeight();
//}
bool loaded = false;
protected override void OnCreateControl()
{
if(!loaded)
RefreshHeight();
base.OnCreateControl();
}
private void RefreshHeight()
{
loaded = true;
Multiline = true;
Size s = TextRenderer.MeasureText(Text, Font, Size.Empty, TextFormatFlags.TextBoxControl);
MinimumSize = new Size(0, s.Height + 1);
Multiline = false;
}
}
I used bool loaded = false to avoid the app to crash in a loop because of OnCreateControl. TextBox control doesn't have OnLoad event (I'm open to another approach).
OnFontChanged can be uncommented if your app change the font size in run time
MinimumSize = new Size(0, s.Height + 1); I added 1 to avoid any error of MeasureText

How to make part of ListViewItem text to be bold?

I have a ListView in Details mode, and I'd like to have some of its items' text in bold (for highlighting where it finds some substring in the item text).
So something like this:
Somefilename/boldText/etc
Is there any way to do that?
Okay, so this is going to be difficult because you're going to have to OwnerDraw your ListView first by setting that property to true. Now that you've done that you're going to need to implement DrawColumnHeader and place this line in it:
e.DrawDefault = true;
Next you'll need to implement the following code, either in DrawItem or DrawSubItem depending on which area it exists in. Keep in mind the code I'm giving you isn't fully complete because it's not parsing the string or anything and further you still need to implement drawing a selected item now because your drawing the text on your own.
var boldFont = new Font(this.Font, FontStyle.Bold);
var location = new PointF(e.Bounds.Location.X, e.Bounds.Location.Y);
e.Graphics.DrawString("Somefilename/", this.Font, Brushes.Black, location);
var size = e.Graphics.MeasureString("Somefilename/", this.Font);
location.X += size.Width;
e.Graphics.DrawString("boldText", boldFont, Brushes.Black, location);
size = e.Graphics.MeasureString("boldText", boldFont);
location.X += size.Width;
e.Graphics.DrawString("/etc", this.Font, Brushes.Black, location);
Another thing to note is that you'll have to play with the offsets a little because some fonts have margins and bolded fonts take up more room.
If the Item is not a SubItem then just implement the e.DrawDefault = true; for the DrawSubItem event - and vica versa if the item is a SubItem then implement that line for DrawItem.
You'll have to override OnPaint. Try these links:
Make portion of a Label's Text to be styled bold
Custom ListView in Winforms?
But, the listview is not painted by the .net framework and is only supported. So, even if you override the OnPaint, it might not be called. So you might have to override your listview control as well.

Change Border of ToolStripComboBox with Flat Style

I would like to be able to change the border color of ToolStripComboBox controls in some of my toolstrips, since the default border color of ComboBoxes when used with flat styling is SystemColors.Window, which is basically invisible against the default control color of the toolstrip. After a lot of digging around in Reflector, I don't see any obvious way to do this, since all the infrastructure behind ComboBox rendering is highly protected behind internal and private interfaces.
Outside of ToolStrips, a common solution I've seen proposed for fixing border color on ComboBoxes is to subclass ComboBox, override WndProc, and manually paint the border. This can't work for ToolStripComboBox controls since the internal ComboBox control is its own private subclass of ComboBox, with no way that I can see to replace the instance of the control.
An alternative solution I'm considering is putting one of the extended ComboBox objects into a ToolStripControlHost, which allows me to draw a border, but then I have to give up some of the professional renderer tweaks. A secondary drawback I've noticed is that I get occasional flicker during mouseover.
Switching my design to WPF is not an acceptable solution. Wrapping controls in parent controls for drawing borders is also not acceptable, as this gains nothing over the ToolStripControlHost alternative.
Does anyone have a clever solution to defeat this problem, or is there an existing (permissively-licensed) re-implementation of the ComboBox flat-style rendering stack out in the wild, which fixes some of the shortcomings in the existing implementation?
Here's a way to make it work ... sort of :)
Create an event handler for the Paint event of the ToolStrip. Then loop through all of the ToolStripComboBoxes and paint a rectangle around them.
private Color cbBorderColor = Color.Gray;
private Pen cbBorderPen = new Pen(SystemColors.Window);
private void toolStrip1_Paint(object sender, PaintEventArgs e)
{
foreach (ToolStripComboBox cb in toolStrip1.Items)
{
Rectangle r = new Rectangle(
cb.ComboBox.Location.X - 1,
cb.ComboBox.Location.Y - 1,
cb.ComboBox.Size.Width + 1,
cb.ComboBox.Size.Height + 1);
cbBorderPen.Color = cbBorderColor;
e.Graphics.DrawRectangle(cbBorderPen, r);
}
}
Here's what it looks like (note that you may need to adjust the Height of the ToolStrip to prevent the painted border from being cut off):
improvement:
check the type of the toolstrip item,
so the program will not crush if it is toolstipLabel for example.
foreach (var item in toolStrip1.Items)
{
var asComboBox = item as ToolStripComboBox;
if (asComboBox != null)
{
var location = asComboBox.ComboBox.Location;
var size = asComboBox.ComboBox.Size;
Pen cbBorderPen = new Pen(Color.Gray);
Rectangle rect = new Rectangle(
location.X - 1,
location.Y - 1,
size.Width + 1,
size.Height + 1);
e.Graphics.DrawRectangle(cbBorderPen, rect);
}
}
toolStrip1.ComboBox.FlatStyle = FlatStyle.System;
This sets the default, OS-styled, border around the combo box. It is a light grey and thin border on Windows 10. Although, depending on the background, this may not show. In which case, you could try the other options like FlatStyle.Popup.
If the presets aren't what you are looking for, the other answers allow you to draw a custom border. However, since the rectangle is drawn with +1 pixel size around the combo box, the border is 1 pixel larger than the combo box. Removing the +1s and -1s doesn't work either.

Visual Studio C# Windows Forms... changing button color?

I have a form (see screenshot):
As you can see, its a pretty basic form, with a save button. I have programmed it so that if any of the text fields get changed, the "SAVE" button changes color so that its obvious that I haven't clicked save and don't forget to. Unfortunately, simply changing the BackColor of the button to red isn't enough, because its UGLY as sin.
What can I do to change the color of the button to red, but not as ugly. As you can see, the "BackColor" doesn't change the entire button, just the inner piece. The border is still the same old fashioned transparent grey.
A little bit of a LinearGradientBrush can go a long way to soften the harshness of a pure red button.
button1.ForeColor = Color.White;
Bitmap bmp = new Bitmap(button1.Width, button1.Height);
using (Graphics g = Graphics.FromImage(bmp)) {
Rectangle r = new Rectangle(0, 0, bmp.Width, bmp.Height);
using (LinearGradientBrush br = new LinearGradientBrush(
r,
Color.Red,
Color.DarkRed,
LinearGradientMode.Vertical)) {
g.FillRectangle(br, r);
}
}
then you can just assign the image to the button's BackgroundImage property:
button1.BackgroundImage = bmp;
Result:
Note: Assigning a background image will lose the mouse hover coloring of the button.
Another solution would be to add an Icon (e.g. exclamation mark) to the button instead to inform the user that the changes haven't been saved yet.
There are many tutorials online on how to create nice buttons with c#. For example this one allows you to create Vista like buttons. Have a look here: http://www.codeproject.com/Articles/19318/Vista-Style-Button-in-C
For basic colors visit this SO question:
C#: Changing Button BackColor has no effect
You can just use one of the button's properties, "FlatStyle". By default, it is standard. But if you switch it to "Popup", your background color will be extended to the area of the button. You can compare the followings:
left-standard, right-popup
This won't work in WinForms, but you might want to switch over to WPF.
It's much more convenient because you can configure EVERYTHING. (Even the color of a progressbar)
Edit: The OP doesn't have to entirely rewrite his application.
He just needs to redo the layout of it, the code can be C&P'd over to the new WPF project, fyi
Edit²: You don't even need to use code to change the color of a WPF button, you can just define a red overlay with 30% opacity in the XAML file. It's that easy, really.

Is there a way to color tabs of a tabpage in winforms?

I am struggling to find a way to color the tab headers of a tabpage in WinForms. There are solutions to color the current indexed tab using the OnDrawItem event, but is it possible to color all the tabs with different colors to make them more intuitive for users for certain behavior?
Thanks in advance.
An improved version of Ash's answer:
private void tabControl_DrawItem(object sender, DrawItemEventArgs e)
{
TabPage page = tabControl.TabPages[e.Index];
e.Graphics.FillRectangle(new SolidBrush(page.BackColor), e.Bounds);
Rectangle paddedBounds = e.Bounds;
int yOffset = (e.State == DrawItemState.Selected) ? -2 : 1;
paddedBounds.Offset(1, yOffset);
TextRenderer.DrawText(e.Graphics, page.Text, e.Font, paddedBounds, page.ForeColor);
}
This code uses the TextRenderer class to draw its text (as .NET does), fixes problems with font clipping/wrapping by not negatively inflating the bounds, and takes tab selection into account.
Thanks to Ash for the original code.
Yes, there is no need for any win32 code. You just need to set the tab controls DrawMode property to 'OwnerDrawFixed' and then handle the tab control's DrawItem event.
The following code shows how:
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
// This event is called once for each tab button in your tab control
// First paint the background with a color based on the current tab
// e.Index is the index of the tab in the TabPages collection.
switch (e.Index )
{
case 0:
e.Graphics.FillRectangle(new SolidBrush(Color.Red), e.Bounds);
break;
case 1:
e.Graphics.FillRectangle(new SolidBrush(Color.Blue), e.Bounds);
break;
default:
break;
}
// Then draw the current tab button text
Rectangle paddedBounds=e.Bounds;
paddedBounds.Inflate(-2,-2);
e.Graphics.DrawString(tabControl1.TabPages[e.Index].Text, this.Font, SystemBrushes.HighlightText, paddedBounds);
}
Setting the DrawMode to 'OwnerDrawnFixed' means each tab button has to be the same size (ie Fixed).
However if you want to change the size of all tab buttons, you can set the tab control's SizeMode property to 'Fixed' and then change the ItemSize property.
Using the current tab control, if it is possible you'd need to hook a lot of win-32 events (there may be a pre-wrapped implementation out there). Another alternative would be a 3rd-party tabbed control replacement; I'm sure plenty of vendors will sell you one.
IMO, you might find it less pain to look at WPF; it is a big change, but has more control over things like this. You can host WPF inside winforms if needed (if you can't justify a full make-over, which is a pretty common reality).

Categories