How to take away vertical space for programmatically added menu? - c#

I add a MenuStrip to my form and I would like to add other controls below it like usual Point(0, 0) is the top left corner of empty form space. After I add the menu to my form and add more controls they overlap each other. So I want to take away some height of the client rect for the menu and a button with Location = (0,0) must be RIGHT below the menu.
How do I do that ?
If I assign a MainMenu to Menu property of the form it does that automatically but I really want and need to use MenuStrip.
Edit: this doesn't work:
MenuStrip menu = new MenuStrip();
menu.Items.Add("File");
menu.AutoSize = false;
menu.Height = 50;
menu.Dock = DockStyle.Top;
MainMenuStrip = menu;
Controls.Add(menu);
Button b = new Button();
b.Text = "hello world";
b.SetBounds(0, 25, 128, 50);
Controls.Add(b);
While this works like I would like it to do with MenuStrip:
Menu = new MainMenu();
Menu.MenuItems.Add("File");
Button b = new Button();
b.Text = "hello world";
b.SetBounds(0, 0, 128, 50);
Controls.Add(b);

When you SetBounds(0, 25, 128, 50), you are actually setting b.Top to 25 (the second parameter). In order to set the top bound relative to the menu control, use:
b.SetBounds(0, menu.Bottom, 128, 50);
[UPDATE]
Alternatively, you could use:
public partial class Form1 : Form
{
private int menuStripHeight = 50;
public Form1()
{
InitializeComponent();
this.ControlAdded += Form1_ControlAdded;
}
private void Form1_Load(object sender, EventArgs e)
{
MenuStrip menu = new MenuStrip();
menu.Items.Add("File");
menu.AutoSize = false;
menu.Height = menuStripHeight; ;
menu.Dock = DockStyle.Top;
MainMenuStrip = menu;
Controls.Add(menu);
Button b = new Button();
b.Text = "hello world";
// note that the position used is 0,0
b.SetBounds(0, 0, 128, 50);
Controls.Add(b);
}
void Form1_ControlAdded(object sender, ControlEventArgs e)
{
if (e.Control.GetType().FullName != "System.Windows.Forms.MenuStrip")
e.Control.Top += menuStripHeight;
}
}
[UPDATE 2]
Or you could just use a Panel:
MenuStrip menu = new MenuStrip();
menu.Items.Add("File");
menu.AutoSize = false;
menu.Height = menuStripHeight; ;
menu.Dock = DockStyle.Top;
MainMenuStrip = menu;
Controls.Add(menu);
Panel p = new Panel();
p.SetBounds(0, menuStripHeight, this.Width, this.Height);
Controls.Add(p);
Button b = new Button();
b.Text = "hello world";
p.Controls.Add(b);
b.SetBounds(0, 0, 128, 50);

Use DockStyle.Top in both MenuStrip and Panel, but add them in the reverse order. Adding a control with Dock=Top puts this last control closest to the border, that is, on top of all the other controls. So without resorting to private constants and event handlers:
MenuStrip menu = new MenuStrip() {
AutoSize = false,
Dock = DockStyle.Top
};
menu.Items.Add("File");
Panel p = new Panel(){
Dock = DockStyle.Top
};
Controls.Add(p);
Controls.Add(menu);
MainMenuStrip = menu;
Button b = new Button(){
Text = "hello world"
};
p.Controls.Add(b);
b.SetBounds(0, 0, 128, 50);

Related

C# Custom ComboBox - DropDown Position

