I am trying to make some code more concise and am throwing an exception when I try to, I suppose, dynamically define a control. Whichever way I try, a and b always return as disposed. I could separate the cases out, but that would make the code twice as long. Any suggestion/comments would be much appreciated.
foreach (string[] str in items)
{
Control box = new Control();
CustomControlTypeA a = CustomControlTypeA();
CustomControlTypeB b = new CustomControlTypeB();
switch (str[4])
{
case "0":
a.richTextBox1.Rtf = str[5];
box = a;
break;
case "1":
b.panel1.BackgroundImage = Image.FromFile(str[5]);
box = b;
break;
}
a.Dispose();
b.Dispose();
box.Location = new Point(x,y);
box.Width = w;
box.Height = h;
panelBody.Controls.Add(box);
box.BringToFront();
}
I also tried defining CustomControlTypeA inside the case statement, redefining box as CustomControlTypeA, and even tried casting like so:
case "0":
(CustomControlTypeA)box.richTextBox1.Rtf = str[5];
break;
It's because you have a.Dispose(); & b.Dispose();. You're assinging one of them to box so it is also disposed.
Oddly though, you're creating box as a new Control (which you don't need to do), but not disposing that.
If you're adding a control to the .Controls collection you shouldn't be disposing it at all.
This code should work though:
foreach (string[] str in items)
{
Control box = null;
switch (str[4])
{
case "0":
CustomControlTypeA a = CustomControlTypeA();
a.richTextBox1.Rtf = str[5];
box = a;
break;
case "1":
CustomControlTypeB b = new CustomControlTypeB();
b.panel1.BackgroundImage = Image.FromFile(str[5]);
box = b;
break;
}
box.Location = new Point(x, y);
box.Width = w;
box.Height = h;
panelBody.Controls.Add(box);
box.BringToFront();
}
After lots of trial and error, I've now discovered that an aspect problem probably lies in the Rtf in my custom control, though who knows why that is. Enigmativity's method works if richtextbox.Text is used instead of richtextbox.Rtf.
EDIT: amended text to credit Enigmativity with solution. Either a typo elswhere in my code (setting str[5] to empty) or some other random code I changed in the meantime was exacerbating the problem.
Related
I'm converting our old program written in VB6 to C# WPF, and there is this code that I'm having a hard time trying to convert.
In our old VB6 project. The code is written like this:
Select Case paymentType
Case "CASH":
Set dlgpayment = New dlgPaymentCash
dlgPaymentCash.lblChange = format(-gvAmountDue - gvAddOnAmount, "0.00") '/NJ-2011/10/25 Added gvAddOnAmount
Case "CARD":
If PaymentTypeSupports(gvPaymentType, "multiple") And PaymentTypeSupports(gvPaymentType, "remember") And TypeName(dlgpayment) = "dlgPaymentCreditCard" Then
Else
Set dlgpayment = New dlgPaymentCreditCard
End If
dlgPayment is declared as:
Window dlgPayment = new Window();
so whenever I want to inherit other windows, I will just simply code like this:
Set dlgPayment = new dlgPaymentCash //dlgPaymentCash is a form.
And whenever I do this, I was able to access the controls in the form dlgPaymentCreditCard like dlgPaymentCash.lblChange, but it doesn't work in C#.
This is roughly the conversion:
switch (paymentType) {
case "CASH":
var dlgpayment = new dlgPaymentCash();
dlgPaymentCash.lblChange = string.Format("{0:0.00}", -gvAmountDue - gvAddOnAmount);
//NJ-2011/10/25 Added gvAddOnAmount
break;
case "CARD":
if (PaymentTypeSupports(gvPaymentType, "multiple")
&& PaymentTypeSupports(gvPaymentType, "remember")
&& typeof(dlgpayment) == "dlgPaymentCreditCard") {
//.....
} else {
var dlgpayment = new dlgPaymentCreditCard();
}
break;
}
If the format() function is the standard VB6 one, you can either use the string.Format() function, or simply the .ToString() function.
You can access a variable inside a Window by callling WindowName.VariableName like this:
switch(paymentType)
{
case "CASH":
Window dlgPayment = new Window();
//Access variable lblChange in dlgPayment
dlgPayment.lblChange="something";
break;
case "CARD":
break;
default:
break;
}
Given that you create a class which inherited the Window class (Which represent the form) :
in xaml.cs
public partial class PaymentDialog : Window //inherit Window
{
public string lblChange {get;set;} //this should be a textblock/label in xaml, but i just assume it is a string.
}
You need to create instance of PaymentDialog by:
PaymentDialog dlgPayment = new PaymentDialog(); //notice the different
dlgPayment.lblChange = "XXX"; //you now can access it
Window dlgPaymentWindow = new Window();
dlgPaymentWindow.lblChange = "XXX";//you cannot access it since
//lblChange is not exist in WPF Window class
I have a function that returns an object as Label for the sake of understanding let's call it "lblStatus".
public Label statusUpdater(int x)
{
Label lblStatus = new Label();
if (x==1)
{
lblStatus.text = "I like Cheese!";
}
else
{
lblStatus.text = "And I don't care!";
}
return lblStatus;
}
label1 = myclass.statusUpdater(1);
Would this be possible?
All I really need is to give all properties from a Label to another.
Not like this (label1 exists in designer)
What you are describing is known as a "Deep Copy". There are several ways to accomplish this that range in the amount of technical wizardry involved, but for your case, I would suggest keeping it simple and just using a helper method to duplicate all the properties you care about:
public static Label CopyLabel(Label label)
{
Label l = new Label();
l.Left = label.Left;
l.Top = label.Top;
l.Right = label.Right;
l.Bottom = label.Bottom;
l.Width = label.Width;
l.Height = label.Height;
l.Margin = label.Margin;
l.Text = label.Text;
// Add whatever other properties you deem important
return l;
}
And call it like so:
Label newLabel = CopyLabel(label1);
(If you really do want to perform a true deep copy, then you can check out existing answers here and here.)
Been fooling around with C# and ran into something that I was stumped on. Essentially, I have multiple RichTextBoxes that I want to change backcolor of all at once with the click of a button. I know the quick and dirty way is to just:
richTextBox1.BackColor = Color.Green;
richTextBox2.BackColor = Color.Green;
...
richTextBoxn.BackColor = Color.Green;
But for something like 100+ boxes, I am trying to aim for something a little compact in terms of programming. I was looking into using a for loop to solve my problem:
var richTextBox = new RichTextBox[6];
for (var i = 1; i < 7; i++)
{
var s = new RichTextBox();
this.Controls.Add(s);
richTextBox[i].BackColor = Color.Green;
}
But when I run the code, I get an exception issue of "An unhandled exception of type 'System.NullReferenceException' occurred..."
I hoping for a way to just change the backcolor of multiple RichTextBoxes/TextBoxes at once without having to write 100+ lines of code if I want to control 100+ backcolors at once.
If you want to change ALL the richtextboxes on your form you can do this:
foreach(var rtb in this.Controls.OfType<RichTextBox>())
rtb.BackgroundColor = Color.Green;
By using var s = new RichTextBox(); you are creating a new RichTextBox in each iteration and bind them to the form/Container. What you need to do in this scenario is that, assign BackColor to the new RichTextBox in each iteration. That is;
for (int i = 1; i < 7; i++)
{
var richBox = new RichTextBox();
richBox.BackColor = Color.Green;
this.Controls.Add(richBox);
}
In this case you need not to use var richTextBox array, If you are using var richTextBox array then your code will be like this:
var richBoxArray = new RichTextBox[6];
for (var i = 1; i < 7; i++)
{
richBoxArray[i].BackColor = Color.Green;
this.Controls.Add(richBoxArray[i]);
}
Updates as Per Comment:
So the Question is that;
How to change the background color of already existing RichTextBoxes
in my form
So the answer will be :
foreach(var richBox in this.Controls.OfType<RichTextBox>())
richBox.BackgroundColor = Color.Green;
I may confusing with the terminology, but here is what I'm trying to do:
I have a move function which will end up moving selected items from one listBox to another. There are three list boxes with two right and left arrow buttons in between each to move the first list box items to the middle, the middle back to the first, etc.
My function accepts the different button names via sender and in the switch statement, I want to choose which listBox are the selected items going to be send from and where they will be sent to. If that makes sense.
The while loop at the bottom is going to perform the actual move, depending on what is set for the "to" and "from" listBoxes.
My question is how can I in the scope of this function reference the names of the three existing listBoxes in each of the cases of the switch statement? I know initializing a new listBox like I've done is wrong and will just create some more listBoxes. Maybe for this case the easiest thing is to explicitly put the while loop in each of the case statements, but for the future in a more complex scenario, I still would like to know how this is done.
private void move(object sender, EventArgs e)
{
Button thisButton = sender as Button;
ListBox to = new ListBox();
ListBox from = new ListBox();
switch (thisButton.Name)
{
case "queueToProgressButton":
to.Name = "queueListBox";
from.Name = "progressListBox";
break;
case "progressToQueueButton":
to.Name = "queueListBox";
from.Name = "progressListBox";
break;
case "progressToCompletedButton":
to.Name = "queueListBox";
from.Name = "progressListBox";
break;
case "completedToProgressButton":
to.Name = "queueListBox";
from.Name = "progressListBox";
break;
}
while (from.SelectedItems.Count > 0)
{
to.Items.Add(from.SelectedItem);
from.Items.Remove(from.SelectedItem);
}
}
You should be using references to the existing list boxes, not allocating new ones. Also, your four branches of the switch are identical in the code you posted; I don't think that's what you intended. I made adjustments to the code based on what I think you meant to do in the switch.
Try something like this instead:
private void move(object sender, EventArgs e)
{
Button thisButton = sender as Button;
ListBox toListBox, fromListBox;
switch (thisButton.Name)
{
case "queueToProgressButton":
toListBox = progressListBox; // notice no "", but actual references
fromListBox = queueListBox;
break;
case "progressToQueueButton":
toListBox = queueListBox;
fromListBox = progressListBox;
break;
case "progressToCompletedButton":
toListBox = completedListBox;
fromListBox = progressListBox;
break;
case "completedToProgressButton":
toListBox = completedListBox;
fromListBox = progressListBox;
break;
// Should add a default just in case neither
// toListBox or fromListBox is assigned here.
}
while (fromListBox.SelectedItems.Count > 0)
{
toListBox.Items.Add(fromListBox.SelectedItem);
fromListBox.Items.Remove(fromListBox.SelectedItem);
}
}
I am using student record entry window form. I want that after submitting data, all fields of form(i.e radio button, combobox etc) and messages(warning and successful) should be reset so that new user can add data.
is their any built in function to reset form in csharp?
or I have to write clear method for this?
or can I regenerate the form?
You must first clear the controls and then use InitializeComponent method to work perfectly.
this.Controls.Clear();
this.InitializeComponent();
This you can achieve in two ways:-
1) you can clear the fields of the form in one method. say public void clear() And whenever you want to clear the form simply call this method.
2) In second way you can destory the instance of the form and generate the new instance of the same form and then show this.
I will recomeded 1st one for you.
This is what I used to create in my every page
private void ClearControls()
{
try
{
txtUserName.Text = string.Empty;
//txtPassword.Text = string.Empty;
txtFName.Text = string.Empty;
txtMName.Text = string.Empty;
txtLName.Text = string.Empty;
lblUserType.Text = string.Empty;
btnSave.Text = "Save";
fnMessage(false, "");
}
catch (Exception ex)
{
fnMessage(true, ex.Message);
}
}
Thanks
Implement data binding to a given object (good starting point here)
For resetting the form, create a new object and the binding will do it for you.
HTH
You can either re-create the form instance, or perhaps try something similar to this (untested):
foreach (Control ctl in this.Controls)
{
switch (ctl.GetType().ToString())
{
case "TextBox":
ctl.Text = null;
break;
case "ComboBox":
ctl.Text = null;
break;
}
}
Clearly, you can include as many different types of control as you wish and introduce other critieria (i.e. where control name begins with 'xyz' or where control resides within a particular panel).
Compared to other suggestions, the advantage of this approach is that if you have dozens of the same control type (typically textboxes), a few lines of code cover the lot. Additionally, if you add more controls of the covered types, you don't need to revisit the code to update it. Perhaps you could even create it as an extension method of your forms?
If form creation doesn't take too much resources it is easier to create new instance.
As i had same problem and my from was having nested controls. I tried CJM's method and it worked however i had to write a recursive function because of controls nesting (tab controls, containers, user controls etc)
Try out the following snippet if you want to clear whole form recursively
private void clearRecursive(Control control)
{
foreach (Control subcontrol in control.Controls)
{
switch (subcontrol.GetType().ToString().Replace("System.Windows.Forms.", ""))
{
case "TextBox":
TextBox textBox = (TextBox)subcontrol;
textBox.Text = null;
break;
case "ComboBox":
ComboBox comboBox = (ComboBox)subcontrol;
if (comboBox.Items.Count > 0)
comboBox.SelectedIndex = 0;
break;
case "CheckBox":
CheckBox checkBox = (CheckBox)subcontrol;
checkBox.Checked = false;
break;
case "RadioButton":
RadioButton radioButton = (RadioButton)subcontrol;
radioButton.Checked = false;
break;
case "TreeView":
TreeView tv = (TreeView)subcontrol;
foreach (TreeNode node in tv.Nodes)
{
node.Checked = false;
CheckChildren(node, false);
}
break;
case "ListBox":
ListBox listBox = (ListBox)subcontrol;
listBox.Items.Clear();
break;
case "CheckedListBox":
CheckedListBox chklstbox = (CheckedListBox)subcontrol;
for (int i = 0; i < chklstbox.Items.Count; i++)
{
chklstbox.SetItemCheckState(i, CheckState.Unchecked);
}
break;
}
if (subcontrol.HasChildren)
clearRecursive(subcontrol);
}
}
Call InitializeComponent method and Form_Load method.