I have a form with a menu and a toolstrip at the top. The menuStrip has a nice looking gradient background, how can I get the same effect on the toolStrip control? I know about the RenderMode property but changing this doesn't have the desired result.
You can achieve this with a custom renderer.
public class CustomToolStripRenderer : ToolStripProfessionalRenderer
{
public CustomToolStripRenderer() { }
protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
{
//you may want to change this based on the toolstrip's dock or layout style
LinearGradientMode mode = LinearGradientMode.Horizontal;
using (LinearGradientBrush b = new LinearGradientBrush(e.AffectedBounds, ColorTable.MenuStripGradientBegin, ColorTable.MenuStripGradientEnd, mode))
{
e.Graphics.FillRectangle(b, e.AffectedBounds);
}
}
}
Then set your toolstrip to use an instance of this renderer.
public Form1()
{
InitializeComponent();
CustomToolStripRenderer r = new CustomToolStripRenderer();
r.RoundedEdges = false;
toolStrip1.Renderer = r;
}
Related
I have created a Windows Forms Custom Control inheriting from class Button in order to get a round button:
public partial class RoundButton : Button
{
public RoundButton()
{
InitializeComponent();
Width = 16;
Height = 16;
FlatStyle = FlatStyle.Flat;
FlatAppearance.BorderSize = 0;
BackColor = SystemColors.ControlDark;
}
public sealed override Color BackColor
{
get => base.BackColor;
set => base.BackColor = value;
}
protected override void OnPaint(PaintEventArgs pe)
{
GraphicsPath grPath = new GraphicsPath();
grPath.AddEllipse(0, 0, ClientSize.Width, ClientSize.Height);
Region = new Region(grPath);
base.OnPaint(pe);
}
}
When I add the RoundButton control to a form in the designer its property Text is automatically assigned a value (roundButton1). I have tried to "clear" the property in the constructor, but that doesn't work:
Text = string.Empty;
How do I make sure that the property Text has no value when adding the control in the designer? I don't want to "clear" the property in the Properties window in the designer. The property should be "cleared" by default when added in the designer.
I'm developing a Windows Desktop Application using C# in VS 2022 on Windows 10. I'm developing for a touch screen and want the UI to be very intuitive and give good feedback because the user(s) will likely be tech-averse. On several of the forms I'm using a PictureBox as a button because I like the visual effects better. I can get a nice "button pressed" effect by using the MouseDown and MouseUp events to change the border style of the PictureBox to Fixed3D (on mouse down) and back to None (on mouse up). The only issue is that the PictureBox image "blinks" when I do this, like the control is clearing the image out and reloading it or something.
My code is rather trivial, but I'll post it here anyway just in case:
private void Button_Down(object sender, MouseEventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.BorderStyle = BorderStyle.Fixed3D;
}
private void Button_Up(object sender, MouseEventArgs e)
{
PictureBox pb = (PictureBox)sender;
pb.BorderStyle = BorderStyle.None;
}
If you're open to solving your blinking problem another way, consider this reusable CustomButton class that lets you use your own custom image to depict the 3D pressed state. The icons are superimposed using the Text property and a custom font containing glyphs (making it easy to change their size and color). When the button is not pressed, system theme takes over or you could unset the UseVisualStyleBackColor property to additionally customize things like OnMouseHover.
CustomButton inherits from Buttonand has a PrivateFontCollection giving it access to a .ttf file containing glyphs. This particular flashlight-filter-history-favorite-search.ttf is one I designed for my own project using the Fontello open-source icon font generator.
public CustomButton()
{
UseCompatibleTextRendering = true;
TextAlign = ContentAlignment.MiddleCenter;
refCount++;
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
if (!DesignMode) initFont();
}
private void initFont()
{
if (privateFontCollection == null)
{
privateFontCollection = new PrivateFontCollection();
var path = Path.Combine(Path.GetDirectoryName(
Assembly.GetEntryAssembly().Location),
"Fonts",
"flashlight-filter-history-favorite-search.ttf");
privateFontCollection.AddFontFile(path);
var fontFamily = privateFontCollection.Families[0];
GlyphFontUp = new Font(fontFamily, 16F);
GlyphFontDown = new Font(fontFamily, 15F);
}
Font = GlyphFontUp;
ForeColor = GlyphColorUp;
}
PrivateFontCollection privateFontCollection = null;
public static Font GlyphFontUp { get; private set; } = null;
public static Font GlyphFontDown { get; private set; } = null;
public static Color GlyphColorUp { get; } = Color.Teal;
public static Color GlyphColorDown { get; } = Color.DarkCyan;
private static int refCount = 0;
protected override void Dispose(bool disposing)
{
if (disposing)
{
refCount--;
if (refCount == 0)
{
GlyphFontUp?.Dispose();
privateFontCollection?.Dispose();
}
}
base.Dispose(disposing);
}
When the mouse is down the button has an image, the icon is smaller, and the icon color changes. When the mouse comes up the image is removed and everything goes back to normal.
partial class CustomButton : Button
{
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
Image = new Bitmap(Resources.buttonDown, Size);
Font = GlyphFontDown;
ForeColor = GlyphColorDown;
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
Font = GlyphFontUp;
ForeColor = GlyphColorUp;
Image = null;
}
}
The buttonDown image is just something I drew myself. I'm pretty sure you could do better!
The CustomButton class can be swapped out in the MainForm.Designer.cs file.
// private System.Windows.Forms.Button customButton0;
private intuitive_buttons.CustomButton customButton0;
This code assigns the various icons to the buttons:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
// Assign the icons to the buttons
customButton0.Text = "\uE800";
customButton1.Text = "\uE801";
customButton2.Text = "\uE802";
customButton3.Text = "\uE803";
customButton4.Text = "\uE804";
}
}
Hope this at least gives you a few ideas to try.
I want my ToolStrip Background to change when an Item is not saved.
To render the background of my toolstrip I use my own renderer:
class ToolStripRenderer : ToolStripProfessionalRenderer
{
private MenuBarForm parent;
public ToolStripRenderer(MenuBarForm Parent)
{
parent = Parent;
}
protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
{
if (parent.controlItems.Last().Unsaved)
e.Graphics.FillRectangle(new System.Drawing.Drawing2D.LinearGradientBrush(e.ToolStrip.ClientRectangle, SystemColors.ControlLightLight, Color.Red, 90, true), e.AffectedBounds);
else
e.Graphics.FillRectangle(new System.Drawing.Drawing2D.LinearGradientBrush(e.ToolStrip.ClientRectangle, SystemColors.ControlLightLight, SystemColors.ControlDark, 90, true), e.AffectedBounds);
}
}
The first time the toolstrip renders it renders correctly with a grey to dark grey design:
But when the bar should become red, only the buttons which the mouse hovers over become red:
I would like the whole toolstrip the be red-colored at once.
I already tried changing e.AffectedBounds to e.ToolStrip.Bounds, to no avail.
You can create a custom color table inheriting ProfessionalColorTable and override relevant properties to change background color:
public class CustomColorTable : ProfessionalColorTable
{
public override Color ToolStripGradientBegin
{
get { return Color.Red; }
}
public override Color ToolStripGradientMiddle
{
get { return Color.Red; }
}
public override Color ToolStripGradientEnd
{
get { return SystemColors.ControlLightLight; }
}
}
To change your ToolStrip background, assign a new ToolStripProfessionalRenderer which uses your custom color table to ToolStripManager.Renderer:
ToolStripManager.Renderer = new ToolStripProfessionalRenderer(new CustomColorTable());
To set the original professional renderer:
ToolStripManager.Renderer = new ToolStripProfessionalRenderer();
I Found this solution Thanks to FSDaniel comment:
By adding Invalidate() to the end of the OnRenderToolStripBackground the toolstrip did indeed become fully red but also caused the application to go into a infinite loop. I solved this by creating an event that was triggered by changing the UnSaved property. The form that has the toolstrip then subscribed a method to this event which called toolstrip.Invalidate(). This way Invalidate() is only used when necessary.
Why tooltip, displayed manually with ToolTip.Show, is not shown, when window, containing control, is inactive?
public class MyControl : Button
{
private _tip;
public string ToolTip
{
get { return _tip; }
set { _tip = value; }
}
private ToolTip _toolTip = new ToolTip();
public MyControl()
{
_toolTip.UseAnimation = false;
_toolTip.UseFading = false;
_toolTip.ShowAlways = true;
}
protected override void OnMouseHover(EventArgs e)
{
_toolTip.Show(_tip, this, 0, Height);
base.OnMouseHover(e);
}
protected override void OnMouseLeave(EventArgs e)
{
_toolTip.Hide(this);
base.OnMouseLeave(e);
}
}
I went for ToolTip.Show because I must have tooltip onscreen for unlimited time, which is not possible with normal ToolTip. I also love the idea of having tooltip text as a part of control itself. But unfortunately, when showing tooltip this way for inactive window (despite ShowAlways = true), it simply doesn't work.
The OnMouseHower event is rised, but _toolTip.Show does nothing.. unless window is activated, then everything works.
Bounty
Adding bounty for a solution to display tooltip for an inactive form (preferably with solution when tooltip text is a property of control, not IContainer).
There is a private method that does what you want, so to access it, you would have to use reflection to call it:
using System.Reflection;
public class MyControl : Button {
private ToolTip toolTip = new ToolTip() {
UseAnimation = false,
UseFading = false
};
public string ToolTip { get; set; }
protected override void OnMouseHover(EventArgs e) {
base.OnMouseHover(e);
Point mouse = MousePosition;
mouse.Offset(10, 10);
MethodInfo m = toolTip.GetType().GetMethod("SetTool",
BindingFlags.Instance | BindingFlags.NonPublic);
m.Invoke(toolTip, new object[] { this, this.ToolTip, 2, mouse });
}
protected override void OnMouseLeave(EventArgs e) {
base.OnMouseLeave(e);
toolTip.Hide(this);
}
}
The tip will display on an inactive window and it will stay on the screen indefinitely until the mouse moves off the control.
Two sample TextBoxes in a standard color scheme and the following constructor yield Box1 with a gray foreground and Box2 with a black foreground, since Box2's foreground color has been explicitly set.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Box2.Foreground = Brushes.Black;
Box1.IsEnabled = false;
Box2.IsEnabled = false;
}
}
I would like to "unset" the foreground color so Box2 "falls back" to the default disabled color and has a gray foreground when IsEnabled is set to false. Is this possible? If so, how is it done?
Setting the Foreground property to null does not have the desired effect. I want to avoid explicitly setting the Foreground color to Gray if possible, since it would not compatible with customized color schemes.
I am not sure if that's what you mean, but try following code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Box2.Foreground = Brushes.Black;
Box1.IsEnabled = false;
Box2.IsEnabled = false;
Box2.ClearValue(TextBox.ForegroundProperty);
}
}
Use the event IsEnabledChanged to set the foreground of the box.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Box2.Foreground = Brushes.Black;
Box1.IsEnabled = false;
Box2.IsEnabled = false;
Box1.IsEnabledChanged += new DependencyPropertyChangedEventHandler(label1_IsEnabledChanged);
}
void label1_IsEnabledChanged( object sender, DependencyPropertyChangedEventArgs e ) {
//Set the foreground you want here!
}
}
But if you don't want to explicit set the color, try to set it to Transparent o.O