I'm creating a ComboBox control using ToolStripControlHost and ToolStripDropDown that can host any kind of control in the DropDown window. For example, the DropDown window might display a listview or treeview or even another usercontrol.
I'm posting a simplified code below where dropdown host a usercontrol with a listview and a button like this:
The problem occurs when the control is positioned at the bottom of the screen in such a way that the dropdown window will extrapolate the lower boundary of the screen. When this occurs, the dropdown ends up hiding the control.
In this case, I'd like to fix the _dropDown.Show method call to show dropdown window as follows:
To repeat the problem, just run the code below and drag the window to the bottom of the screen and open the dropdown.
using System;
using System.Windows.Forms;
public class CustomComboBox : UserControl
{
ToolStripDropDown _dropDown;
public CustomComboBox()
{
var textbox = new TextBox();
textbox.Location = new System.Drawing.Point(0, 0);
textbox.Size = new System.Drawing.Size(this.Width - 22, 20);
textbox.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
this.Controls.Add(textbox);
var button = new Button();
button.Location = new System.Drawing.Point(this.Width - 22, -1);
button.Size = new System.Drawing.Size(22, 22);
button.Text = "\u2BC6";
button.Anchor = AnchorStyles.Right | AnchorStyles.Top;
button.Click += new System.EventHandler(this.Button_Click);
this.Controls.Add(button);
var dropDownControl = new DropDownControlTest();
var controlHost = new ToolStripControlHost(dropDownControl);
_dropDown = new ToolStripDropDown();
_dropDown.AutoSize = true;
_dropDown.Items.Add(controlHost);
}
void Button_Click(object sender, EventArgs e)
{
_dropDown.Show(this, 0, this.Height);
}
}
public class DropDownControlTest : UserControl
{
public DropDownControlTest()
{
var listview = new ListView();
listview.Location = new System.Drawing.Point(3, 1);
listview.Size = new System.Drawing.Size(400,300);
listview.View = View.Details;
listview.Columns.Add("Col 1",100);
listview.Columns.Add("Col 2",100);
this.Controls.Add(listview);
var button = new Button();
button.Location = new System.Drawing.Point(3, 305);
button.Text = "More...";
this.Controls.Add(button);
}
}
public class Form1 : Form
{
private static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
public Form1 ()
{
CustomComboBox ccBox = new CustomComboBox();
ccBox.Location = new System.Drawing.Point(10, 10);
ccBox.Height = 20;
this.Text = "Test CustomComboBox";
this.Controls.Add(ccBox);
}
}
You can use the ToolStripDropDown.Show Method (Control, Point, ToolStripDropDownDirection) overload to control the drop direction. The code will need to perform bounds checking to decide whether to place the dropdown above or below the textbox.
The following is a simplistic method for doing the bounds checking and was only tested on a single screen configuration.
First, make textbox a class level variable.
private TextBox textbox;
public CustomComboBox()
{
//var textbox = new TextBox();
textbox = new TextBox();
The display logic is as follows.
void Button_Click(object sender, EventArgs e)
{
Point textBoxScreenLocation = textbox.PointToScreen(textbox.Location);
// try to position _dropDown below textbox
Point pt = textBoxScreenLocation;
pt.Offset(0, textbox.Height);
// determine if it will fit on the screen below the textbox
Size dropdownSize = _dropDown.GetPreferredSize(Size.Empty);
Rectangle dropdownBounds = new Rectangle(pt, dropdownSize);
if (dropdownBounds.Bottom <= Screen.GetWorkingArea(dropdownBounds).Bottom)
{ // show below
_dropDown.Show(pt, ToolStripDropDownDirection.BelowRight);
}
else
{ // show above
_dropDown.Show(textBoxScreenLocation, ToolStripDropDownDirection.AboveRight);
}
}
}
I can not comment that is why I am answering your question. You can use the reflection and then re-position you control. I have found a custom combobox control same as you developed. Please check this. At least, you will get some idea what you need to do.

Put floating controls on top of docking control in a container

It easier to see my problem in below image. I need to fill the tabPage with a chart, and then put some buttons in the top left corner.
How may I do this programmatically?
Here is what I have tried:
//UI
tabControl1.TabPages.Clear();
TabPage tp1 = new TabPage("tp1");
tabControl1.TabPages.Add(tp1);
Button btn1 = new Button();
btn1.Text = "OK";
btn1.Parent = tp1;
Button btn2 = new Button();
btn2.Text = "OK2";
btn2.Size = new System.Drawing.Size(220, 50);
//btn2.Anchor = AnchorStyles.None;
//btn2.Margin = new Padding(200,3,3,3);
btn2.Parent = tp1;
Chart cht = new Chart();
cht.Parent = tp1;
cht.Dock = DockStyle.Fill;

