how to stop flickering C# winforms - c#

I have a program that is essentially like a paint application. However, my program has some flickering issues. I have the following line in my code (which should get rid of flickering - but doesn't):
this.SetStyle(ControlStyles.AllPaintingInWmPaint
| ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
my code(minus the super and sub classes for the shapes is as follows:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Paint
{
public partial class Paint : Form
{
private Point startPoint;
private Point endPoint;
private Rectangle rect = new Rectangle();
private Int32 brushThickness = 0;
private Boolean drawSPaint = false;
private List<Shapes> listOfShapes = new List<Shapes>();
private Color currentColor;
private Color currentBoarderColor;
private Boolean IsShapeRectangle = false;
private Boolean IsShapeCircle = false;
private Boolean IsShapeLine = false;
public SPaint()
{
InitializeComponent();
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
currentColor = Color.Red;
currentBoarderColor = Color.DodgerBlue;
IsShapeRectangle = true;
}
private void panelArea_Paint(object sender, PaintEventArgs e)
{
Graphics g = panelArea.CreateGraphics();
if (drawSPaint == true)
{
Pen p = new Pen(Color.Blue);
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
if (IsShapeRectangle == true)
{
g.DrawRectangle(p, rect);
}
else if (IsShapeCircle == true)
{
g.DrawEllipse(p, rect);
}
else if (IsShapeLine == true)
{
g.DrawLine(p, startPoint, endPoint);
}
}
foreach (Shapes shape in listOfShapes)
{
shape.Draw(g);
}
}
private void panelArea_MouseDown(object sender, MouseEventArgs e)
{
startPoint.X = e.X;
startPoint.Y = e.Y;
drawSPaint = true;
}
private void panelArea_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
if (e.X > startPoint.X)
{
rect.X = startPoint.X;
rect.Width = e.X - startPoint.X;
}
else
{
rect.X = e.X;
rect.Width = startPoint.X - e.X;
}
if (e.Y > startPoint.Y)
{
rect.Y = startPoint.Y;
rect.Height = e.Y - startPoint.Y;
}
else
{
rect.Y = e.Y;
rect.Height = startPoint.Y - e.Y;
}
panelArea.Invalidate();
}
}
private void panelArea_MouseUp(object sender, MouseEventArgs e)
{
endPoint.X = e.X;
endPoint.Y = e.Y;
drawSPaint = false;
if (rect.Width > 0 && rect.Height > 0)
{
if (IsShapeRectangle == true)
{
listOfShapes.Add(new TheRectangles(rect, currentColor, currentBoarderColor, brushThickness));
}
else if (IsShapeCircle == true)
{
listOfShapes.Add(new TheCircles(rect, currentColor, currentBoarderColor, brushThickness));
}
else if (IsShapeLine == true)
{
listOfShapes.Add(new TheLines(startPoint, endPoint, currentColor, currentBoarderColor, brushThickness));
}
panelArea.Invalidate();
}
}
private void rectangleToolStripMenuItem_Click(object sender, EventArgs e)
{
IsShapeRectangle = true;
IsShapeCircle = false;
IsShapeLine = false;
}
private void ellipseToolStripMenuItem_Click(object sender, EventArgs e)
{
IsShapeRectangle = false;
IsShapeCircle = true;
IsShapeLine = false;
}
private void lineToolStripMenuItem_Click(object sender, EventArgs e)
{
IsShapeCircle = false;
IsShapeRectangle = false;
IsShapeLine = true;
}
private void ThicknessLevel0_Click(object sender, EventArgs e)
{
brushThickness = 0;
}
private void ThicknessLevel2_Click(object sender, EventArgs e)
{
brushThickness = 2;
}
private void ThicknessLevel4_Click(object sender, EventArgs e)
{
brushThickness = 4;
}
private void ThicknessLevel6_Click(object sender, EventArgs e)
{
brushThickness = 6;
}
private void ThicknessLevel8_Click(object sender, EventArgs e)
{
brushThickness = 8;
}
private void ThicknessLevel10_Click(object sender, EventArgs e)
{
brushThickness = 10;
}
private void ThicknessLevel12_Click(object sender, EventArgs e)
{
brushThickness = 12;
}
private void ThicknessLevel14_Click(object sender, EventArgs e)
{
brushThickness = 14;
}
private void FillColour_Click(object sender, EventArgs e)
{
ColorDialog fillColourDialog = new ColorDialog();
fillColourDialog.ShowDialog();
currentColor = fillColourDialog.Color;
panelArea.Invalidate();
}
private void button1_Click(object sender, EventArgs e)
{
ColorDialog fillColourDialog = new ColorDialog();
fillColourDialog.ShowDialog();
currentBoarderColor = fillColourDialog.Color;
panelArea.Invalidate();
}
}
}
How do i stop the flickering?
*UPDATE:*This code actually works great when i'm drawing directly on the form. However, when i try to draw on the panel, flickering becomes an issue

For a "cleaner solution" and in order to keep using the base Panel, you could simply use Reflection to implement the double buffering, by adding this code to the form that holds the panels in which you want to draw in
typeof(Panel).InvokeMember("DoubleBuffered",
BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
null, DrawingPanel, new object[] { true });
Where "DrawingPanel" is the name of the panel that you want to do the double buffering.
I know quite a lot of time has passed since the question was asked, but this might help somebody in the future.

Finally solved the flickering. Since I was drawing on a panel instead of the form the line of code below will not solve the flickering:
this.SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer,
true);
SetStyle must be of type 'YourProject.YourProject' (or derived from it) hence, you have to create a class as such (so that you can use MyPanel which will be derived from SPaint.SPaint and hence allowing you to use doublebuffering directly for the panel - rather than the form):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SPaint;
namespace YourProject
{
public class MyPanel : System.Windows.Forms.Panel
{
public MyPanel()
{
this.SetStyle(
System.Windows.Forms.ControlStyles.UserPaint |
System.Windows.Forms.ControlStyles.AllPaintingInWmPaint |
System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer,
true);
}
}
}
After you've done this(although you should really never edit the designer code unless you truly know what you're doing) you'll have to edit the Form.Designer.cs. Inside this file you will find code that looks like this:
this.panelArea = new YourProject.MyPanel();
The above line needs to be changed to:
this.panelArea = new MyPanel();
After I completed these steps, my paint program no longer flickers.
For anyone else having the same issue, the problem is finally solved.
Enjoy!

