C# - Keep track of open child forms - c#

I currently have a parent control (Form1) and a child control (Form2).
Form1 contains a listview that stores a list of of file data (each file is a separate item).
Form2 contains only a textbox.
Upon clicking on one of these listviewitems in Form1, Form2 is opened up and accesses the file's data and loads it into the textbox in Form2 in plain text format.
The issue I'm having is, I would like to be able to detect, upon clicking of a listviewitem, whether that file is already opened in said child form and if so, to activate it (bring it to the front) and if it is not already opened, open it. I'm not sure what the best method of doing this would be since this can involve many child forms being open at once. This is not an MDI application. Any ideas on how this could be accomplished are appreciated and samples even more so. Thank you.

What I have done in the past is give each new form a unique tag (based on the file you're viewing in this case), so:
var form = new Form2();
form.Tag = (object)"My Unique Object as a Tag"; // Redundant cast I know, but shows Tag is of type object
Then, when going to open up a window for a file, iterate over all the open forms checking tags like so:
foreach(var f in Application.OpenForms)
{
if(f.Tag == tagForFile)
{
f.BringToFront();
return;
}
}
// Couldn't find one, so open on
var form = new Form2();
form.Tag = tagForFile;
form.Show();
And this should only open up one form per file (or tag really)
Hopefully that helps !

You could simply maintain a Dictionary<ListViewItem,Form>. Each time you open a new form add an entry to the dictionary. If the dictionary already contains the ListViewItem that was clicked as a key then you don't need to open a new form.

Assuming form is created for every selected item you could keep track of opened forms in ListViewItem's tag.
lv.ItemSelectionChanged += lv_ItemSelectionChanged;
private void lv_ItemSelectionChanged(Object sender, ListViewItemSelectionChangedEventArgs e)
{
if(e.IsSelected)
{
if(e.Item.Tag == null)
{
var form = new Form2();
// init Form2 here
form.Parent = this.panel1;
e.Item.Tag = form;
}
(e.Item as Form2).BringToFront();
}
}
EDIT:
On the other hand why would you create and switch between forms which have only one Edit, it would be much simpler to just fill TextBox with file contents:
ListView1.ItemActivate += ListView1_ItemActivate;
private void ListView1_ItemActivate(Object sender, EventArgs e)
{
if(ListView1.SelectedItems.Count > 0)
{
this.form2Instance.ContentsTextBox.Text = File.ReadAllText(this.rootFilesPath + #"\" + ListView1.SelectedItems.Last().Text));
}
}
And if you wamt to read file contents only once, just save file contents in ListViewItem's tag
ListView1.ItemActivate += ListView1_ItemActivate;
private void ListView1_ItemActivate(Object sender, EventArgs e)
{
if(ListView1.SelectedItems.Count > 0)
{
var item = ListView1.SelectedItems.Last();
if(item.Tag == null)
item.Tag = File.ReadAllText(this.rootFilesPath + #"\" + item.Text);
this.form2Instance.ContentsTextBox.Text = (string) item.Tag;
}
}

Related

Call a Method in a DockPanel Document

I have a dictionary list of forms which are Documents within DockPanelSuite (Windows Forms) When a button on the main form is pressed all the document's "Contents" contained in the first control (ScintillaNet Editor instance) of the Document Form should be saved.
However, accessing the Save() method of the form is proving frustrating.
Currently this is the code:
private void btnCompile_Click(object sender, EventArgs e)
{
// Save the Project.
foreach(var editor in EditorList)
{
if(editor.Key.StartsWith(CurrentProjectModel.Name))
{
FrmCodeEditor fce = new FrmCodeEditor();
fce = (FrmCodeEditor)editor.Value;
fce.Save();
}
}
IDA.Controllers.CLI.Exec exec = new Controllers.CLI.Exec();
exec.ExecuteCompiler();
}
editor is the name of the form, EditorList is the Dictionary which contains a list of all active Documents. However, the fce.Save is not being found.
Question
All I want to do is iterate through all the open Documents which are FrmEditor types and call their Save method. How can I do that?
As it turned out - the method I was trying to call was static. However, this was not being flagged in intellisense.

Items in checklistbox deleted after form closes

I have a simple c# winform and I'm trying to add a string to it.
e.g.
checklistbox1.Items.Add("string");
the problem is that after I close the form and run the program again, my added string is deleted from the checklistbox and I have to enter it again.
When you close the form, the members associated with it are removed as well. If you want it to be saved, you need to use a method that well save the data for you, such as XML, txt doc, or even a database, depending on the lifespan of the information you want to keep.
If it is only needed while the program is running, you may look into having the information stored in a member in the mainform rather than only just the form with the checklistbox.
Add a public List property to your form.
Create a second ctor for your form and inside your second ctor code
write:
public YourForm(List<string>() strings)
{
foreach(var item in strings)
{
checklistbox1.Items.Add(item);
}
}
You don't have to unload the form when closing. Let the parent form - I assume this is launched from another form - do the unloading/disposing of all the child forms instead. The trick is to make it appear to the user that you're closing the form. Let's say the form containing the checklist is Form2, the function that loads Form2 from the parent form will look like this:
Form2 _form2 = null;
private void button1_Click(object sender, EventArgs e)
{
if (_form2 == null)
{
_form2 = new Form2();
}
_form2.Show();
}
And in the Form2, handle the Closing event like this:
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
Hide();
}
And finally, in the parent form Closing event, you can dispose Form2
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (_form2 != null)
{
_form2.Dispose();
_form2 = null;
}
}
If you need to have the same set of values for all instances of Form2, then you can use Singleton pattern. That's another discussion :)

c# - how to change button image on all my forms

I have got three forms and on one of them there is a combobox which is supposed to change icons on all my running forms and images of buttons located on another forms, when selected value of the combobox is changed.
Please note that the problem is solved when it comes to changing icons, but I need solution for changing buttons images. I have managed to do so on just one form (where the combobox is located). I cannot figure out how to customise buttons on other forms as well.
I have tried this way:
private void combo_Theme_SelectedValueChanged(object sender, EventArgs e)
{
Main f1 = new Main();
if (combo_Theme.Text == "Purple")
{
foreach (var form in Application.OpenForms.Cast<Form>())
{
form.Icon = Properties.Resources.Purple;
f1.btn_Exit.Image = Properties.Resources.EXIT_purple;
}
}
... but had no success.
Basically, I am stuck now, since the code above doesn't work for me.
Any ideas?
You should re-design your forms by implementing some interface with some method, calling that method will actually update the images of the buttons on a specific form. That way you don't have to loop through each controls (in nested relationship) and check out every button. However if your forms don't have complex nested relationship and the number of buttons is small, we can use the following code, in fact this code still works OK (responsive enough) when you have thousands of controls on a form with several nested containers):
public IEnumerable<Button> GetAllButtons(Form form){
Stack<Control> controls = new Stack<Control>();
controls.Push(form);
while(controls.Count > 0){
var control = controls.Pop();
foreach(var c in control.Controls){
if(c is Button) yield return c;
controls.Push(c);
}
}
}
//now use that method in your code like this:
private void combo_Theme_SelectedValueChanged(object sender, EventArgs e)
{
Main f1 = new Main();
if (combo_Theme.Text == "Purple")
{
foreach (var form in Application.OpenForms.Cast<Form>())
{
form.Icon = Properties.Resources.Purple;
f1.btn_Exit.Image = Properties.Resources.EXIT_purple;
//looping through each button on the current form
foreach(var button in GetAllButtons(form)){
//your code here
button.Image = Properties.Resources.EXIT_purple;
}
}
}
//...
}

Keep form on top and open and close other forms

I'm new to C# and could use some help.
What I have so far is a set of 8 windows forms I have created in C#, these forms have basic things like text boxes, labels, radio buttons, etc. Now that I have completed making all of these forms I want to have one additional form (called the Selector form) I can use to select one of the other 8 forms. At any given time, I want the Selector form to be on top of other windows and it will have 8 radio buttons (or regular buttons, doesn't matter). When one of the buttons is clicked, the current form (not the Selector form) should disappear and a new form should appear. The name of the button will be the name of the new form that appears.
I have seen a few examples and here is the code I have so far:
void Button1Click(object sender, EventArgs e)
{
//this.Hide();
var form1 = new CASII();
form1.Closed += (sender1, args) => this.Close();
form1.Show();
}
void Button2Click(object sender, EventArgs e)
{
// this.Hide();
var form2 = new CCARAdmin();
form2.Closed += (sender1, args) => this.Close();
form2.Show();
//Application.Run(new CCARAdmin());
}
Problem I am having is I don't want to hide the Selector form, which this does, and I don't know how to identify the other form that is open to close it and then open a different form.
From starting the program the logic would be like this:
Show Selector form
When a button is clicked on the Selector form, keep the Selector form on top and show the other form with the name of the button.
When a different button is clicked on the Selector form, close the previous form that was open (not the Selector form) and open the new form corresponding to the name of the button. Keep the Selector form on top.
When the Selector form is close, application stops.
Problem I am having is I don't want to hide the Selector form, which
this does, and I don't know how to identify the other form that is
open to close it and then open a different form.
Set Selector form TopMost to True to make it always on top. Or
you can use BringToFront after opening a new form
to know other forms that are open check this answer. Or you can define each From as a field in the Selector form, and check that.
selectorForm.TopMost = true ( this will help to keep the selector form always on top).
Create a form variable in your selector form to keep the reference of your currently opened form.
Sample code for 1 button click :
Form frm = null;
void Button1Click(object sender, EventArgs e)
{
//this.Hide();
var form1 = new CASII();
if (frm == null)
{
frm = form1;
}
else
{
frm.Close();
}
form1.Show();
this.TopMost = true;
frm = form1;
}
I resolved this by setting TopMost to true and then using the following code under each one of the buttons:
for (int i = Application.OpenForms.Count - 1; i >= 0; i--)
{
if (Application.OpenForms[i].Name != "FormSelector")
Application.OpenForms[i].Close();
}
var form = new TRAC();
if (radioButton9.Checked == true)
{
form.Show();
}

refreshing treeview component from other form

I currently have a class that handles my treeview and other winForm components.
I want to use another form which act as my input and once I press the save button it should update my treeview component on the other form. So far what I tried has not worked.
here is my code:
*mainDisplay is my form which includes my component and stores my variable that holds the data
Here I load my date into the treeview
public void mainDisplay_Load( TreeNode input)
{
treeView1.BeginUpdate();
foreach (data x in mydata1)
{
Console.WriteLine(x.getName());
if (x.getName() != null)
{
treeView1.Nodes.Add(input);
}
}
treeView1.Refresh();
}
here is my button action on the OTHER form:
private void button1_Click(object sender, EventArgs e)
{
if (!(String.IsNullOrEmpty(getnamebox.Text))) ;
{
mainDisplay putdata = new mainDisplay();
name = getnamebox.Text;
pass = getpassbox.Text;
url = geturlbox.Text;
notes = getnotebox.Text;
data newData = new data(name, pass, notes);
mainDisplay.mydata1.Add(newData);
TreeNode mytree = new TreeNode(name);
putdata.mainDisplay_Load(mytree);
this.Hide();
}
Any tip would be appreciated.
You just created a brand new main display form somewhere (in memory) and added a tree node to it.
You need to pass the reference of your main display forward (usually in an initialize function or trace back your second form's parentage depending on how your stuff was set up) and then use the reference to your actual main form to update the tree.

Categories

Resources