C# Winform - Keep MouseDown and join to other object the object MouseMove not work

When MouseDown on objectA then mousemove to objectB , the objectB(mousemove handle)cannot calling.
How to let other object detect the mousemovehandle , when mousedown before enter the object area.
public Test()
{
InitializeComponent();
this.Size = new Size(500, 500);
Panel pl = new Panel();
pl.Size = new Size(200, 200);
pl.Location = new Point(0, 0);
pl.BackColor = Color.Pink;
Label lb = new Label();
lb.Text = "Keep MouseDown and move to Panel2 , Panel2 MouseMoveHandler not work";
lb.Dock = DockStyle.Fill;
pl.Controls.Add(lb);
TextBox tb = new TextBox();
tb.Multiline = true;
tb.Size = new Size(400, 100);
tb.Location = new Point(0,300);
Panel pl2 = new Panel();
pl2.Size = new Size(100, 100);
pl2.Location = new Point(0, 0);
pl2.BackColor = Color.Red;
pl2.Location = new Point(300, 0);
pl2.MouseMove += new MouseEventHandler(delegate (object o, MouseEventArgs a)
{
tb.AppendText(a.X + "," + a.Y);
});
this.Controls.Add(pl);
this.Controls.Add(pl2);
this.Controls.Add(tb);
}
What you see is the standard behaviour. It's the only way you could get MouseMove events for an object while having the mouse down if you move the mouse outside that object.
If you want to find out which control is under the cursor at any point in time (you can do it in your MouseMove event if needed), you can use this code:
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint(Point pnt);
public static Control GetControlUnderCursor() {
var handle = WindowFromPoint(Control.MousePosition);
if (handle != IntPtr.Zero)
return Control.FromHandle(handle);
return null;
}
You could use this code in the form's MouseMove event if you set the form's Capture property to true (that's what is happening on your control when you hold the mouse button down) also and you can check Control.MouseButtons to find out which mouse buttons are pressed if needed..

Scale constrols inside TableLayoutPanel

Why tableLayoutPanel.Dock = DockStyle.Fill; do not work and tableLayoutPanel does not fill all available space in Form?
How to scale button.Text = "Button";?
namespace Scalability
{
static class Program
{
/// <summary>
/// Главная точка входа для приложения.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
ViewForm viewForm = new ViewForm();
Application.Run(viewForm);
}
}
}
namespace Scalability.Forms
{
class ViewForm:Form
{
public ViewForm()
{
TableLayoutPanel tableLayoutPanel = new TableLayoutPanel();
Button button = new Button();
button.Text = "Button";
button.Dock = DockStyle.Fill;
Label label = new Label();
label.Text="Label";
label.Dock = DockStyle.Fill;
TextBox textBox = new TextBox();
textBox.Text = "textBox";
textBox.Dock = DockStyle.Fill;
tableLayoutPanel.Controls.Add(button, 0, 0);
tableLayoutPanel.Controls.Add(label, 0, 1);
tableLayoutPanel.Controls.Add(textBox, 1, 0);
tableLayoutPanel.Dock = DockStyle.Fill;
this.Controls.Add(tableLayoutPanel);
}
}
}
configurate RowStyles of TableLayoutPanel to make them stretch
TableLayoutPanel tableLayoutPanel = new TableLayoutPanel();
tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50));
tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 50));
But it does work. :)
1) Try to attach colors to your controls like this.
Button button = new Button();
button.Text = "Button";
button.BackColor = Color.Orange;
button.Dock = DockStyle.Fill;
Label label = new Label();
label.Text = "Label";
label.BackColor = Color.Yellow;
label.Dock = DockStyle.Fill;
TextBox textBox = new TextBox();
textBox.Text = "textBox";
textBox.BackColor = Color.Green;
textBox.Dock = DockStyle.Fill;
Now you will see that the controls use your entire window exactly in the way you put them. So button is col 0, row 0 (left, top). Textbox is col 1, row 0 (right, top). Label is col 0, row 1 (left bottom). And there is nothing in col 1 row 1 (right bottom "central place" is empty).
If you add a button to 1,1 it will stretch in the remaining space. Like this
// Blue button.
Button bbutton = new Button();
bbutton.Text = "Button";
bbutton.BackColor = Color.Blue;
bbutton.Dock = DockStyle.Fill;
tableLayoutPanel.Controls.Add(button, 0, 0);
tableLayoutPanel.Controls.Add(label, 0, 1);
tableLayoutPanel.Controls.Add(textBox, 1, 0);
// We added this one.
tableLayoutPanel.Controls.Add(bbutton, 1, 1);
tableLayoutPanel.Dock = DockStyle.Fill;
So there you have it.

