I've got two user controls. First one, called "Indicator" is a simple Control that paints a square using OnPaint(...); No place for an error in first UserControl.
public partial class Indicator : UserControl
{
public Indicator()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillRectangle(Brushes.Black, 0,0,this.Width,this.Height);
}
}
The second one is a test control and consists of a panel, which contains a picture box and the first user control brought to front.
public partial class testIndicator: UserControl
{
private static Bitmap bmp;
public Indicator()
{
InitializeComponent();
loadImage();
pictureBox.Image = bmp;
indicator.BringToFront();
}
}
When I launch the test control in a dialog (From a form to make sure the program remains running) it displays fine the first time. However if the dialog is closed and opened again (while the program is still running) the OnPaint Method on Indicator doesn't get fired.
It works fine if indicator is placed without a panel onto UserControl.
And just to be clear, I've tried running Invalidate() and Invalidate()+Update() manually while testing, no changes.
Could anyone explain this behavior or possibly know a similar container that doesn't have such issue?
Edit: The mistake was so stupid that i failed to even consider it as a possibility;
The PictureBox uses a static Image, and i had code to only initialize the image once. The problem is it had a "Size largeScaleSize" object that is not static and gets initialized together with images. Since images already exist on 2nd run largeScaleSize does not get initiaized and is basically {0,0}. Scaling method has this line:
float xRatio = (float)this.tankPanel.Width / (float)largeScaleSize.Width;
//same as "xRatio = this.tankPanel.Width / 0" which is infinity
I only wonder why I never got a Division By Zero exception.
I made a small project from your description. You can download it here.
Panel was anchored to every edge in the second user control. Picture box and Indicator control were docked top and bottom inside the panel. A form containing the composite user control is run modally/modelessly. Could not reproduce faulty behavior.
Related
I have a form with a splitcontainer. One of the panels in the splitcontainer then loads a user control. This user control contains a combobox with the following properties changed from default:
DrowdownStyle=DrowDownList
FlatSyle=flat
Anchor=top,left,right
When the form and user control load, the combobox looks as expected:
However, if I resize the splitcontrol, it starts looking weird. If I increase the size of the panel that holds the control, this happens:
If i decrease the size of the splitter, it looks less weird, but still not how it is supposed to:
In either case, the combobox starts looking normal once I mouse over it.
Here is my code:
Main Form:
//Main form. Has a split container created from the toolbox
public partial class SampleForm:Form
{
public SampleForm()
{
InitializeComponent();
SampleControl cntrl = new SampleControl();
splitContainer1.Panel1.Controls.Add(cntrl);
splitContainer1.BorderStyle = BorderStyle.FixedSingle;
cntrl.Dock = DockStyle.Fill;
}
}
User Control:
//User control. Has a combobox created from toolbox. Options as described above
public partial class SampleControl : UserControl
{
public SampleControl()
{
InitializeComponent();
}
}
How can I fix this problem?
May be try to set dock to None . Also try to fix the margin for control
I know this is old, but was having the same problem and just in case someone finds themselves in the same predicament, answer below. Basically, create a new Class:
Imports System.Windows.Forms
Public Class MyComboBox
Inherits ComboBox
Protected Overrides Sub OnResize(e As EventArgs)
Me.Refresh()
End Sub
End Class
You can either drag this from your toolbox or add it in code. It will then auto redraw itself on resize of any parent controls.
Winforms is a bit like a sibling - flawed and deeply annoying sometimes - but you just gotta love it.
I'm experiencing some strange behavior. Let me try to explain, I stripped my code down to the bare minimum and I'm still having the problem. So first of all, I'm using VS2013 with .NET 4.0 and I'm on Windows 8.1.
So I have a custom UserControl with a TextBox that's being used through a ToolStripControlHost, if I focus on this textbox and hit TAB, it only cycles through the controls to the LEFT of this textbox. If I have it focused and hit SHIFT+TAB, it cycles through the buttons to the right of it.
So this is an example of my form. The textbox in the middle is a custom control. My code (as simplified as possible) looks like:
[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip | ToolStripItemDesignerAvailability.StatusStrip)]
public class ToolStripTestControl : ToolStripControlHost
{
public ToolStripTestControl() : this(new TestControl()) { }
public ToolStripTestControl(Control c) : base(c) { }
}
public class TestControl : UserControl
{
private TextBox _textBox = new TextBox();
public TestControl()
{
_textBox.Dock = DockStyle.Fill;
this.Controls.Add(_textBox);
}
protected override Size DefaultMinimumSize { get { return new Size(100, 22); } }
}
Simply creating a new WinForms (.NET4) project and following these steps will allow you to replicate the problem:
Add new class file and paste the code above.
Build
Add a ToolStrip to your form
On the ToolStrip add a Button, my custom control, and another Button (through the designer is how I've been doing it)
Run
Once running...
Focus in the custom control
Hit TAB a few times, it should only focus on controls to the left.
Hit SHIFT+TAB a few times and it will only focus to the right.
Does anyone know what the problem is - or how I can fix this? I've been tearing my hair out all day trying to fix this. I finally stripped my code down and I can't seem to get it to work. I even tried overriding much of the OnEnter/OnGotFocus functionality and doing it myself, but that became a nightmare.
Thanks!
Update1: So a few extra tid-bits.
If I change the custom control to inherit from TextBox instead of UserControl, tabbing/focus works as expected.
If I change it to be a Control instead of a UserControl the tabbing works fine, as well, however the focus never gets inside my inner TextBox - the focus seems to be lost (or presumably on the outer parent control but not being passed down to the inner TextBox).
I do see a MS Connect item added that describes this problem from 2009, but this link only seems to work if I'm NOT logged in to Microsoft Connect. Which means, I can't vote on it or comment... http://connect.microsoft.com/VisualStudio/feedback/details/472592/tab-cycling-through-controls-with-usercontrol-on-toolstrip-doesnt-perform-as-expected
The .NET 2.0 ToolStripItem classes have been a major bug factory. They are window-less controls, but reproducing the exact behavior of a Windows window isn't that easy. There is an enormous amount of code underneath, most of it internal so you can't tinker with it. And with quirks when they don't emulate the behavior of a window perfectly. You could call them "airspace" issues, pretty similar to the kind of problems that WPF has.
The airspace issue here is focus, entirely unambiguous for a true window but it needs to be faked for a ToolStripItem. It is actually the item's parent that has the focus, it needs to be emulated for the item. It is the transition that bytes, ToolStrip expects a window-based control to have a reliable Focus property.
Trouble is, your custom host doesn't. It is the inner control that has the focus. This could arguably be blamed on an omission in the ToolStripControlHost class. Probably. The trouble with emulating a window, there's never enough code :)
Anyhoo, fix your problem by adding this sliver of code to your host:
public override bool Focused {
get { return _textBox.Focused; }
}
I created one class library file for visual inherited form for my project. In the class library project I take one form. In this form I take one panel control and its Modifiers property set to public. Now my this form's name is BaseEditDialog and the BaseEditDialog.cs file is as following:
namespace BaseObjects
{
public partial class BaseEditDialog : System.Windows.Forms.Form
{
public BaseEditDialog()
{
InitializeComponent();
}
private void BaseEditDialog_Load(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Maximized;
}
public void BaseEditDialog_Resize(object sender, EventArgs e)
{
panel1.Left = (this.ClientSize.Width - panel1.Width) / 2;
panel1.Top = (this.ClientSize.Height - panel1.Height) / 2;
}
}
}
and in my actual project I take one inherited form selected with this BaseEditDialog.dll file
My first question:
but in this form when I move panel control it easily moves but when I resize my form then the panel control automatically move to the center of the form at the design time. I inherit this form because when my application actually run at run time at that time panel is automatically reside at the center position of the form. but in my problem at design time when I resize my form then panel is centered out of the form.
my second question:I cannot able to resize my panel control at design time.
You should probably check if you are in design mode in the Resize event.
If you are in design mode you should take some extra actions. Maybe you shouldn't try to center then the panel then?
Same goes for maximi,ing the form in the onload event.
Here is how to tell if you are running in deaign mode:
How to tell if .NET code is being run by Visual Studio designer
First off, I'll explain my program.
I have one winform that I use as my control panel. From here I have the ability to take a screen shot of my desktop using the mouse to define the area. Much like how the snipping tool works within windows.
The screen shot is generated using my screen shot class which is ran by another form called Form1. This second form has no other code in it but is simply used to generate the rectangle the screen shot will use. From here, the taken screen shot is stored in the clip board and passed back to my Screenshot class.
Now, from here what I want is a picture box in my control panel to display this taken image. Exactly like how the snipping tool works. However, the code I have wrote to pass this image to the control panel from the screen shot class complains that the event handler is always returning as null.
The code I have wrote for this is as follows:
Image img = (Image)bitmap;
if (OnUpdateStatus == null) return;
ProgressEventArgs args = new ProgressEventArgs(img);
OnUpdateStatus(this, args);
I've tried commenting out the if statement but then the processing OnUpdateStatus throws an exception saying it no longer exists.
Now, in my control panel form I am trying to grab that image and display with the following code:
private ScreenCapture _screenCap;
public ControlPanel()
{
InitializeComponent();
_screenCap = new ScreenCapture();
_screenCap.OnUpdateStatus += _screen_CapOnUpdateStatus;
}
private void _screen_CapOnUpdateStatus(object sender, ProgressEventArgs e)
{
imagePreview.Image = e.CapturedImage;
}
I've spent hours on this but i cannot work out why the image won't display in the image box on my ControlPanel. Can anyone with a fresh set of eyes help me out? Why is it the screen shot image I take, isn't being displayed in my picture box held on my ControlPanel?
This is the problem, I think (there's a lot of code to skim through - a short but complete example would have been better):
ScreenCapture capture = new ScreenCapture();
capture.CaptureImage(...);
That's a new instance of ScreenCapture. It doesn't have any event handlers attached to it (which is why you're seeing a value of null for OnUpdateStatus. If you want to use the instance that you've created in the ControlPanel class, you'll want to pass that to your Form1 (e.g. in the constructor).
Okay, I was able to create a simple Windows Forms project that reproduces some strange behavior I found. In the designer, make a form with a ListBox (named lbx) anchored Top, Left, Right, and Bottom, and a button (button1). Now, the Form's code is here:
using System;
using System.Windows.Forms;
namespace ListBoxKaboom
{
public partial class Form1 : Form
{
private bool _initFinished = false;
public Form1()
{
InitializeComponent();
this._initFinished = true;
this.Height += 100;
this.Height -= 50;
this.Height += 50;
}
private void lbx_SelectedIndexChanged(object sender, EventArgs e)
{
this.button1.Enabled = (this.lbx.SelectedItem != null);
}
protected override void OnLayout(LayoutEventArgs e)
{
if (_initFinished)
{
int lines = (this.lbx.Height - 4) / this.lbx.ItemHeight;
this.SuspendLayout();
while (lines < this.lbx.Items.Count)
{
this.lbx.Items.RemoveAt(this.lbx.Items.Count - 1);
}
while (lines > this.lbx.Items.Count)
{
this.lbx.Items.Add("Item " + (this.lbx.Items.Count + 1).ToString());
}
this.ResumeLayout();
}
base.OnLayout(e);
}
}
}
PLEASE NOTE THE FOLLOWING INSTRUCTIONS:
Run this, click any of the items in the list box, and use the arrow keys to move down far enough to cause the list box to scroll. Kaboom.
Exception (sometimes NullReferenceException and sometimes IndexOutOfBoundsException). Any ideas why? Also, I would think that the items would be in order, but they're not. Is this just a goofy corner case that didn't get handled properly by Windows Forms, or am I doing something wrong?
Stack trace:
at System.Windows.Forms.ListBox.NativeUpdateSelection()
at System.Windows.Forms.ListBox.SelectedObjectCollection.EnsureUpToDate()
at System.Windows.Forms.ListBox.SelectedObjectCollection.get_InnerArray()
at System.Windows.Forms.ListBox.SelectedObjectCollection.get_Item(Int32 index)
at System.Windows.Forms.ListBox.get_SelectedItem()
I Copy/Pasted it to an empty Form and get a StackOverflow exception. Looking at it, with manipulation of the Items inside a Layout event I would say you deserve little better.
I realize this may be a simplification of something else, but there simply are limits to what you can do in a EDS.
My best guess: The ResumeLayout triggers a recursive layout operation. You could try to stem it with a sibling to _initFinished but I would suggest rethinking tour design here.
I copy/pasted wrong, my bad (used layout event).
Second try:
based on the two while-loops I would expect the Item strings to be in order, and no vertical scrollbar. It is clear that the listbox is confused, showing vertical scroll range and with the items out-of-order. So some 'error' is already present in the internals of the Listbox, waiting for a Scroll. I can also reproduce it with the mouse.
A workaround: You should be able to get the desired effect using the Resize event.
Attempt to an explanation: The (unmanaged part of the) Listbox gets confused by (multiple) Add/RemoveAt operations with suspended Layout. The last items are drawn at the wrong place, and the Listbox can't compute pixel-to-item.
You should not manipulate any GUI elements in the
constructor, e.g. this.Height += 100; in your example.
Strange things can happen. I have been bitten by this
several times in legacy code.
Wait until form load time - handle the base.Load event and do the
height manipulation there.
From "When does Form.Load event get raised?":
Q: "... I need to find out basically
what the difference is between
putting code in Load event's handler,
versus putting code in the Form's
constructor after the
InitializeComponents() line ..."
A: "The Load event is fired once the
control/form has been fully
initialized and has a window handle
created. Therefore once this event
has fired it is a fully usable user
interface control. Remember that
inside the constructor the actual
window handle for the control/form has
not yet been created, you are only
creating C# objects here and inside
the InitializeComponent call."