Copy and paste this into your project
protected override CreateParams CreateParams
{
get
{
CreateParams handleParam = base.CreateParams;
handleParam.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
return handleParam;
}
}
This enables double-buffering for all controls from the form level down, otherwise double buffering needs to be individually enabled for each one... you may want to fine tune double bufferring after this because blanketed double buffering may give unwanted side effects.

I have had the same problem. I was never able to 100% rid myself of the flicker (see point 2), but I used this
protected override void OnPaint(PaintEventArgs e) {}
as well as
this.DoubleBuffered = true;
The main issue for flickering is making sure you
paint things it the right order!
make sure your draw function is < about 1/60th of a second
winforms invokes the OnPaint method each time the form needs to be redrawn. There are many ways it can be devalidated, including moving a mouse cursor over the form can sometimes invoke a redraw event.
And important note about OnPaint, is you don't start from scratch each time, you instead start from where you were, if you flood fill the background color, you are likely going to get flickering.
Finally your gfx object. Inside OnPaint you will need to recreate the graphics object, but ONLY if the screen size has changed. recreating the object is very expensive, and it needs to be disposed before it is recreated (garbage collection doesn't 100% handle it correctly or so says documentation). I created a class variable
protected Graphics gfx = null;
and then used it locally in OnPaint like so, but this was because I needed to use the gfx object in other locations in my class. Otherwise DO NOT DO THIS. If you are only painting in OnPaint, then please use e.Graphics!!
// clean up old graphics object
gfx.Dispose();
// recreate graphics object (dont use e.Graphics, because we need to use it
// in other functions)
gfx = this.CreateGraphics();
Hope this helps.

Double buffering is not going to be of much help here I'm afraid. I ran into this a while ago and ended up adding a separate panel in a rather clumsy way but it worked for my application.
Make the original panel that you have ( panelArea ) a transparent area, and put it on top of a 2nd panel, which you call panelDraw for example. Make sure to have panelArea in front. I whipped this up and it got rid of the flickering, but left the shape that was being drawn smeared out so it's not a full solution either.
A transparent panel can be made by overriding some paint actions from the original panel:
public class ClearPanel : Panel
{
public ClearPanel(){}
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= 0x00000020;
return createParams;
}
}
protected override void OnPaintBackground(PaintEventArgs e){}
}
The idea is to handle drawing the temporary shape during the MouseMove event of the 'panelArea' and ONLY repaint the 'panelDraw' on the MouseUp Event.
// Use the panelDraw paint event to draw shapes that are done
void panelDraw_Paint(object sender, PaintEventArgs e)
{
Graphics g = panelDraw.CreateGraphics();
foreach (Rectangle shape in listOfShapes)
{
shape.Draw(g);
}
}
// Use the panelArea_paint event to update the new shape-dragging...
private void panelArea_Paint(object sender, PaintEventArgs e)
{
Graphics g = panelArea.CreateGraphics();
if (drawSETPaint == true)
{
Pen p = new Pen(Color.Blue);
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
if (IsShapeRectangle == true)
{
g.DrawRectangle(p, rect);
}
else if (IsShapeCircle == true)
{
g.DrawEllipse(p, rect);
}
else if (IsShapeLine == true)
{
g.DrawLine(p, startPoint, endPoint);
}
}
}
private void panelArea_MouseUp(object sender, MouseEventArgs e)
{
endPoint.X = e.X;
endPoint.Y = e.Y;
drawSETPaint = false;
if (rect.Width > 0 && rect.Height > 0)
{
if (IsShapeRectangle == true)
{
listOfShapes.Add(new TheRectangles(rect, currentColor, currentBoarderColor, brushThickness));
}
else if (IsShapeCircle == true)
{
listOfShapes.Add(new TheCircles(rect, currentColor, currentBoarderColor, brushThickness));
}
else if (IsShapeLine == true)
{
listOfShapes.Add(new TheLines(startPoint, endPoint, currentColor, currentBoarderColor, brushThickness));
}
panelArea.Invalidate();
}
panelDraw.Invalidate();
}

