Exist control in current form? - c#

I need to find out if component with some name exist in current form.
I have name of the component in string variable and if it doesnt exist, i need create it.
I use this code
Control c = Controls.Find(New, true)[0]; //najiti komponenty
if (c == null) {}
But it gives me error that the index was outside the bounds of the array.
I know this code is bad, but i dont know to write it good and google dont help me.

Find method return an array of controls, i.e. Control[]. You are trying to access the first element of the empty array, thus resulting in IndexOutOfRangeException
You should try:
Control[] controls = Controls.Find(New, true);
if (controls.Length > 0)
{
//logic goes here
}
else
{
//no components where found
}

Try using the Control.ContainsKey() Method, (pass a string variable containg the control name instead of the quoted text in my example):
if (!this.Controls.ContainsKey("MyControlName"))
{
// Do Something
}

Related

How to Dispose() a specific User control from panel control in C#?

I want to dispose a specific type of User control from panel. Right now i am using foreach loop to dispose the User control.
foreach (CTRL.box bx in RightPanel.Controls.OfType<CTRL.box>())
{
bx.Dispose();
}
But it is not working properly. while checking in google i find the below code.
while(tabControlToClear.Controls.Count > 0)
{
var tabPage = tabControlToClear.Controls[0];
tabControlToClear.Controls.RemoveAt(0);
tabPage.Dispose();
// Clear out events.
foreach (EventHandler subscriber in tabPage.Click.GetInvocationList())
{
tabPage.Click -= subscriber;
}
}
I am trying to do this, But for me it is a specific User control i need to dispose. they are other User controls which should be required in my form. Overall i want to dispose box User control from my form.
while (RightPanel.Controls.OfType<CTRL.box>().Count() > 0)
{
var panel = RightPanel.Controls.OfType<CTRL.box>()[0];//Here i am getting error "Cannot apply indexing with [] to an expression of type 'System.Collections.Generic.IEnumerable<Project_Server.CTRL.box>'"
}
Can anyone help me to fix this error.
Error is pretty clear, you cannot apply indexing on IEnumerable
I would suggest use First or FirstOrDefault extension method to retrieve first element and delete it.
var panel = RightPanel.Controls.OfType<CTRL.box>().FirstOrDefault();
if(panel != null)
{
//logic
}
In case, if you would like to remove all controls of type CTRL.box use this.
List<Control> controls= RightPanel.Controls.OfType<CTRL.box>().ToList();
foreach(Control c in controls)
{
RightPanel.Controls.Remove(c);
c.Dispose();
}

Read assembly MethodBody, parse its Name in a ListBox and its IL in a TextBox?

I have a WPF MainWindow Form with a ListBox and a TextBox that looks like this:
Figure A. WPF MainWindow with Sample Text.
Now, the Load Assembly... OnClick button event allows me to select a .NET Assembly and load it up using DnLib
Then, if I want to display the Methods bodies I would do it like so:
Assembly asm = Assembly.LoadFile(filename);
foreach (Module mod in asm.GetModules())
{
foreach (Type types in mod.GetTypes())
{
foreach (MethodInfo mdInfo in types.GetMethods())
{
listBox.Items.Add(mdInfo.Name);
}
}
}
This adds each found Method name to the ListBox on the left, resulting like so:
Figure B. Showing the ListBox Filled with Methods Names
Now the trick part, I would like to for whichever method I select from the ListBox to display its respective MethodBody IL on the TextBox
How can I achieve such thing?
«Phew!» Finally Solved it!
Here's the solution for whoever tries to do the same thing in the future.
Make an instance of 'List' and then iterate through the methods and assign the names to such list, then whenever your SelectedItem index value changes, I can simply call GetMethodBodyByName and then I can surely solve this issue
Here's how to implement the function GetMethodBodyByName:
public string GetMethodBodyByName(string methodName)
{
ModuleDefMD md = ModuleDefMD.Load(filename);
foreach (TypeDef type in md.Types)
{
foreach (MethodDef method in type.Methods)
{
for (int i = 0; i < type.Methods.Count; i++)
{
if (method.HasBody)
{
if (method.Name == methodName)
{
var instr = method.Body.Instructions;
return String.Join("\r\n", instr);
}
}
}
}
}
return "";
}
The idea is that 'GetMethodBodyByName' will receive the method name as a parameter, then it will iterate through methods and see if a method matches the given name, then if found, the function will just simply iterate through that method and output the method's body.
Here's how my ListBox_SelectedItemChanged event looks like:
private void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
textBox.Text = "";
textBox.Text = GetMethodBodyByName(method[listBox.SelectedIndex].Name);
}
That's All Folks!
Note: Be careful when doing this approach as if when you request names, different methods can have the same names. But that's a cake for another day, I'm done for now! take care bye-bye!
Working our way up for the Ultimate Solution!
The WPF MainWindow Forms carry with themselves two little useful properties, they are: Tag and Content, the idea is the following one:
With the Tag and Content Property we can assign any values to it that later it can be retrieved On-The-Fly without having to depend on Methods names specifically for this task.
So you would instead of looping each method and get its name respectively you can just do the way I did:
Iterate through the Method, and assign its body to the Tag property, and its name to the Content property, as this last property is the one that handles the actual Title property, so disregarding anything you do with the method in the future and even if it had the same name of another one, it will work no matter what.
How Can We Implement It?
Simply:
<...>
// Inside Method Body iteration routine...
<...>
var instr = mdInfo.Body.Instructions;
// Allocate in a new `ListBoxItem` each method and add it to the current listbox with their
// ... respective Tag and Content information... // Many Thanks Kao :D
newItem = new ListBoxItem();
newItem.Content = mdInfo.Name;
newItem.Tag = string.Join("\r\n", instr);
method.Add(mdInfo);
listBox.Items.Add(newItem);
Then on your SelectedItem Index-Value-Changed Event put this:
MSILTextBox.Clear();
// Retrieve them given the selected index...
// ... the returned value will be the Tag content of the ...
// ... previously saved item.
string getTag= ((ListBoxItem)listBox.SelectedItem).Tag.ToString();
MSILTextBox.Text = getTag;

