How to connect 3 forms into one - c#

I am with a problem where I have 3 forms and a class called Languages. The 3 Forms are the Main Form, The Settings Form and Languages Form. So what I need help with is, when I click in the language flag, I am trying to access to Main Form to pick up there a function I created there called 'changedLanguages()' I can access it, but when I click the flag, the Main Form is not Updating the changes without close the actual opened Main Form. But if i write a line of code mus.Show(); it opens a new one with the changes.
But I want to do the changes in the actual opened Main Form. Is it possible?
Below you have the LanguagesForm from the flag image click:
private void ptLang_img_Click(object sender, EventArgs e)
{
enLang_img.BackColor = Color.Transparent;
ptLang_img.BackColor = Color.CadetBlue;
Form1 mus = new Form1();
Languages PT_lang = new Languages();
mus.changeLanguage(PT_lang.file_PT, PT_lang.open_PT, PT_lang.settings_PT, PT_lang.exit_PT, PT_lang.controls_PT, PT_lang.play_PT, PT_lang.pause_PT, PT_lang.stop_PT, PT_lang.next_PT, PT_lang.prev_PT, PT_lang.playRecently_PT, PT_lang.volUp_PT, PT_lang.volDown_PT, PT_lang.help_PT, PT_lang.about_PT, PT_lang.faq_PT, PT_lang.update_PT);
mus.Refresh();
}
And here you have the function of 'changedLanguages()':
public void changeLanguage(string file, string open, string settings, string exit, string controls, string play, string pause, string stop, string next, string prev, string recPlayed, string volUp, string volDown, string help, string about, string faq, string update)
{
fileToolStripMenuItem.Text = file;
openToolStripMenuItem.Text = open;
settingsToolStripMenuItem.Text = settings;
exitToolStripMenuItem.Text = exit;
controlsToolStripMenuItem.Text = controls;
playToolStripMenuItem.Text = play;
pauseToolStripMenuItem.Text = pause;
stopToolStripMenuItem.Text = stop;
forwardToolStripMenuItem.Text = next;
backwardToolStripMenuItem.Text = prev;
playRecentToolStripMenuItem.Text = recPlayed;
volumeUpToolStripMenuItem.Text = volUp;
volumeDownToolStripMenuItem.Text = volDown;
helpToolStripMenuItem.Text = help;
aboutUMusicToolStripMenuItem.Text = about;
fAQToolStripMenuItem.Text = faq;
updatesToolStripMenuItem.Text = update;
}
Any help is welcome...

create a static instance of your main form, I hope that the changes will be immediately visible, if it does not work, add this statement after making your changes
Application.DoEvents();

Related

C# Get variable from popup form that will be closed