I know this is really old question but maybe someone will find it useful.
I'd like to make little enhancement to viper's answer.
You can make simple extension to Panel class and hide setting property through reflection.
public static class MyExtensions {
public static void SetDoubleBuffered(this Panel panel) {
typeof(Panel).InvokeMember(
"DoubleBuffered",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty,
null,
panel,
new object[] { true });
}
}
If your Panel variable's name is myPanel you can just call
myPanel.SetDoubleBuffered();
and that's it. Code looks much cleaner.

I'd advise overriding OnPaintBackground and handling the background erase yourself. If you know you are painting the whole control you can just do nothing in OnPaintBackground (don't call the base method) and it will prevent the background colour being painted first

In this condition you have to enable double buffer .
Open current form and go to form properties and apply double buffer true;
or you can also write this code .
this.DoubleBuffered = true;
In form load.

if all of the above doesn't work you can always create your own double buffer
link to Microsofts tutorial: https://learn.microsoft.com/en-us/dotnet/framework/winforms/advanced/how-to-reduce-graphics-flicker-with-double-buffering-for-forms-and-controls
hopes it works for you

It's a bit of and old question, but just to be complete: There is yet another solution, that worked for me where the double-buffering did not.
As it turns out Microsoft offers the BufferedGraphics class as a solution. Nice thing about this class is that it enables you to copy one Graphics object to another, so except from setting up a temporary Graphics object and eventually copying it to the final destination, one can use pretty much the same code that one would have done when the flickering should not have been a problem:
private void Indicator_Paint(object sender, PaintEventArgs e)
{
Control pbIndicator = (Control)sender;
Rectangle targetRect = pbIndicator.ClientRectangle;
Image img = Bitmap.FromFile("bitmap.bmp");
BufferedGraphicsContext ctx = new BufferedGraphicsContext();
BufferedGraphics bg = ctx.Allocate(e.Graphics, targetRect);
// Do the graphic stuff
bg.Graphics.Clear(this.BackColor);
bg.Graphics.DrawImage(img, 0, 0);
// etcetera
bg.Render(e.Graphics);
bg.Dispose();
ctx.Dispose();
}
Downside of this solution that it might clutter your code. Furthermore I'm not sure whether it is a good idea to setup the context each time, or whether it would suffice to create one in advance and keep using that context.
For more information see https://learn.microsoft.com/en-us/dotnet/api/system.drawing.bufferedgraphicscontext?view=dotnet-plat-ext-3.1