Checking Multiple textbox if they're null or whitespace

I have a form where I have lots of textboxes and all of them are required to be filled out. In C# how do I actually if check there are group of fields having a null or whitespace?
I am familiar with string.isNullOrWhiteSpace(string here) but I don't want to do multiple if statements of that, it would result in a bad code.
I am trying to avoid something like this
if(string.isNullOrWhiteSpace(string here)
|| string.isNullOrWhiteSpace(string here)
|| string.isNullOrWhiteSpace(string here))
{
// do something
}
Are there fix for this type of bad code?
You can query the controls collection of the form (or relevant container) and filter for textboxes and further query to see if any are empty (none should really have null values). Example:
var emptyTextboxes = from tb in this.Controls.OfType<TextBox>()
where string.IsNullOrEmpty(tb.Text)
select tb;
if (emptyTextboxes.Any())
{
// one or more textboxes are empty
}
You can do effectively the same thing using the fluent syntax.
bool isIncomplete = this.Controls.OfType<TextBox>().Any(tb => string.IsNullOrEmpty(tb.Text));
if (isIncomplete)
{
// do your work
}
For this code, you should be working with at least Visual Studio 2008 / C# 3 / .NET 3.5. Your project needs to have a reference to System.Core.dll (should have one by default) and you need a using System.Linq; directive in the class file.
Based upon your comments, consider another method if you are having trouble understanding or working with the linq version. You can certainly do this in an explicit loop (the Linq code will ultimately be a loop as well). Consider
bool isIncomplete = false;
foreach (Control control in this.Controls)
{
if (control is TextBox)
{
TextBox tb = control as TextBox;
if (string.IsNullOrEmpty(tb.Text))
{
isIncomplete = true;
break;
}
}
}
if (isIncomplete)
{
}
Finally, this code is written as if all of the textboxes are in a single container. That container might be the form, a panel, etc. You will need to point to the appropriate container (eg., instead of this (the form) it might be this.SomePanel). If you are working with controls that are in multiple and perhaps nested containers, you will need to do more work to find them programmatically (recursive searching, explicit concatenation, etc.) or you might just preload the references into an array or other collection. For example
var textboxes = new [] { textbox1, textbox2, textbox3, /* etc */ };
// write query against textboxes instead of this.Controls
You said you have multiple GroupBox controls. If each GroupBox is loaded onto the form and not nested in another control, this may get you started.
var emptyTextboxes = from groupBox in this.Controls.OfType<GroupBox>()
from tb in groupBox.Controls.OfType<TextBox>()
where string.IsNullOrEmpty(tb.Text)
select tb;
That depends on what you consider "bad code." Depending on your requirements what text boxes are required to be filled out can vary. Further, even if all of the fields are required all of the time you still want to give friendly error messages letting people know which field they didn't fill out. There a variety of approaches to solving this issue depending on how you are rendering your form. Since you haven't specified any here's a very direct method for doing so.
var incompleteTextBoxes = this.Controls.OfType<TextBox>()
.Where(tb => string.IsNullOrWhiteSpace(tb.Text));
foreach (var textBox in inCompleteTextBoxes)
{
// give user feedback about which text boxes they have yet to fill out
}
Yet another solution.
This will recursively travel the whole control Tree , and Check for null or empty text in all of the textboxes.
caveat -
If you have some fancy controls not inheriting from the standard Winforms textbox - check will not be performed
bool check(Control root,List<Control> nonFilled)
{
bool result =true;
if (root is TextBox && string.isNullOrEmpty(((TextBox)root).Text) )
{
nonFilled.Add(root);
return false;
}
foreach(Control c in root.Controls)
{
result|=check(c,nonFilled)
}
return result;
}
Usage :
List<Control> emptytextboxes=new List<Control>()
bool isOK=check(form, emptytextboxes);