Centering OK button within a MessageBox in winforms

I am learning C#, and as a part of it I wrote small app that consists of form with two groups of buttons, two buttons each. Button for closing of app is added as well. And everything works ok. Also there is MessageBox, showing that the app is going to be closed. And here is little problem that bugs me: OK button within that MessageBox is NOT centered horizontally. I guess there is a method to align that button, but what puzzles me is why it's is not centered by default? As illustration here are screenshots:
Here is code as well:
using System;
using System.Drawing;
using System.Windows.Forms;
public class myForm : Form
{
private GroupBox gboxGrp1;
private GroupBox gboxGrp2;
private RadioButton butn1a;
private RadioButton butn1b;
private RadioButton butn2a;
private RadioButton butn2b;
private Button btnClose;
public myForm()
{
InitializeComponent();
}
private void InitializeComponent()
{
this.btnClose = new Button();
this.gboxGrp1 = new GroupBox();
this.gboxGrp2 = new GroupBox();
this.butn1a = new RadioButton();
this.butn1b = new RadioButton();
this.butn2a = new RadioButton();
this.butn2b = new RadioButton();
//myForm
this.Text = "My Form";
this.StartPosition = FormStartPosition.CenterScreen;
this.Height = 350;
this.Width = 200;
//btnClose
this.Controls.Add(btnClose);
this.btnClose.Text = "Close";
this.btnClose.Location = new Point(60, 260);
this.btnClose.Click += new EventHandler(btnClose_Click);
//gboxgrp1
this.gboxGrp1.Location = new Point(20, 20);
this.gboxGrp1.Text = "Group Box 1";
this.gboxGrp1.Width = 150;
this.gboxGrp1.Height = 100;
//gboxgrp2
this.gboxGrp2.Text = "Group Box 2";
this.gboxGrp2.Location = new Point(20, 130);
this.gboxGrp2.Width = 150;
this.gboxGrp2.Height = 100;
//Radio buttons
this.butn1a.Text = "Radio 1a";
this.butn1a.Location = new Point(30, 30);
this.butn1a.Size = new Size(90, 15);
this.butn1b.Text = "Radio 1b";
this.butn1b.Location = new Point(30, 60);
this.butn1b.Size = new Size(90, 15);
this.butn2a.Text = "Radio 2a";
this.butn2a.Location = new Point(30, 30);
this.butn2a.Size = new Size(90, 15);
this.butn2b.Text = "Radio 2b";
this.butn2b.Location = new Point(30, 70);
this.butn2b.Size = new Size(90, 15);
//Controls
this.Controls.Add(gboxGrp1);
this.Controls.Add(gboxGrp2);
this.gboxGrp1.Controls.Add(butn1a);
this.gboxGrp1.Controls.Add(butn1b);
this.gboxGrp2.Controls.Add(butn2a);
this.gboxGrp2.Controls.Add(butn2b);
}
private void btnClose_Click(object sender, EventArgs e)
{
MessageBox.Show("Closing Application");
Application.Exit();
}
}
public class MyApp
{
public static void Main()
{
Application.Run(new myForm());
}
}
You can't restyle the default MessageBox as that's completely depends on the windows OS theme. However you could create your own message box by simply creating a new form and then call it by using newMessagebox.ShowDialog();

Categories