here is the program of moving circle in .net, that doesn't flicker.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
namespace CircleMove
{
/// <summary>
/// Description of MainForm.
/// </summary>
public partial class MainForm : Form
{
int x=0,y=0;
Thread t;
public MainForm()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
//
// TODO: Add constructor code after the InitializeComponent() call.
//
}
void MainFormPaint(object sender, PaintEventArgs e)
{
Graphics g=e.Graphics;
Pen p=new Pen(Color.Orange);
Brush b=new SolidBrush(Color.Red);
// g.FillRectangle(b,0,0,100,100);
g.FillEllipse(b,x,y,100,100);
}
void MainFormLoad(object sender, EventArgs e)
{
t=new Thread( new ThreadStart(
()=>{
while(true)
{
Thread.Sleep(10);
x++;y++;
this.Invoke(new Action(
()=>{
this.Refresh();
this.Invalidate();
this.DoubleBuffered=true;
}
)
);
}
}
)
);
t.Start();
}
}
}

If memory is tight (so you don't want the memory cost of double-buffering), one possible way to REDUCE, though not eliminate, flicker, is to set background color to the dominant color in your current scene.
Why this helps: flicker is a momentary flash of the background color, which the OS draws before drawing child controls or your custom drawing code. If that flash is a color that is closer to the final color to be displayed, it will be less noticeable.
If you are not sure what color to start with, start with 50% gray, because this is an average of black and white, so will be closer to most colors in your scene.
myFormOrControl.BackColor = Color.Gray;

Try to insert drawing logic in current form's
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
}
method. In this case you should use parameter e to get Graphics object. Use e.Graphics property. Then you should invoke Invalidate() method for this form whenever form must be redrawn.
PS: DoubleBuffered must be set to true.

Drawing onto a Label instead of a Panel, solved the problem for me.
No need to use DoubleBuffering or anything either.
You can remove the text from the label, set AutoSize to false, then Dock it or set the Size and use it as for the Panel.
Best wishes,

Quite late into the game... but for me WS_EX_COMPOSITED worked fine for a while and after some time of application start, layout started behaving very weird. I use TabControl and some TabPages on addition/removal started displaying titles of its siblings, so be careful with using it. Without WS_EX_COMPOSITED all worked fine, but I still had the flickering issue on new TabPage add.
None solution here really worked for me so I started looking at my code. I have a functionality where I create RichTextBox, then this RichTextBox is added to newly created TabPage and finally TabPage is added to TabControl. I decided to change order of that action - firstly I create TabPage, then add it to TabControl, and when TabPage is already added to TabControl, I add RichTextBox to it. When I did that, no more flickering and all works perfectly without any 'hacks'.
The moral of the story is that if nothing really works for you, try to (if possible and applicable in your case) play around with order in which you add controls.

Can you try using a timer and boolean to check if mouse is down, and paint in that spot, using a variable again check if user has moved his mouse, if moved paint that spot too etc.
Or just check if mouse down(via boolean that sets true when mouse is down) using a timer and paint it considering you are probably trying to just paint one pixel, not like you have shadow etc. Instead of using actual mousedown. So you check every 1 second instead of 0.0001 and it wont flicker. Or vice-versa, try it with your own times.

just do this.Refresh() when shown the form.

Related

Change button color on mouse hover

