I have a TableLayoutPanel with a grid of PictureBox controls within it. I'm trying to find a shortcut way to change them all to Label controls instead of manually deleting each one and placing new controls in each cell.
I thought I could go into the designer code and find/replace PictureBox with Label, but now I get an
"Object does not match target type"
error in Visual Studio's error list. I can't view the designer page now either. Is this not allowed? If it is allowed, what's the right way to do it?
If you take a closer look at the generated code:
label1:
this.label1 = new System.Windows.Forms.Label();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(134, 163);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(35, 13);
this.label1.TabIndex = 1;
this.label1.Text = "label1";
pictureBox1:
this.pictureBox1 = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
//
// pictureBox1
//
this.pictureBox1.Location = new System.Drawing.Point(97, 75);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(100, 50);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
My guess is that the
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
is changed by you into something like:
((System.ComponentModel.ISupportInitialize)(this.label1)).BeginInit();
which doesn't work, and results in designer issues. Object does not match target type.
so, apply the changes you already did, remove the lines like:
((System.ComponentModel.ISupportInitialize)(this.label1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.label1)).EndInit();
and I think you're good to go.
Don't change designer code. That stuff is automatically generated. Not only can your changes cause unexpected behavior, but they can get over-written as well.
I would attempt to make a change or 2 to your form, or whatever your designer is behind, and hope it regenerates all it's code.
You can delete all the picture boxes in the designer, then add all the labels in the _load event (or another convenient event). That way it will be easier to change next time.
As Haxx illustrated, you will have to clean-up the extra initialization PictureBox requires as well. The error you received is a interface casting error. In your case, as Haxx guessed, the Label control doesn't implement the ISupportInitialize interface.
Unlike most, I am not afraid of changing designer code in the interest of expediency, for what you are doing, it is ok to do so. Just know your objects, check-in prior to doing so, and don't put custom code in there!
Related
I am doing brownfield development, and have to deal with lots of old forms with code that looks like this.
//
// Button1
//
Button1.Location = new System.Drawing.Point(556, 447);
Button1.Name = "Button1";
Button1.Size = new System.Drawing.Size(136, 23);
Button1.TabIndex = 112;
Button1.Text = "Restart kontor";
Button1.Click += Button1_Click;
If I try to edit one of these forms, the form is upgraded. All the identifiers will then have the "this" qualifier prepended. Unfortunately Visual Studio 2015 will also simply strip away all event handler assignments in the file. That means the last line in the above example snippet will simply vanish.
Why does this happen? Is there a very simple way to prevent it?
I have found a workaround that is reasonably quick to work through for each form. The workaround is posted as an answer. It will cut my work upgrading these forms from days to hours.
If anybody knows of a quicker way, a proper fix perhaps, I'd like to know.
Workaround
Editing an entire form to fix broken event handler assignments can be very time consuming. This workaround speeds up the process significantly, by fixing the source before the designer tries to upgrade it. (I do not know if "upgrade" is the proper term, but who cares...)
Before allowing the designer to upgrade the form, edit the form source manually in this way.
Edit all lines with event handlers so that they explicitly do a new System.EventHandler. All you have to do to find the relevant lines is to search for "+=". This is what the line in the snippet from the question will look like then.
Button1.Click += new System.EventHandler(Button1_Click);
When this is done, you must somehow trigger the designer to upgrade the form. This can be done e.g. by changing the title of the form via the designer, and then change it back. The designer will now hopefully correctly upgrade all lines. The entire snippet in the question will then look like this after upgrade.
//
// Button1
//
this.Button1.Location = new System.Drawing.Point(556, 447);
this.Button1.Name = "Button1";
this.Button1.Size = new System.Drawing.Size(136, 23);
this.Button1.TabIndex = 112;
this.Button1.Text = "Restart kontor";
this.Button1.Click += new System.EventHandler(this.Button1_Click);
So far this way to handle the problem leaves me with upgraded forms that are easy to compare with the original forms, which is important when verifying the upgrades.
I have no code to show because this is a problem with me not understanding the behavior of the designer in VS2015 using C#. I have added a series of labels to a panel, so I can iterate through them in code. The problem is, it seems no matter what order I add the labels to the panel, the indexes of the controls make no sense.
Here is a screen shot. The back colored labels to the right are all contained in a separate panel. I have coded the labels to show their index within the panel container.
These were added one at a time from the bottom up. How can I manually add the labels and still have predictable indexes?
Any help is appreciated.
This is the result after making the labels the same size, renaminging them lbl0, lbl1 etc. and adding them one at a time from top to bottom....
You can see where controls are added to the control collection if you look in the Form.Designer.cs file, which is part of the class definition for your form.
Here you will see a section that begins with // Form, and under that you will see where it calls `this.Controls.Add();
The items in this list appear in the order in which you dropped them onto the form (at least for me they do). I just copy/pasted 10 labels onto the form, and I see this:
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 684);
this.Controls.Add(this.label10);
this.Controls.Add(this.label9);
this.Controls.Add(this.label8);
this.Controls.Add(this.label7);
this.Controls.Add(this.label6);
this.Controls.Add(this.label5);
this.Controls.Add(this.label4);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
At runtime, the controls are found in the collection exactly as you would expect from reading the code above; the last control added is at index [0]:
Now, adding a panel is a slightly different story, but not much. Because the Panel is a container object, the labels get added to the Panel controls collection:
//
// panel1
//
this.panel1.Controls.Add(this.label18);
this.panel1.Controls.Add(this.label17);
this.panel1.Controls.Add(this.label16);
this.panel1.Controls.Add(this.label15);
this.panel1.Controls.Add(this.label14);
this.panel1.Controls.Add(this.label13);
this.panel1.Controls.Add(this.label12);
this.panel1.Controls.Add(this.label11);
this.panel1.Location = new System.Drawing.Point(37, 366);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(200, 172);
this.panel1.TabIndex = 13;
Note, however, that the behavior is the same. The most recent control is added to the Controls collection first, and will be in the Panel.Controls[0] position.
I'm confused with the RichTextBox control.
I have a RichTextBox control of my WinForm with a width of 100px. I want to create one dynamically and then reference the instance.
So, assuming on my Form I have a RichTextBox called rtbResult I would have thought I can do the following:
RichTextBox rtb = new RichTextBox();
rtb.Text = "Hello all";
rtb.Width = 50;
rtbResult = rtb;
When the code executes, the result is an empty RichTextBox on my page, at the original size of 100px (eg, not at width 50).
Please note, in live I'm using text highlighting and as such it must be a RichTextBox, the example above is stripped to make the question more concise.
Any ideas what I'm doing wrong?
What you did is not so different from this:
RichTextBox r1 = new RichTextBox();
r1.Text = "I am RTB #1";
Controls.Add(r1);
RichTextBox r2 = new RichTextBox();
r2.Text = "I am RTB #2";
Now on your page you have the RichTextBox named r1. If you do this:
r1 = r2;
You do not replace the control in the form with the new RichTextBox, you simply assign the same reference to the variable r1. In your form you still have the old control but both variables (r1 and r2) point to the same object.
What you may do, if you can't simply update the original RichTextBox with new values, is to delete the old one and to add the new one in the same position:
r2.Bounds = r1.Bounds;
Controls.Remove(r1);
Controls.Add(r2);
This is pretty naive, many properties may need to be copied from the old one to the new one (Dock, TabIndex and so on), moreover the order is important too so you may need to call Controls.SetChildIndex() for proper positioning (this depends on what you really have to do and how your code is).
The rtbResult is just a variable that contains a reference to the control, it's not the control itself. By putting the new control in that variable you are only changing the variable, the original control is still in the form, and the new control doesn't belong to any form so it's not visible anywhere.
You have to add the new control to the form to make it visible, for example:
somePanel.Controls.Add(rtb);
I am not sure what is going on here. I am following the example provided by Microsoft. Everything is done on the back end because I need to decide if you user should enter stuff into a text field or should the text field value be displayed as normal text. The code is as follows:
nameInput.Name = "inputName";
nameInput.Text = "Journey Name";
nameInput.KeyUp += onNameInput;
ColorAnimation animation = new ColorAnimation();
animation.From = Colors.Blue;
animation.To = Colors.White;
animation.Duration = new Duration(TimeSpan.FromMilliseconds(100));
animation.RepeatBehavior = RepeatBehavior.Forever;
Storyboard.SetTarget(animation, nameInput);
Storyboard.SetTargetProperty(animation, new PropertyPath(TextBlock.ForegroundProperty));
storyBoard.Children.Add(animation);
journeyStackPanel.Children.Add(nameInput);
ClockState state = storyBoard.GetCurrentState();
storyBoard.Begin(); //<---Crashes here
I am following the
http://msdn.microsoft.com/en-us/library/cc672995(v=vs.95).aspx
example. I am not sure what is going on, unfortunately the debugger does not spit out any more information. Maybe I am missing a step? I am sorry that I am being a little vague but this is all the information I have on the issue.
Any help is greatly appreciated!!
I was able to replicate this problem on the latest WP8 SDK, with the following error message generated:
ColorAnimation cannot be used to animate property Foreground due to
incompatible type.
I believe this is because you're trying to change the Foreground property of the TextBox to a Color object, but Foreground is actually a Brush object, hence the Type Mismatch error. Instead, you have to change the Color property of the Foreground object.
Try this instead:
Storyboard.SetTargetProperty(animation, new PropertyPath("(Foreground).(Color)"));
What is the C# equivalent of Delphi's DisableControls/EnableControls methods (used to disable updating of databound controls while iterating through the underlying dataset)? I have googled for half an hour and did not find an answer...
I have a list box and a rich edit box bound to a binding source, but I need to do an operation that iterates through the entire dataset, and both controls get updated as I move through the underlying dataset. In Delphi this is easy enough: enclose the block that does the iteration between DisableControls and EnableControls. I can't find the C#/.NET equivalent, and I have looked really hard!
IIRC, setting Enabled to false does not prevent the controls from reacting to data changes in WinForms.
Collection-bound controls like the ListBox typically have methods BeginUpdate() and EndUpdate() which temporarily disable visual updates.
Also, the property mentioned by DarkSquirrel might be worth a look
I don't have access to Visual Studio right now, so I can't test this, but look through the methods for the control instance. Code such as:
// set the Enabled property of
// the controls to False; this should
// disable the controls for user access
listBox.Enabled = False;
richEditBox.Enabled = False;
// perform iteration
// and other operations
// set the Enabled property back
// to True
listBox.Enabled = True;
richEditBox.Enabled = True;
The exact name of the property may differ slightly, but I'm pretty sure that this is what it is.
I assume you are using WinForms, in that case you can try using the methods SuspendLayout/ResumeLayout.
Code sample from MSDN:
private void AddButtons()
{
// Suspend the form layout and add two buttons.
this.SuspendLayout();
Button buttonOK = new Button();
buttonOK.Location = new Point(10, 10);
buttonOK.Size = new Size(75, 25);
buttonOK.Text = "OK";
Button buttonCancel = new Button();
buttonCancel.Location = new Point(90, 10);
buttonCancel.Size = new Size(75, 25);
buttonCancel.Text = "Cancel";
this.Controls.AddRange(new Control[]{buttonOK, buttonCancel});
this.ResumeLayout();
}
So far I know, you don't need to Disiable/EnableControls in C#, since this type of DataSet doesn't work with a current cursor, like Delphi TDataSets.