After asking this: Prevent AutoScroll when contained Control gets focus I've found a way to have a scrollbar without the AutoScroll (using a derived class which can access the VScroll property). However - it's not in real-time. i.e. Only when the user is done scrolling does the Control actually get scrolled. (as opposed to a Panel with AutoScroll = true.) So how do I get it to scroll in real-time?
My code:
using System.Drawing;
using System.Windows.Forms;
namespace test
{
public partial class Form1 : Form
{
MyPanel panel = new MyPanel
{
//AutoScroll = true,
Size = new Size(200, 200),
Location = new Point(0, 30),
BackColor = Color.Green
};
Button b1 = new Button
{
Location = new Point(100, 100),
Size = new Size(50, 150),
BackColor = Color.Black
};
Button b2 = new Button();
public Form1()
{
InitializeComponent();
panel.Controls.Add(b1);
Controls.Add(panel);
Controls.Add(b2);
Shown += new System.EventHandler(Form1_Shown);
}
void Form1_Shown(object sender, System.EventArgs e)
{
panel.VerticalScroll.Visible = true;
panel.SetV();
}
}
class MyPanel : Panel
{
public void SetV() { VScroll = true; }
}
}
As in the comment:
You'll need to override the panel's OnScroll() method and call
SetDisplayRectLocation(0, -se.NewValue).
That's the answer to this question.
However, I've found that I can't have both scrollbars simultaneously. Or at least - I haven't found a way to do it.
Related
In my C# WinForm application I have a tableLayoutPanel with only one row and two columns. The left column contains a TreeView, the right one another tableLayoutPanel which was set to Dock: Fill in the designer. I want to create several GroupBoxes programmatically that should use the full width of this second column also when the form is resized.
In the designer of Visual Studio it looks like this:
But when the application runs, the GroupBoxes don't use the complete width and it looks like this:
I'm using two methods to create the GroupBoxes (you can ignore the int values):
private void addDashboardRow(int i, int s)
{
// Add one row to dashboardTableLayoutPanel
sensorTableLayoutPanel.RowCount++;
// Maybe this one is wrong, but SizeType.AutoSize doesn't work either
sensorTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 75f));
sensorTableLayoutPanel.Controls.Add(createSensorGroupbox(i, s));
}
private GroupBox createSensorGroupbox(int i, int sen)
{
GroupBox g = new GroupBox();
//g.Width = 500; // I don't want fixed sizes, height of 75px is sufficient
//g.Height = 75;
g.Dock = DockStyle.Fill;
g.Text = "Sensor " + sen.ToString();
// just one label as example...
Label temp = new Label();
temp.Text = "Temperature: ";
temp.Location = new Point(5, 20);
Label tempVal = new Label();
tempVal.Text = "°C";
tempVal.Location = new Point(5, 50);
tempVal.Name = "Sensor" + sen.ToString() + "_temp";
//[... more labels]
g.Controls.Add(temp);
g.Controls.Add(tempVal);
return g;
}
My questions are:
How can I fit the GroupBox into the complete width of the parent container?
How can I delete all rows? E.g. when looking up the sensors during run time all GroupBoxes are dublicated, but everything should be created newly.
Layout of the question: how should I format terms like TableLayoutPanel correctly in this forum? It's my second question here and I haven't found out, yet.
For the second question. Currently I'm using this method that doesn't do what I'm expecting:
private void clearDashboardTable()
{
if (sensorTableLayoutPanel.Controls.Count == sensorList.Count) {
//MessageBox.Show(sensorTableLayoutPanel.Controls.Count.ToString());
foreach (Control con in sensorTableLayoutPanel.Controls)
{
sensorTableLayoutPanel.Controls.Remove(con);
con.Dispose();
}
//sensorTableLayoutPanel.Dispose();
sensorList.Clear();
}
}
I commented out what I've tried so far in the above code or added additional comments. I used this topic to try to understand the basics of dynamic groupbox creation: Add Row Dynamically in TableLayoutPanel
One way to achieve the outcome you describe is to make a custom UserControl containing a docked GroupBox that contains a docked TableLayoutPanel.
To adjust the width when the container changes, attach to the SizeChanged event of the parent.
public partial class CustomGroupBox : UserControl
{
public CustomGroupBox() => InitializeComponent();
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
if((Parent != null) &&!DesignMode)
{
Parent.SizeChanged += onParentSizeChanged;
}
}
private void onParentSizeChanged(object? sender, EventArgs e)
{
if(sender is FlowLayoutPanel flowLayoutPanel)
{
Debug.WriteLine($"{flowLayoutPanel.Width}");
Width =
flowLayoutPanel.Width -
SystemInformation.VerticalScrollBarWidth;
}
}
public new string Text
{
get=>groupBox.Text;
set=>groupBox.Text = value;
}
}
Main Form
The main form is laid out similar to your image except to substitute a FlowLayoutPanel on the right side.
Now test it out with this minimal code in the method that loads the Main Form:
public partial class MainForm : Form
{
int _id = 0;
public MainForm()
{
InitializeComponent();
flowLayoutPanel.AutoScroll= true;
for (int i = 0; i < 5; i++)
{
var customGroupBox = new CustomGroupBox
{
Text = $"Sensor {++_id}",
Width = flowLayoutPanel.Width - SystemInformation.VerticalScrollBarWidth,
Padding = new Padding(),
Margin = new Padding(),
};
flowLayoutPanel.Controls.Add(customGroupBox);
}
}
}
Clear
An example of clearing the sensors would be to add a button and set a handler in the same Load method:
buttonClear.Click += (sender, e) => flowLayoutPanel.Controls.Clear();
I have a winform that starts out with a sizable border around it. On the form is a button which, when pressed, changes the form to border style none.
The problem is that then the inner part of the form moves up and to the left slightly. I want to make it that, no matter what border is used, the "inner" part of the form will always stay in the same spot (note: but I do still want the form to be moved around when it has a movable border selected)
Thanks.
The Borderless form moves up and slightly left because thats the location that the form currently has,you need to count for the border.To achieve the result you are after you need to reassign the location property and to do that you need to account for the client size and the whole size(with border),the code i think is simple and it will be self-explanatory i believe:
private void button1_Click(object sender, EventArgs e)
{
var X = (this.Size.Width - this.ClientRectangle.Width) / 2;
var Y = (this.Size.Height - this.ClientRectangle.Height) - X;
Point p = new Point(Location.X + X, Location.Y + Y);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Location = p;
}
Another option is to set the padding on the parent that contains the panel with the border. E.g.
public class Form10 : Form {
Button btn = new Button { Text = "Button", Location = new Point(100, 100) };
Panel border = new Panel { Dock = DockStyle.Fill, BorderStyle = BorderStyle.Fixed3D };
public Form10() {
Controls.Add(border);
border.Controls.Add(btn);
btn.Click += delegate {
if (border.BorderStyle == BorderStyle.Fixed3D) {
border.BorderStyle = BorderStyle.None;
border.Parent.Padding = new Padding(2);
}
else {
border.BorderStyle = BorderStyle.Fixed3D;
border.Parent.Padding = new Padding(0);
}
};
}
}
I want to create a Toolstrip and for each ToolStripButton. I also want to create a Toolstrip below the first, in this way each Toolstrip dynamically appear when I click on a ToolStripButton.
I have tried to create the main Toolstrip with Visual Studio designer and for the other toolstrips below I tried to use a customize Toolstrip class. But when I tried to add them:
var cts = new CustomToolStrip();
this.Controls.Add(cts);`
they appeared above of the main Toolstrip.
Here is my CustomToolStrip class:
public class CustomToolStrip : ToolStrip
{
public ToolStripSec()
{
this.GripStyle = ToolStripGripStyle.Hidden;
this.Padding = new Padding(4, 2, 4, 2);
this.AutoSize = true;
this.Dock = DockStyle.Top;
this.Location = new Point(0, 42);
var tspr = new ToolStripProfessionalRenderer();
tspr.RoundedEdges = false;
this.Renderer = tspr;
}
}
Form:
public partial class MainForm : Form
{
public FormAccueil()
{
InitializeComponent(); //this method add the first toolstrip (TSMain)
var r = new ToolStripProfessionalRenderer();
r.RoundedEdges = false;
TSMain.Renderer = r;
var cts = new CustomToolStrip();
this.Controls.Add(cts); // here is the problem
}
}
Result:
http://s16.postimg.org/9kgh0xmh1/Capture.png
Toolstrip 1 and 2 both have the property dock = top.
What can I do to get the Toolstrip 2 below the Toolstrip 1 ?
Could someone guide me please...
Try setting the z-order:
this.Controls.Add(cts);
cts.BringToFront();
How can I center an image in a picturebox as I resize the form? What I have is a picturebox in a panel so if the image is larger than the picturebox, I can get scrollbars on the panel. But this doesn't work with the picturebox size mode "Center Image" and only works with "Auto Size".
This can easily be done with the SizeMode property
pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
Don't use a PictureBox here, a Panel is already perfectly capable of displaying a centered image through its BackgroundImage property. All that's needed is to turn on its DoubleBuffered property to suppress flicker. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form, replacing the panel. Assign its BackgroundImage property with the Properties window or in your code.
using System;
using System.Drawing;
using System.Windows.Forms;
internal class PicturePanel : Panel {
public PicturePanel() {
this.DoubleBuffered = true;
this.AutoScroll = true;
this.BackgroundImageLayout = ImageLayout.Center;
}
public override Image BackgroundImage {
get { return base.BackgroundImage; }
set {
base.BackgroundImage = value;
if (value != null) this.AutoScrollMinSize = value.Size;
}
}
}
What's wrong with using Padding?
void picturebox_Paint(object sender, PaintEventArgs e)
{
int a = picturebox.Width - picturebox.Image.Width;
int b = picturebox.Height - picturebox.Image.Height;
Padding p = new System.Windows.Forms.Padding();
p.Left = a / 2;
p.Top = b / 2;
picturebox.Padding = p;
}
Where in VS2010 can I find a horizontal separator control, as can be found in Outlook settings (screenshots below)?
https://jira.atlassian.com/secure/attachment/14933/outlook+settings.jpg
http://www.keithfimreite.com/Images/OutlookSettings3.gif
Note: VB.NET preferred, but C# answers okay.
If I'm not mistaken, that's just a Line control, but I don't think that control exists anymore. Here is a workaround.
label1.AutoSize = False
label1.Height = 2
label1.BorderStyle = BorderStyle.Fixed3D
Even though this has been answered, I found the following to be what I need based partly on smoore's answer.
Create a new control. Edit the code to be the following:
public partial class Line : Label
{
public override bool AutoSize
{
get
{
return false;
}
}
public override Size MaximumSize
{
get
{
return new Size(int.MaxValue, 2);
}
}
public override Size MinimumSize
{
get
{
return new Size(1, 2);
}
}
public override string Text
{
get
{
return "";
}
}
public Line()
{
InitializeComponent();
this.AutoSize = false;
this.Height = 2;
this.BorderStyle = BorderStyle.Fixed3D;
}
}
Replace Line with the control's class name you want. This will put a separator that will allow you to resize in the designer and disables adding text, changing the autosize forces the size's height to be 2 and width to be whatever you want, and disables adding text.
It's not actually included in the standard set of controls (pretty sure it used to be back in the day!) but you can easily create your own or cheat by using a GroupBox with no text and a height of 1px.
UserControl to provide the same thing: (Not written by me, source: http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/0d4b986e-3ed0-4933-a15d-4b42e02005a7/)
public partial class LineSeparator:UserControl
{
public LineSeparator()
{
InitializeComponent();
this.Paint += new PaintEventHandler(LineSeparator_Paint);
this.MaximumSize = new Size(2000, 2);
this.MinimumSize = new Size(0, 2);
this.Width = 350;
}
private void LineSeparator_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.DrawLine(Pens.DarkGray, new Point(0, 0), new Point(this.Width, 0));
g.DrawLine(Pens.White, new Point(0, 1), new Point(this.Width, 1));
}
}
I wrote a custom control just for this purpose. It supports both vertical and horizontal modes. Just install my [small] control suite and drag the separator control onto the form and place it anywhere you want.
Install-Package ALMSTWKND -Version 1.0.0
The controls will show up in the Toolbox pane after installation.