In C #, how to change the color of the buttons when the mouse pointer is on them, so that the color of the button returns to the previous color when the mouse leaves it.
Supposing you are using Windows.Forms you can add event handlers to the MouseEnter and MouseLeave events of your Button and set the Button's BackColor property accordingly:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
button1.MouseEnter += OnMouseEnterButton1;
button1.MouseLeave += OnMouseLeaveButton1;
}
private void OnMouseEnterButton1(object sender, EventArgs e)
{
button1.BackColor = SystemColors.ButtonHighlight; // or Color.Red or whatever you want
}
private void OnMouseLeaveButton1(object sender, EventArgs e)
{
button1.BackColor = SystemColors.ButtonFace;
}
}
below code worked for me.
private void shipdbutton_MouseHover(object sender, EventArgs e)
{
shipdbutton.BackColor = Color.White;
}
private void shipdbutton_MouseLeave(object sender, EventArgs e)
{
shipdbutton.BackColor = Color.FromArgb(32, 38, 71); // ****add the color you want here.**
}
No need hover/leave events or drawing.
Just make your button flat and use MouseOverBackColor property.
Button.FlatStyle = FlatStyle.Flat;
Button.FlatAppearance.MouseOverBackColor = Color.Red; //color you want it to be background on hover
You're not really being very specific, but you could use the MonoGame library if you wanted to. If you do choose to use it (generally not recommended for simple programs like a calculator, but it does the job nonetheless), you should do something like this:
//1. Declare your button's texture, and some other stuff (button rectangle, etc.).
Texture2D My_texture;
Rectangle buttonBox;
bool isMouseIn = false;
//2. Load your button's texture in the LoadContent() method.
My_texture = Content.Load<Texture2D>("name of your resource");
//3. Handle the input in the Update() method.
MouseState currentMouseState = Mouse.GetState();
if(buttonBox.Contains(currentMouseState.Position))
{
isMouseIn = true;
}
//4. Draw the button in the Draw() method.
spriteBatch.Begin();
if(isMousein)
{
spriteBatch.Draw(My_texture, buttonBox, Color.Red;
}
else
{
spriteBatch.Draw(My_texture, buttonBox, Color.Blue);
}
spriteBatch.End();
It is however better to use Windows Forms as the other answer says, since it is more suited to such a simple program and does not require a very polished or flexible graphical interface.

C# mouse event for class object

First - I'm a graphics designer - not a programmer :/
I'm trying create simple aplication (C# windows Form application) with option to add some objects (PictureBox) and allow user to drag those PicturesBoxes on form (change their positon after adding to form).
I can do it for one PictureBox, but can't add function to all dinamic created objects :/
I have something like that for standard Picturebox4
public bool moveDetect = false;
private void pictureBox4_MouseDown(object sender, MouseEventArgs e)
{
moveDetect = true;
}
private void pictureBox4_MouseUp(object sender, MouseEventArgs e)
{
if (moveDetect)
{
Point pozycja = new Point();
this.Cursor = new Cursor(Cursor.Current.Handle);
pozycja = this.PointToClient(Cursor.Position);
pictureBox4.Location = pozycja;
}
}
Does anyone know any tutorial showing how to add function like above to my simple class "myPictureBox : Picturebox"
My class is:
class myPictureBox : PictureBox
{
public bool moveDetect = false;
// constructor
public myPictureBox(int w, int h, string name)
{
this.Width = w;
this.Height = h;
this.Image = Image.FromFile("../../Resources/" + name + ".png");
Debug.WriteLine("Created ...");
}
}
Constructor works good and show "Created..." in output. Cant add function to all objects :/
Thanks and Regards ;)
If I understand correctly, your code works fine with the event handlers MouseUp and MouseDown when you are working with PictureBoxes that you create at design time using the designer.
You can add these same event handlers to controls that are created dynamically when you instantiate them:
MyPictureBox dynamicPicBox = new MyPictureBox(800, 600, "JustATest");
dynamicPicBox.MouseDown += pictureBox_MouseDown;
this adds an event handler that maps to the method pictureBox_MouseDown
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
moveDetect = true;
}
Since your custom class is derived from PictureBox, it should recognize this type of event handler.

How do you move a pictureBox across a painted panel without any flicker?

I have been using a doublebuffered panel to paint images onto itself, but when I move a pictureBox across it, it flickers and lags.
The code I've been using to move pictureBoxes is:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
x = e.X;
y = e.Y;
panel1.Invalidate();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
pictureBox1.Left += (e.X - x);
pictureBox1.Top += (e.Y - y);
}
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(pictureBox2.BackgroundImage, new Rectangle(pictureBox2.Location, pictureBox2.Size));
}
as you can see pictureBox2 which isn't visible gets painted to the doublebuffered panel. When I move pictureBox1 however it flickers across the panel. And yes I have been using Invalidate() panel
The doublebuffered panel class code I use is:
public class DoubleBufferPanel : Panel
{
public DoubleBufferPanel()
{
// Set the value of the double-buffering style bits to true.
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint, true);
this.UpdateStyles();
}
}
Here is a picture of what I am trying to achieve without any flicker.(The pictureBoxes not being moved by the mouse are getting painted to the panel). I can't do this without seeing flicker
It lags because you call Invalidate instead of Refresh. Try to set double buffering on Form as well. If it doesn't help, read some tutorials about custom controls. LINK

Make a TabPage flash on event