I have a form populated with an array of userControls that is created from the main form. I need to be able to access this array of userControls from the main form once the popup has been closed when a button is pressed. If I fill out the forms and then press the button on the main form without closing the popup, the values are present. However, if I close the popup window, the values are not present. My main form is static so I can use it's variables in other forms.
Code for the popup:
public ScanChannel[] controls;
public ScanListSetup()
{
InitializeComponent();
int numChans = Convert.ToInt32(Form1.Self.numChannels.Text);
controls = new ScanChannel[numChans];
// Create the UserControls
for(int i = 0; i < numChans; i++)
{
controls[i] = new ScanChannel();
}
// Place them
for (int i = 0; i < numChans; i++)
{
controls[i].Location = new Point(13,(35+25*(i)));
this.Controls.Add(controls[i]);
}
doneButton.Location = new Point(82, 35 + (25 * (numChans + 1)));
this.Size =new Size(280, 110 + (25 * (numChans + 1)));
}
private void doneButton_Click(object sender, EventArgs e)
{
Form1.Self.setChannelsToScan(controls);
}
I need to access the controls array in the main form. The code for the main form is as follows:
private ScanChannel[] channelsToScan;
private void configureScanListButton_Click(object sender, EventArgs e)
{
var form = new ScanListSetup();
form.Show(this);
scanListConfigured = true;
this.channelsToScan = new ScanChannel[Convert.ToInt32(numChannels.Text)];
}
public void setChannelsToScan(ScanChannel[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
this.channelsToScan[i] = arr[i];
}
}
private void scanButton_Click(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Test: " + this.channelsToScan[0].getDeviceType());
// THIS PRINTS AN EMPTY STRING
}
So, the Debug writeLine outputs the correct value if I click the scanButton while the popup form is still open. However, if I close the form after clicking the doneButton on the popup form, the Debug writeLine outputs Test: with nothing else.
Any help with this would be greatly appreciated. Thanks.
Your problem essentially boils down to sending data from a secondary window (your 'pop-up' window) to the main window from where it was created. It doesn't matter whether you're working with Windows Control objects or simple data types like string, so I'm going to use a simple example to illustrate how to handle such a situation.
Let's assume you have a Main form that looks like this. It has an OPEN button and a TextBox.
When you click OPEN, it opens up this secondary input window (your pop-up) which looks like this:
Now the idea is this. You click OPEN and opens the Input form, and lets the user enter some text into the TextBox there. Once you click the OK button, it should close the Input window, and display the text entered by the user in the Main window. Remember that at this point the Input window is closed, which is equivalent to your situation.
So I'd make use of Delegates to accomplish this goal. A delegate lets you transfer data between windows which is what you want.
In my Main I'd declare a public delegate with a signature like this:
public delegate void DataTransfer(string data);
That is, this delegate represents a method that takes in a single string parameter, and has void return type. The idea is to let the secondary Input window 'call' a method in the Main, and that method takes in a string parameter. So, if there was a way for us to call a method that resides in the Main from Input, and pass a string, we can then take the user input text in the Input window, and pass it to the Main window. With me so far?
Now, if I write a method like this in the Main, and let it be called from Input, that should accomplish our goal. Here, txtDisplay is the TextBox in the Main form.
public void ReceiveInput(string data)
{
txtDisplay.Text = data;
}
To accomplish this, I would define a delegate of type DataTransfer in the Main form like below, and register the ReceiveInput() method to it. Your Main form code behind should look like this:
public delegate void DataTransfer(string data);
public partial class MainForm : Form
{
public DataTransfer transferDelegate;
InputForm inputForm = null;
public MainForm()
{
InitializeComponent();
transferDelegate += new DataTransfer(ReceiveInput);
}
public void ReceiveInput(string data)
{
txtDisplay.Text = data;
}
private void BtnOpen_Click(object sender, EventArgs e)
{
inputForm = new InputForm(transferDelegate);
inputForm.Show();
}
}
BtnOpen is the OPEN button in the Main form, and when it's clicked, it passes the delegate to the Input form, then opens it. So, accordingly, we need to now modify our Input form:
public partial class InputForm : Form
{
DataTransfer transferDel;
public InputForm(DataTransfer del)
{
InitializeComponent();
transferDel = del;
}
private void BtnOK_Click(object sender, EventArgs e)
{
string data = txtInput.Text;
transferDel.Invoke(data);
Close();
}
}
Here, we modify the constructor so that it takes in a delegate of type DataTransfer, and sets it to the local instance of the same type. Then, at the click of BtnOK on the Input form, we take in the text input by user, and pass that text to the said delegate and invoke it. 'Invoking' is the same as calling the method in the Main form. At this point, you can Clsoe() the Input window as shown above, and you'd still have access to the user input string data from your Main form.
You can use this same approach, and instead of strings you can pass around Controls. However, it's not the best approach to pass around a bunch of controls back and forth, so ideally you would extract the data you need from those controls in your pop-up, and pass only the said data instead of the whole controls.
EDIT: After OP posted the erroneous code.
OK, so here's your issue. The testUserControl class is not a regular class but a control element derived from UserControl. In otherwise, a GUI element. You shouldn't use GUI elements to pass data around. Because, when you do your controlArr[i].getText();, it tries to get the text from the textItem, but textItem is a TextBox Control which doesn't exist at this point because you closed your window. Remember, you do the delegate.Invoke() only once, and at that point *you must send ALL the data back to your main window*.
What you should do is, simply define a class to hold ALL the data you want to pass to your main. For example something like this:
public class DataToPass
{
public string TextBoxText { get; set; }
public string SomeOtherData { get; set; }
// Other stuff you want...
}
Now, instead of passing an array of testUserControl, pass an array of DataToPass. That way, at the Main form you don't have to do the following:
controlArr[i].getText();
Instead you'd simply do something like:
controlArr[i].TextBoxText;
where controlArr now is an array of type DataToPass.
Simply, passing a control derived from UserControl is not a good idea. Just create one class that is capable of holding ALL the data you want to pass and pass it back to the main once.