Saving and loading TextBox or other control values with a text file

I know that this is possible to be done with application settings, but I want to do it this way:
I have some textboxes and other controls that have Text property. I am doing a loop and save the Name and Text property of them in a text file. The saving statement is like:
if (ctrl != null) sb.AppendLine(ctrl.Name.ToString() + ":" + ctrl.Text);
When I want to load them back I want to do it this way, but since I can not point to the Name of the controls, I am stuck! (I beleive it was possible in PHP to point to a variable using other variables!)
using (StreamReader file = new StreamReader(ofile.FileName))
{
while((line = file.ReadLine()) != null)
{
if (line.StartsWith("#")) continue; //Line is a commment so skip
else
{
data = line.Split(':');
//How to set back the text property to the variable?
}
}
}
What I have in mind now, is to save Tag property of controls instead of theire Name property. But the problem is my controls are all scaterred in side nested panels and stuff like that so I have to do a lot of LOOPING! to compare theire tags with tags avilable in my saved file (note that I am not going to save all controls in the text file, just some of em!)
What to do ?
You can find control by it's name if you have access to form's Controls property
var textBox = yourForm.Controls.Find("name", true) as TextBox;
if(textBox != null)
textBox.Text = "text";
Store all your controls in a key value pair container where key is the name of the control and value is a reference to the control it self. You can use a Dictionary to store them. When loading back from the text file, use the key to find the appropriate control and set the text.
your question is unclear .what i understand is you want to write text property to a text file and later restore via txt file if so then its a straighforward solution [in Winform]
to save use the format control-name:text
later on load
use
this.Controls[<controlname>].Text=Text
i.e. in your context
while((line = file.ReadLine()) != null)
{
if (line.StartsWith("#")) continue; //Line is a commment so skip
else
{
string[] data = line.Split(':');
if(data.Length>0)
{
if(this.Controls.ContainsKey(data[0]))
{
if(this.Controls[data[0]] is TextBox)
{
//generic
// this.Controls[data[0]].Text=data[1];
//or use
((TextBox) this.Controls[data[0]]).Text=data[1];
}
}
}
}
}
please note that this.Controls return a Control Object if you want to do any specific operations please Type Cast and then apply.
Also if you try to access
Hope that helps.

Problem looping through web controls

I've got a web page where I am dynamically creating controls during Page_Load event (this is done so because I do not know how many controls I will need until session is active and certain variables are accessible)
I need to be able to loop through these controls to find Checkbox when a button click is processed. Looping through the Form.Controls does not appear to be sufficient. I would think that Request.Form might work but it does not appear to be accessible in my C# block?
What should code for Request.Form look like? OR
Has anyone done this before with dynamically created controls?
Any insight is appreciated.
Simplified Example from MSDN:
var myControl = FindControl("NameOfControl");
if(myControl != null)
{
//do something
}
else
{
//control not found
}
Hope this helps! ;)
Your controls will be accessible trough the Controls collection of their immediate parent. Unless you add them like Page.Form.Controls.Add (myControl);, you won't find it in Page.Form.Conttrols. If you add them to a place holder, you must find them in thePlaceHolder.Controls.
LinkButton myDynamicLinkButton = new myDynamicLinkButton ();
myDynamicLinkButton.ID = "lnkButton";
myPlaceHolder.Controls.Add (myDynamicLinkButton);
//........
LinkButton otherReferenceToMyLinkButton = myPlaceHolder.FindControl ("lnkButton");
As #David said in his comment, you should probably think about using a Repeater instead. It would probably simplify your case a lot.
Since the controls might be nested in other controls, you need to search recursively. You can use this method to find the control:
public Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
{
return root;
}
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, id);
if (t != null)
{
return t;
}
}
return null;
}
And you can implement it this way:
CheckBox check = FindControlRecursive(Page.Form, "CheckBox1");
You should have access to Request["xyz"] anywhere in your aspx.cs code. You can either find control as described above and read it's value or do so directly from Request using the Control.UniqueID property. For example if it's a checkbox that's within the repeater then the UniqueID would look like dtgData$ctl02$txtAmount
Thanks for the insight guys. I kind of took the discussion and ran with it and found my solution that worked best for me.
foreach(String chk in Request.Form)
{
if (chk.Contains("chkRemove"))
{
int idxFormat = chk.LastIndexOf("chkRemove");
objectname = chk.Substring(idxFormat);
}
}
Turned out really all I needed was the name. The string contained a number at the end which was needed to determine a position of datatable items. Thanks for the advice!

Categories