I'm in the stages of making a program which will require a tabpage to flash when an event happens
I've googled around, and i came across this: Blink tab header on receiving event. This is similar, but uses WPF, and i'm using WinForms, and i'm not even sure that does what i want :L
I've also found this: C#: Flash Window in Taskbar via Win32 FlashWindowEx. This is what i want, but obvious for the whole form, and in the taskbar, not 'in form'
Anyone got any ideas?
I'm not saying this is the best way or even a great way to accomplish this, but it does work. I've used code similar to this when I needed to something similar.
The tabControl1 has two tabs and I blink tab 1 (the second tab).
For my example that I threw together, I set tabControl1's DrawMode property to "OwnerDrawFixed" and then a couple of buttons which start/stop the timer. The interval was something like 750ms but you could choose whatever, of course. On a timer1_Tick event, I swap out the current color and tell the tabControl1 to refresh itself. That'll make the DrawItem event get raised and then I either draw the rectangle the current color if it is tab page 1 or the backcolor if not. Then I draw the tabpage's text.
It works. Could use some tweaking for sure. Give it a whirl!
public partial class Form1 : Form
{
Color currentColor = Color.Green;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (currentColor == Color.Yellow)
currentColor = Color.Green;
else
currentColor = Color.Yellow;
tabControl1.Refresh();
}
private void button2_Click(object sender, EventArgs e)
{
timer1.Stop();
}
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
if (timer1.Enabled && e.Index == 1)
{
e.Graphics.FillRectangle(new SolidBrush(currentColor), e.Bounds);
}
else
{
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), e.Bounds);
}
Rectangle paddedBounds = e.Bounds;
paddedBounds.Inflate(-2, -2);
e.Graphics.DrawString(tabControl1.TabPages[e.Index].Text, this.Font, SystemBrushes.HighlightText, paddedBounds);
}
}

in winforms, can i drag a control with a bunch of controls (like listboxes) in it into another control and resize / move them from there?

I'm running into some situations where it has been nice to make a control (Control A) with a bunch of things in it like buttons, listboxes, datagridviews etc so I can drag it into other controls (Control B) whenever I like, so I don't have to write the logic for the stuff within Control A over and over again.
The only annoying thing with this approach has been that I can't seem to find a way in the designer to move/resize the buttons, listboxes, datagridviews etc of Control A around from the designer of Control B. All it seems to let me do is resize the entirety of Control A.
Does anyone know how to make these custom controls containing multiple controls in such a way that they support design time resizing/moving?
Thanks
Isaac
There is no built in way to do this. You would essentially have to implement event handlers in order to handle the resizing of individual components within your control. One alternative for you is to expose the Size and Location properties of each individual component to the control's clients. For example, within the Control class you could do something like this:
public Size Component1Size
{
get { return component1.Size; }
set { component1.Size = value; }
}
public Point Component1Location
{
get { return component1.Location; }
set { component1.Location = value; }
}
and do this for each component of your control. I think this would be your best option, even though the user won't be able to physically click/drag the components to move and resize them.
Yes you can my friend ,you need to create a SizeAble and DragAndDrop pannel where you can Insert Controls and by Moving That Pannel you can reach that .And for the Resizing Issue you can play with Anchor of Control's that you already added .
using System;
using System.Drawing;
using System.Windows.Forms;
public class SizeablePanel : Panel {
private const int cGripSize = 20;
private bool mDragging;
private Point mDragPos;
public SizeablePanel() {
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.BackColor = Color.White;
}
protected override void OnPaint(PaintEventArgs e) {
ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor,
new Rectangle(this.ClientSize.Width - cGripSize, this.ClientSize.Height - cGripSize, cGripSize, cGripSize));
base.OnPaint(e);
}
private bool IsOnGrip(Point pos) {
return pos.X >= this.ClientSize.Width - cGripSize &&
pos.Y >= this.ClientSize.Height - cGripSize;
}
protected override void OnMouseDown(MouseEventArgs e) {
mDragging = IsOnGrip(e.Location);
mDragPos = e.Location;
base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseEventArgs e) {
mDragging = false;
base.OnMouseUp(e);
}
protected override void OnMouseMove(MouseEventArgs e) {
if (mDragging) {
this.Size = new Size(this.Width + e.X - mDragPos.X,
this.Height + e.Y - mDragPos.Y);
mDragPos = e.Location;
}
else if (IsOnGrip(e.Location)) this.Cursor = Cursors.SizeNWSE;
else this.Cursor = Cursors.Default;
base.OnMouseMove(e);
}
}

Categories