How to create a simple one time activation process using c#?

I want to create a simple one time activation process for my windows form application. So, I basically have two forms, form1 is the activation window and form2 is the actual program. I've create a very basic activation program in form1 given below
string mac = textBox1.Text;
string str1 = mac.Substring(4,1);
string str2 = mac.Substring(5,1);
string str3 = mac.Substring(7,1);
string str4 = mac.Substring(2, 1);
string pattern = str1 + str2 + str2 + str3 + str4;
if (textBox2.Text == pattern)
{
MessageBox.Show("Program activated!!!");
Form2 n = new Form2();
n.Show();
this.Hide();
}
else { MessageBox.Show("Wrong key"); }
Now, the problem is every time I load my program it always loads form1 even when someone successfully entered the key(i.e. pattern) once before. How do I store that information so that if someone enters the correct key, every time after that whenever the program is loaded it will automatically show form2 (i.e. my actual program) and skip form1.
BTW, I'm aware that there are other more advanced and secure ways of doing this but I'm just currently interested in this very basic method.
Can anyone help?
Here's one very rudimentary way - write a file to a known location when they activate, then check for the existence of that file each time you load the form. If it's there, immediately show Form2. If not, give them the chance to activate.
Differing methods would be to save the activation status in the Registry or in a Database, or somewhere else, but the overall process is about the same
Sample code:
First, a method to get the path to the file we're going to create:
private string GetActivatedFilePath()
{
var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var thisExeName = Path.GetFileNameWithoutExtension(
System.Reflection.Assembly.GetEntryAssembly().Location);
return Path.Combine(appDataPath, thisExeName, "Activated.txt");
}
Then a couple of methods to create the file (Activate()), check if the file exists (IsActivated), and delete the file (Deactivate()):
private void Activate()
{
if (!IsActivated())
{
var filePath = GetActivatedFilePath();
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
File.Create(filePath);
}
}
private bool IsActivated()
{
return File.Exists(this.GetActivatedFilePath());
}
private void Deactivate()
{
if (IsActivated())
{
File.Delete(GetActivatedFilePath());
}
}
Then we can also create a method to show the second form, since we will be calling this in more than one place. I've modified this to first hide the current form, then show the second form as a dialog (which means they can't switch back to the main form and code will pause in the first form until the second one closes), and then close the first form when the second one closes:
private void ShowForm2()
{
Form2 n = new Form2();
this.Hide();
n.ShowDialog();
this.Close();
}
Now we can check if they're activated in our Form_Load event, and if they are then immediately show the second form:
private void Form1_Load(object sender, EventArgs e)
{
// If they user is already activated, show the second form immediately
if (IsActivated())
{
ShowForm2();
}
}
And then your current code can also make use of these functions to activate the user. I'm assuming the code lives behind an Activate button:
private void btnActivate_Click(object sender, EventArgs e)
{
bool activated = false;
if (textBox1.Text.Length > 7)
{
string mac = textBox1.Text;
string str1 = mac.Substring(4, 1);
string str2 = mac.Substring(5, 1);
string str3 = mac.Substring(7, 1);
string str4 = mac.Substring(2, 1);
string pattern = str1 + str2 + str2 + str3 + str4;
activated = textBox2.Text == pattern;
}
if (activated)
{
MessageBox.Show("Program activated!!!");
Activate();
ShowForm2();
}
else
{
MessageBox.Show("Wrong key");
}
}

