I am working on WindowsForm C#.
The border i create becomes problem when maximized!
private void App_Paint(object sender, PaintEventArgs e)
{
ControlPaint.DrawBorder(e.Graphics, ClientRectangle, Color.Crimson, ButtonBorderStyle.Solid);
}
Normal:
Maximized:
Am i doing something wrong?
Is there a better way of doing this?
DrawBorder() has a parameter that can be used to remove a previously drawn border, just set ButtonBorderStyle to None
Example:
ControlPaint.DrawBorder(e.Graphics, (sender as Control).ClientRectangle, Color.Red, ButtonBorderStyle.None);
The only thing I don't like as much of my approach, is that it requires calls to the Paint event, which can get slow.
See this to refresh the form at runtime
Based on the information provided, I see it twice, meaning the painted information is being retained (relative to the position of the form) from the previous instance.
I'd strongly recommend staying away from trying to paint the non-client area.
If you have a custom request such as this, create a form with FormBorderStyle.None. Then, have a custom event to paint the Split Container's border. The top panel will have the custom min/max buttons. The rest of the content should be in the lower panel that fills below the min/max button.
Stay away from non-client painting. It's more trouble than it's worth.
I did it my self :D
1) Create a button, turn its FlatStyle to flat.
2) Turn Enable property to false, also remove all text
3) Dock the button to fill.
4) If previous button,labels(control) got hidden because of button, right click the button , send it to back!
Related
I have a transparent form that overlays the desktop in a c# .NET winforms application. The transparency is done by setting the BackColor to bright orange and then setting the TransparencyKey to the same bright orange.
So far this works great and it creates a transparent form. I then want to create a control on the transparent form that draws a rectangle around items on the desktop. So essentially you can think of a transparent button with a rectangular border. To make this happen I currently extend Control and setup the control like this inside of the parent form which is also transparent:
public class CustomControl : Control
{
public CustomControl(Size size, Point point)
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.BackColor = Color.Transparent;
this.Size = size;
this.Location = point;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Pen pen = new Pen(Color.Red, 2f);
e.Graphics.DrawRectangle(pen, this.ClientRectangle);
}
}
This creates the exact effect I'm looking for in that there is a control with a solid opaque rectangle border inside a transparent form and you can see the desktop through the control and form (see image below on left side).
The problem is that the transparent area of the control does not receive any mouse events. In fact, it basically doesn't exist. For example, when your mouse goes over the red rectangular border of the control that triggers the Mouse Hover, Mouse Enter, and Mouse Leave events and changes the cursor to whatever you set as this.Cursor for the control. Once, the mouse is in the transparent portion of the control none of these things trigger.
How can I keep things the way they are now in regards to the look of the control but still receive mouse events in the transparent area. In particular I want to receive Mouse Hover and have the controls Cursor value be honored. Note that if I make the BackColor of the control anything other than Color.Transparent then mouse events work fine.
Thank you!
Update
Based on Hans comment I would like to add that we have implemented the above and that it has usually worked (i.e., the transparent area does respond to mouse events). The reason this issue came up is because I recently rebuilt my machine with all the Windows 8.1 updates and latest ATI graphic drivers and after that the above setup no longer works ever (transparent areas on the control no longer receive any mouse events and for all intents and purposes are not part of the control) On my colleague's machine it almost always works although we've occasionally noticed that it won't work but we could never consistently reproduce the issue.
My assumption was that we did something wrong to cause the transparent areas to not respond to mouse events. However, based on Hans' comment, it seems as though the above code should never work and that the only reason it worked was because of a bug in Aero.
The exact color of our transparency key is rgb(255, 128, 0). In addition we did notice that any label controls placed on the transparent form look terrible (per Han's comment).
Update 2
Based on Han's additional comment regarding the Aero transparency bug I have the following updated questions.
Is there any information on this bug somewhere that explains what the bug is?
What is the intended behavior (assume there are no bugs) for transparent areas of a control? Should mouse events (e.g., Mouse Hover) work on the transparent area?
The Final Answer (that usually works)
The answered provided by Reza below did work for me on some of my computers. However, my primary desktop continued to stubbornly refuse to cooperate. Even when copying the exact project between computers using the same version of windows and .NET the problem existed. The issue when it arose was that transparent areas would not trigger mouse events and were not treated as part of the control.
In addition, I noticed the same thing Reza noticed which was that certain TransparencyKey colors flat out did not work. Although I don't know any details of the bug I would have to agree with Hans that there are bugs involved with transparency on WinForms and if anyone is starting from scratch I would go the WPF route and save yourself any possible future headaches.
In the end we ended up implementing a work around based on some of Hans' answers that required using a timer to check the mouse location and nesting two forms (one with opacity set) to be able to manage the mouse cursor. This solution has worked on all our systems and will hopefully hold up until we move over to WPF. I accepted Reza's answer because it seems to work in most places but be aware that it might not work you and there is no rhyme or reason as to why.
For detailed information on the two workaround we implemented please see the following questions and answers by Hans.
MouseHover and MouseLeave Events controlling
How can I add transparency to a c# form while keeping controls visible?
Important
Consider set BackgroundColor of form to Red and TransparencyKey to Red and BackGroundColor of transparent control to Transparent and it will work!
the strange thing that I see is, the approach doesn't work with for example Magenta but works with Red and Blue.
I think you should create your transparent control this way:
Transparent Control Code
public class TransparentControl : Control
{
public TransparentControl()
{
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
}
private const int WS_EX_TRANSPARENT = 0x20;
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle = cp.ExStyle | WS_EX_TRANSPARENT;
return cp;
}
}
}
And for the mouse events and rendering border when the mouse enters, here is the sample I did Using .Net 4.5 On Windows 8.1:
Create a Form and put a TransparentControl that we created using above code, on it, then handle MouseEnter and MouseLeave and Paint events and paint the border when mouse is in control bouds and handle Click event and show a message.
Form Code
private bool drawBorder;
private void transparentControl1_MouseLeave(object sender, EventArgs e)
{
drawBorder = false;
transparentControl1.Invalidate();
}
private void transparentControl1_MouseEnter(object sender, EventArgs e)
{
drawBorder = true;
transparentControl1.Invalidate();
}
private void transparentControl1_Paint(object sender, PaintEventArgs e)
{
if(drawBorder)
{
using (var pen = new Pen(this.ForeColor, 5))
{
e.Graphics.DrawRectangle(pen, 0, 0, this.transparentControl1.Width - 1, this.transparentControl1.Height - 1);
}
}
}
private void transparentControl1_Click(object sender, EventArgs e)
{
MessageBox.Show("Clicked");
}
Screenshot
The mouse cursor is in the control's area so the black border has been painted.
Important Note
If you draw border the same color as form's transparency key, the border will not be shown.
I think it's okay for the mouse cursor to go in the middle of that overlay box and move with the mouse cursor and the overlay box to make it look like it's a mouse cursor.
Like this picture
I have had similar problem when I use a picturebox control on a transparent form and use the mouseclick event over the control to trigger code. Sometimes the mouseclick is captured and sometimes it isn't. No pattern to it other than the color used as the form background. Red works fine but many other colors do not. Even black does not work consistently. I have found an almost black color that works fine when form.backcolor and form.transparencykey are set to this color. Based on this and others experiences it appears a bug in VB Studio and the way transparency is handled.
Form1.BackColor = Color.FromArgb(64, 0, 0) ' a color that works with transparency and allows picturebox to be clicked
I'm trying to create an effect so when the user hovers the mouse over a picturebox, the button fades to a hoverimage, and when they leave, it fades back to the original. I'm using pictureboxes as buttons in a program. I'm doing this because all the buttons will be pictures with no button textures, so I didn't see the point in using a button. Just so you can visualize it, here is the original image:
And the image to fade to:
I could still change these images a bit, but thats the general idea.
How would I go about creating this fading effect? I'm picturing something using timers and opacity settings, but I don't know how any of that stuff could help me solve this.
E: Heres a bit of code I have. It changes from image to image when I hover, but its not a fade, and it looks very choppy.
private void pictureBox3_MouseEnter(object sender, EventArgs e)
{
pictureBox3.Image = pictureBox37.Image;
}
private void pictureBox3_MouseLeave(object sender, EventArgs e)
{
pictureBox3.Image = pictureBox38.Image;
}
pictureBox37 and pictureBox38 are invisible reference pictureboxes with the images I need.
I don't think there's any WinForms support for this kind of animation, so you'd have to do this manually. If you have more than one of these buttons, I recommend creating your own UserControl with this functionality. I can give you some pointers how to do this:
Your UserControl will have two Image properties, one for the normal and one for the hover image
You'll have to override the OnPaint method to do your own custom painting, blending these two images onto your Graphics according to a position property. This is a float where 0 indicates showing the normal image and 1 the hover image. Any value in between means a blend of these two images. I found some good blending code here.
Then you'll need a Timer to update this position dynamically and redraw the button (by calling Invalidate). I recommend using a Windows.Forms.Timer, which has the advantage that its Tick event is always executed on the main Thread, so you don't have to use Invoke to modify your control.
And last but not least you override the OnMouseEnter and OnMouseLeave methods, to set this all into motion. These methods could set a positionChange property that indicates in which direction position is changing.
Hope this helps ...
Is there a way to resize a Winform window just in Resize End?
This means that as long as the mouse is clicked I see lines and only when I leave the mouse (Resize end) window will resize on the screen.
You will need to use DrawReversibleFrame. Default resizing will need to be disabled (FormBorderStyle = FixedSingle).
Basic Logic is -
MouseDown - Begin tracking
MouseMove - Draw Reversible Frame
MouseUp - Stop Drawing Reversible Frame. Resize Form.
Luckily this MSDN post had working code for this. I have a made a working sample for you.
http://www.mediafire.com/download/427g2h2ajm5z62m/ResizeFrame.zip
You will need to tweak this so Form resize only happens when user 'MouseDown' near the border.
If it's fine to only have the contained controls resize then (and the Form itself - immediately) - use the Form's ResizeEnd event.
(I'm assuming this is the case, because usually there is no reason to delay the Form's resize itself, rather the contained controls', because their resize might be 'expensive'.)
Note: "The ResizeEnd event is also generated after the user moves a form".
Try this.
protected override void OnResizeBegin(EventArgs e) {
SuspendLayout();
base.OnResizeBegin(e);
}
protected override void OnResizeEnd(EventArgs e) {
ResumeLayout();
base.OnResizeEnd(e);
}
I have a form with status strip. Form has auto-scroll on. When required, scrollbars appear and user can scroll.
However when the content is bigger than form size and user has to scroll down to see other parts of the content, he/she has to scroll all the way down also to see the status strip.
I want to keep the status strip on the bottom of the form whatever the size and scroll position is. How do I do that?
Why can I not put everything on a panel and set panel.AutoScroll = true?
Because I draw everything on this panel (with GDI+), then resize it, then form displays scrollbars. Now if I set autoscroll on in the panel no scroll bars are shown because there are no controls on panel, only GDI+ drawings.
Put everything that needs scrolling inside a panel and set auto-scroll on the panel. Your status strip should go outside the panel.
If you are doing extensive drawing with GDI+, there are two good options that I can think of to replace your design.
If the user must interact with your graphics, consider creating a custom control to encapsulate the functionality and graphics.
If it is nothing but a display of some data, you can draw your graphics to a Bitmap and view it in a PictureBox.
I don't know what you are trying to accomplish, so I can't say what is the correct solution.
It sounds like you are doing things backwards. The "Form" shouldn't be showing the scrollbars, the panel should be.
If the "content" of your panel is larger than your panel, and you are doing all of this drawing inside the panel, then you need to set the panel's AutoScrollMinSize to the size of your content, not keep enlarging the size of the panel.
Set the size of your panel's content (example):
panel1.AutoScrollMinSize = new Size(500, 500);
Then in your panel's paint event, apply the transformation:
private void panel1_Paint(object sender, PaintEventArgs e) {
e.Graphics.TranslateTransform(panel1.AutoScrollPosition.X, panel1.AutoScrollPosition.Y);
// do your normal painting here
}
Use a Double-Buffered panel to avoid flicker.
Your StatusStrip should just be docked to the bottom of the form, not interfering with the panel.
In our application we have white buttons on a white form. When the mouse hovers the button we want to show a light-blue transparant rectangle over the button.
I want to create this user control, but I don't know how to do this. I've tried google, but I didn;t found anything that could help me, so I hope you guys can point me at the right direction.
You can just derive your own WinForms control from a Button and override the OnPaint event. In the event handler you'll have an PaintEventArg parameter that contains the property called Graphics. You can use this property to draw anything you want directly where you control is located.
Here is an example directly from MSDN: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.onpaint.aspx
Added: just re-read your question and found that I didn't not reply it correctly.
Basically, you have to override two events and add one property showing whether your control should be painted with an overlayed rectangle or not, let's say IsDrawRectangle. As soon as the OnMouseEnter event is triggered you check if IsDrawRectangle is set and if not you set it to true and invoke this.Invalidate(). The Invalidate() method will force the control to be re-drawn and then in your OnPaint event you just again check the value of your IsDrawRectangle property and draw the rectangle if needed.
You also have to override OnMouseLeave to set the property back to false and force the repaint to remove the rectangle.
Added: if you need to re-draw more than just a single control (in case if your rectangle covers some other controls that need to be re-drawn) then put everything you want to be re-drawn in one container and call the Parent.Invalidate() method in your event handlers.