C# .NET Window won't show in front after double clicking on listview row

I have this one problem that I can't get over. I think it will be something really simple but I just was not able to find out.. I am trying to open new window here for editing contact when user double click on one row in listview. Window normally opens but the problem is it won't open in front of current main window but behind it so it is not visible and can easily confuse user. I have tried few methods like BringIntoView() or playing with focus but nothing helped.
Please help me with this. Thanks!
Code:
void ListViewItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
editContact();
}
private void editContact()
{
Window1 win = new Window1("edit");
DatabaseHandler handler = new DatabaseHandler();
win.Show();
List<Contact> listie = handler.GetContactList();
var selected = listview_contacts.SelectedItem as Contact;
win.textbox_id.Text = selected.cId.ToString();
win.textbox_name.Text = selected.Name.ToString();
win.textbox_address.Text = selected.Address.ToString();
win.textbox_email.Text = selected.Email.ToString();
win.textbox_name.Focus();
win.textbox_name.SelectionStart = win.textbox_name.Text.Length;
}
private void editContact()
{
using(Window1 win = new Window1("edit"))
{
DatabaseHandler handler = new DatabaseHandler();
List<Contact> listie = handler.GetContactList();
var selected = listview_contacts.SelectedItem as Contact;
win.textbox_id.Text = selected.cId.ToString();
win.textbox_name.Text = selected.Name.ToString();
win.textbox_address.Text = selected.Address.ToString();
win.textbox_email.Text = selected.Email.ToString();
win.textbox_name.Focus();
win.textbox_name.SelectionStart = win.textbox_name.Text.Length;
win.ShowDialog();
// do something with whatever win1 did.
// if its say OK Cancrl form
// if (win.ShowDialog() == DialogResult.OK) { // do something }
}
}
Will probably fix your issue. However without seeing the rest of your code, or knowing your intent, I can't tell you exactly how badly you've gone wrong.
For example at least all the code setting up win.textbox, should be in win...
Try
win.ShowDialog();
Which should open the new windows as a modal window.
You could try
win.Show(this);
This will enable the user to interact with the main form when your editing dialog opens.
Or you can try
win.ShowDialog();
This will block the main form when your editing dialog opens.

Reload UI language strings after changing settings

I have a problem with changing my UI strings after the user has changed the language in the option window. To change the UI strings of the main form, I have to restart the program every time, so that changes take effect, but that's annoying. So I tried it with a delegate to call the function, which loads the strings for the main window in the option window after saving the new settings. The function is called in the option window, but it doesn't change the strings of the main window.
Code in the main window
public delegate void CallLoadUIStrings(SupportedLanguages lang);
public CallLoadUIStrings callLoadUIStrings;
public Renamer()
{
callLoadUIStrings = new CallLoadUIStrings(LoadUIStrings);
}
public void LoadUIStrings(SupportedLanguages lang)
{
try
{
switch (lang)
{
#region "DE/JA/FR/ES/NL"
case SupportedLanguages.De:
case SupportedLanguages.Ja:
case SupportedLanguages.Fr:
case SupportedLanguages.Es:
case SupportedLanguages.Nl:
// reads the language file where the ui strings are stored
langHelper.Read(RenamerLangOpener.RenamerMainWindow);
this.mnuFile.Text = langHelper.Files;
this.mnuClose.Text = langHelper.Close;
this.mnuEdit.Text = langHelper.Edit;
this.mnuUndo.Text = langHelper.Undo;
this.mnuCut.Text = langHelper.Cut;
this.mnuCopy.Text = langHelper.Copy;
this.mnuPaste.Text = langHelper.Paste;
this.mnuDelete.Text = langHelper.Delete;
this.mnuSelectAll.Text = langHelper.SelectAll;
#endregion
}
}
catch (Exception ex) { //exception handling }
}
private void mnuOpt_Click(object sender, EventArgs e)
{
Preferences opt = new Preferences(this);
opt.ShowDialog();
}
Code in the option window
internal Renamer instance = null;
public Preferences(Renamer form)
{
instance = form;
}
public void UpdateUI()
{
langHelper.ReadSettingsValues();
instance.BeginInvoke(instance.callLoadUIStrings,new object[] { langHelper.GetLang});
}
Since I've never worked with delegates I don't have a clue where the mistake is.
I've googled so much to find a solution for a similar problem, but I haven't found something that matched my problem.
I assume this is winforms and not WPF question, and that you have one main form that is open from app's Main function. My solution to changing a language is to open this one form in a loop, and continue the loop as long as the form has a property set to some language identifier. If this property is set then I change the language to that value, and go for another loop iteration. I copy all other properties that need be copied form one form to another, with main being the form's position.
If the form is closed without the language ID being set then we break the loop and exit application as usual.

Why does the same function do 2 different things?

I'm an Amateur at C# and I don't understand what's going on here. It's not really a problem, as I can make a quickfix for it, but I still want to know Why.
Disclaimer: I know this is probably not the best way to design this program, but I have been given a very short amount of time to develop it and I'm just trying to ship it by the deadline.
I have a main form in my program. This form calls a second form when 1 of 2 buttons are pressed. These buttons use the same function to open the second form:
private void setupShow(int show)
{
fSetup setup = new fSetup(show);
setup.Show();
setup.FormClosed += new FormClosedEventHandler(setup_FormClosed);
}
When button1 calls that function, it hides the main form and opens the next form. However, when the second button calls that function it keeps the main form open, but still opens the second form.
So what could be causing this?
Button1 has quite a bit more code than button2 and if the functions are needed, I can post them here but it would fill up the majority of the screen.
Edit:
int show;
Is just a variable I use for functions performed in the second form. It has no bearing on anything as far as windows closing.
Button 1: Only calls this function. The function inserts into a database, then gets the inserted ID of that row and passes it to the second form
private void CheckFields()
{
OleDbCommand insertParty;
OleDbDataAdapter partyAdapt = new OleDbDataAdapter();
int nameL = PName.Text.Length;
int newPartyID = 0;
if (nameL > 0)
{
String test = "INSERT INTO Parties (PartyName, BackgroundImg) VALUES (?, ?)";
insertParty = new OleDbCommand(test, Parties);
insertParty.Parameters.AddWithValue("PartyName", PName.Text);
insertParty.Parameters.AddWithValue("BackgroundImg", tBrowse.Text);
Parties.Open();
insertParty.ExecuteNonQuery();
NewPartyForm.ActiveForm.Visible = false;
OleDbCommand selectnewParty;
OleDbDataAdapter newpartyAdaptr = new OleDbDataAdapter();
String selectNew = "SELECT TOP 1 PartyID, PartyName FROM Parties ORDER BY PartyID DESC";
selectnewParty = new OleDbCommand(selectNew, Parties);
OleDbDataReader newReader = selectnewParty.ExecuteReader();
while (newReader.Read())
{
newPartyID = newReader.GetInt32(0);
}
setupShow(newPartyID);
}
else
MessageBox.Show("Please Create a Party Name");
}
Button 2: Cuts out the integer from the string in a combobox and passes it to the second form
private void bLoad_Click(object sender, EventArgs e)
{
Object selectedParty = cLoadP.SelectedItem;
String sP = selectedParty.ToString();
String d1 = " - ";
char[] delim = d1.ToCharArray();
String[] numS = sP.Split(delim);
setupShow(Convert.ToInt32(numS[0]));
}
Like I said, this code is being developed by an amateur and very quickly. This is not the way I would normally do things, but I don't have much time to really think. lol
Second form initial function:
public fSetup(int partyID)
{
InitializeComponent();
pID = partyID;
lpID.Text += " " + pID.ToString();
}
I suspect that the cause of the different behavior is this line in the code for button 1:
NewPartyForm.ActiveForm.Visible = false;
There's no similar line in the code for button 2.

Categories