Cannot invoke changes in form a second time - c#

I try to write an app where I need to use a scanner via COM-port.
I'm using an enabled SerialPort object for it,
scanning works fine in the main form.
I then use a button to toggle if the main form should be able to do the ReadExisting() method.
private void ScannerDataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
try
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();`
if (string.IsNullOrEmpty(indata))
{
return;
}
Invoke(new MethodInvoker(delegate { cbValues.SelectedItem = values; }));
}
catch (Exception ex)
{
log.Error($"{ex}");
}
}
(cbValues is a ComboBox)
(System.IO.Ports.SerialPort)
In my mainform I use this to create a new form:
var form = new Form2(_data, scanner);
form.ShowDialog();
Then the form is shown as expected.
On the first try when I scan stuff in the new form everything works fine.
Then I close the 'child' form.
Then I reopen it and it is shown and the scanner event is fired.
This is my constructor:
InitializeComponent();
HandleCreated += new EventHandler((sender, args) =>
{
scanner.DataReceived += new SerialDataReceivedEventHandler(ScannerDataReceivedHandler);
});
In my event I try to invoke a change in a combobox.
BeginInvoke(new MethodInvoker(delegate { cbValues.SelectedItem = values; }));
On my second try the form is not created (IsCreated = false) and doesn't have a handle (IsHandleCreated = false), despite being visible AND reacting to the scanner.
I cannot wrap my head around it. I also tried using the form to have it disposed after usage, but it doesn't work.
Does anyone have a guess?

I read your post and code carefully. As I understand it, scanner is a member variable of MainForm, and you're passing it as an argument to the Form2 constructor. More than a guess, what I'm seeing is a roundabout way to subscribe to the event that should be attached in the main form one time as soon as the scanner is instantiated.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
scanner = new Scanner();
scanner.DataReceived += ScannerDataReceivedHandler;
}
// F O R E X A M P L E
// The class name `Scanner` is just a placeholder for this example.
// The point is, it's being declared/instantiated "somewhere".
private readonly Scanner scanner;
private void ScannerDataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
// Do something
}
}

I solved it.
It is ugly, but it works.
I hope there will be a future me with a nice solution.
The solution: closing the SerialPort object via scanner.Close() and opening it in the other form.
After everything is scanned closing that object on Form2_FormClosing(object sender, FormClosingEventArgs e).

Related

ShowDialog() is not preventing the originating form from being clickable

I have a winform with the following code that opens an external program when the form is opened. If the program closes, a dialog box is suppose to pop up with an option to return that a button was clicked. This will close the dialog box and return to the initial form and then run the function to open the external program again.
Here is the problem, the original form is STILL clickable AND the function is not running. Any ideas?
public Manager()
{
InitializeComponent();
ExternalProgramOpen();
}
private void ExternalProgramOpen()
{
Process startProgram = Process.Start("program.exe", Program.ConnectionArg);
startProgram.EnableRaisingEvents = true;
startProgram.Exited += this.PrematureClose;
}
private void PrematureClose(object sender, EventArgs e)
{
ManagerWarning messagepopup = new ManagerWarning();
messagepopup.ShowDialog();
using (var ManagerWarning = new ManagerWarning())
{
if (ManagerWarning.ShowDialog() == DialogResult.Retry)
{
ExternalProgramOpen();
}
}
}
The reason for this effect is probably that the Exited event is not raised in the same UI thread that started the process.
When you call ShowDialog() from another thread, the new window will not use and block the original UI thread.
To solve this, check if InvokeRequired is true and use Invoke:
private void PrematureClose(object sender, EventArgs e)
{
if (InvokeRequired)
{
Invoke(new Action(() => PrematureClose(sender, e)));
return;
}
// your code here
// ...
}

Show or Show Dialog block other forms C#

I have 2 forms. First is a simple notepad, and i make a find function. Is works very good, but i add this.Close(); to get the resultate. If i don't close the FindForm, the action of Find button not work. I see the first form is blocked and i can't write another text. if i delete this.close() and i close FindForm after i press Find is work.
How i can open the FindForm in a new thread? i use FindForm f = new FindForm(); and f.showDialog();
If i make a Thread Th; and i use this thread to open the FindForm, my function will not work anymore. Is any method to open other form without block first form?
FindForm
public FindDialog()
{
InitializeComponent();
}
private void button_Find_Click_1(object sender, EventArgs e)
{
Form1.FindText = textBox_Text.Text;
this.Close();
}
MainForm
public void findNewToolStripMenuItem_Click(object sender, EventArgs e)
{
FindDialog gtl = new FindDialog();
gtl.Show();
richTextBox1.Select();
if (FindText != null)
{
k = richTextBox1.Find(FindText);
}
}
Calling ShowDialog will block the caller until the dialog is closed (i.e. it is modal) - if you don't want this behaviour then call Show which will open the child form modelessly (i.e. the calling code can continue)
For example, you could do something like:
public void findNewToolStripMenuItem_Click(object sender, EventArgs e)
{
FindDialog gtl = new FindDialog();
gtl.Show(); // Execution will continue immediately
richTextBox1.Select();
if (FindText != null)
{
k = richTextBox1.Find(FindText);
}
}

Mono Gtk.Dialog returning object as response

I am trying to write a simple form application with mono Gtk# but am already stuck in the beginning I create a Dialog form inherits from Gtk.Dialog. The dialog form for collection basic information and returning these information as an object to main window or trigger some event to main window so it can do what it suppose to do in this case bind the data a TreeView control (which is another story). These are what I have tried so far;
Dialog code
public partial class MyDialog : Gtk.Dialog
{
public MyDialog ()
{
this.Build ();
}
protected void OnButtonOkClicked (object sender, EventArgs e)
{
int portNumber = 0;
iint.TryParse (spnPort.Text, out portNumber);
var myObj = new MyObj ();
myObj.Username = txtUsername.Text;
myObj.Password = txtPassport.Text;
// did not work as ParentWindow is a Gdk.Window
//(this.ParentWindow as MainWindow).AddObj(myObj);
//Also did not work because there is no response related method
//or property in the Dialog please read below code block this will make more sense
//this.OnResponse(myObj);
}
}
MainWindow Code to call dialo
protected void OnAddActionActivated (object sender, EventArgs e)
{
MyDialog s = new MyDialog();
s.Run();
s.Response += HandleResponse;
}
void HandleResponse (object o, ResponseArgs args)
{
//as this event has args.Args and args.RetVal I thought one would do what I wanted
//maybe I am using them all wrong
}
I appreciate it if some one can explain what is Gdk.Window is and what it is doing under Gtk control.
Just store the object you want to return in your dialog object, and provide access to it using a property. Don't forget to check whether the user pressed the cancel button (if you have one), conveniently by examining the return value of Run().
For an example see the sample code for the stock FileChooserDialog in the official documentation.

How to close form

Ok, so a Windows Forms class, WindowSettings, and the form has a "Cancel"-button. When the user clicks the button, the dialog DialogSettingsCancel will pop-up up and ask the user if he is sure he wants to perform the action. The dialog has 2 buttons, a "Yes"-button and a "No"-button. If the user clicks the "Yes"-button, I want both DialogSettingsCancel and WindowSettings to be closed.
My button_Click event handler in DialogSettingsCancel:
private void button1_Click(object sender, EventArgs e)
{
//Code to trigger when the "Yes"-button is pressed.
WindowSettings settings = new WindowSettings();
this.Close();
settings.Close();
}
When I run my application, and go to the settings form, and click the "Cancel"-button, and then click the "Yes"-button, only DialogSettingsCancel closes without closing WindowSettings.
Why won't it work?
I've also tried changing
this.Close();
settings.Close();
to
settings.Close();
this.Close();
But still the same result.
You need the actual instance of the WindowSettings that's open, not a new one.
Currently, you are creating a new instance of WindowSettings and calling Close on that. That doesn't do anything because that new instance never has been shown.
Instead, when showing DialogSettingsCancel set the current instance of WindowSettings as the parent.
Something like this:
In WindowSettings:
private void showDialogSettings_Click(object sender, EventArgs e)
{
var dialogSettingsCancel = new DialogSettingsCancel();
dialogSettingsCancel.OwningWindowSettings = this;
dialogSettingsCancel.Show();
}
In DialogSettingsCancel:
public WindowSettings OwningWindowSettings { get; set; }
private void button1_Click(object sender, EventArgs e)
{
this.Close();
if(OwningWindowSettings != null)
OwningWindowSettings.Close();
}
This approach takes into account, that a DialogSettingsCancel could potentially be opened without a WindowsSettings as parent.
If the two are always connected, you should instead use a constructor parameter:
In WindowSettings:
private void showDialogSettings_Click(object sender, EventArgs e)
{
var dialogSettingsCancel = new DialogSettingsCancel(this);
dialogSettingsCancel.Show();
}
In DialogSettingsCancel:
WindowSettings _owningWindowSettings;
public DialogSettingsCancel(WindowSettings owningWindowSettings)
{
if(owningWindowSettings == null)
throw new ArgumentNullException("owningWindowSettings");
_owningWindowSettings = owningWindowSettings;
}
private void button1_Click(object sender, EventArgs e)
{
this.Close();
_owningWindowSettings.Close();
}
You can also close the application:
Application.Exit();
It will end the processes.
new WindowSettings();
You just closed a brand new instance of the form that wasn't visible in the first place.
You need to close the original instance of the form by accepting it as a constructor parameter and storing it in a field.
Why not use the DialogResult method to close the form?
if(DialogSettingsCancel.ShowDialog() == DialogResult.Yes)
{
//this will close the form but will keep application open if your
//application type is "console" in the properties of the project
this.Close();
}
For this to work however you will need to do it inside your "WindowSettings" form while you call the DialogSettingsCancel form. Much the same way you would call the OpenFileDialog, or any other Dialog form.
Your closing your instance of the settings window right after you create it. You need to display the settings window first then wait for a dialog result. If it comes back as canceled then close the window. For Example:
private void button1_Click(object sender, EventArgs e)
{
Settings newSettingsWindow = new Settings();
if (newSettingsWindow.ShowDialog() == DialogResult.Cancel)
{
newSettingsWindow.Close();
}
}
send the WindowSettings as the parameter of the constructor of the DialogSettingsCancel and then on the button1_Click when yes is pressed call the close method of both of them.
public class DialogSettingsCancel
{
WindowSettings parent;
public DialogSettingsCancel(WindowSettings settings)
{
this.parent = settings;
}
private void button1_Click(object sender, EventArgs e)
{
//Code to trigger when the "Yes"-button is pressed.
this.parent.Close();
this.Close();
}
}
for example, if you want to close a windows form when an action is performed there are two methods to do it
1.To close it directly
Form1 f=new Form1();
f.close(); //u can use below comment also
//this.close();
2.We can also hide form without closing it
private void button1_Click(object sender, EventArgs e)
{
Form1 f1 = new Form1();
Form2 f2 = new Form2();
int flag = 0;
string u, p;
u = textBox1.Text;
p = textBox2.Text;
if(u=="username" && p=="pasword")
{
flag = 1;
}
else
{
MessageBox.Show("enter correct details");
}
if(flag==1)
{
f2.Show();
this.Hide();
}
}
There are different methods to open or close winform.
Form.Close() is one method in closing a winform.
When 'Form.Close()' execute , all resources created in that form are destroyed.
Resources means control and all its child controls (labels , buttons) , forms etc.
Some other methods to close winform
Form.Hide()
Application.Exit()
Some methods to Open/Start a form
Form.Show()
Form.ShowDialog()
Form.TopMost()
All of them act differently , Explore them !

Windows.Form topmost called from a workerthread doesnt work when ClickOnce is enabled and published

I have a main thread that is a form, that starts another application, in this case Notepad, then I spawn off a BackgroundWorker that waits for Notepad to be closed. When its closed, the BackgroundWorker shows another Form to display, topmost, to the user. This Form needs to be non-modal, so that the user can click on some buttons on the main thread dialog. The problem is this form (Form2, from the BackgroundWorker) is NOT TopMost, even though I set it to true. It works when I hit F5, but when I publish, as a ClickOnce application, to my server, form2 is no longer TopMost. I have tired Form2.Topmost = true, BringToFront, Activate, "MakeTopMost" from What is powerful way to force a form to bring front? .... nothing seems to work.
I even tried to get the handle of the main form, and use that as the parent of form2, but I'm getting "InvalidOperationException: Cross-thread operation not valid: Control 'Form2' accessed from a thread other than the thread it was created on."
Here is a code snippet:
public partial class Form1 : Form
{
System.Diagnostics.Process p = new System.Diagnostics.Process();
private BackgroundWorker endApplicationBackgroundWorker= new BackgroundWorker();
public Form1(string[] args)
{
endApplicationBackgroundWorker.DoWork += new DoWorkEventHandler(endApplicationBackgroundWorker_DoWork);
p.StartInfo.FileName = "notepad";
p.Start();
endApplicationBackgroundWorker.RunWorkerAsync();
//Quit here so we can accept user inputs (button pushes ..)
}
private void endApplicationBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
p.WaitForExit();
Form2 form2 = new Form2();
form2.TopMost = true;
System.Diagnostics.Process[] procs = System.Diagnostics.Process.GetProcessesByName(form1ProcessName);
if (procs.Length != 0)
{
IntPtr hwnd = procs[0].MainWindowHandle;
if (form2.ShowDialog(new WindowWrapper(hwnd)) == DialogResult.OK)
{
// process stuff
}
}
this.Close();
}
}
Any other ideas? Or can someone fix my code above? I have been dealing with this issue for weeks now and getting flustered.
Thanks!
Any work you do in a BackgroundWorker's DoWork method after calling the RunWorkerAsync procedure is NOT running on the UI thread, but your code is creating a form in the background.
Forms are UI elements, so this won't work:
private void endApplicationBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
Form2 form2 = new Form2();
form2.TopMost = true;
// etc..
if (form2.ShowDialog(new WindowWrapper(hwnd)) == DialogResult.OK)
{
// process stuff
}
}
From the comments, you should subscribe to the RunWorkerCompleted event to show your second form. Also, you can't call the Close method either since you are trying to keep Form2 alive without a ShowDialog call, so try subscribing to the Form_Closing() event of the second form to notify when the main form should be closed, too:
public Form1(string[] args)
{
endApplicationBackgroundWorker.DoWork +=
new DoWorkEventHandler(endApplicationBackgroundWorker_DoWork);
endApplicationBackgroundWorker.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(endApplicationBackgroundWorker_RunWorkerCompleted);
p.StartInfo.FileName = "notepad";
endApplicationBackgroundWorker.RunWorkerAsync();
}
private void endApplicationBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
p.Start();
p.WaitForExit();
}
private void endApplicationBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Form2 form2 = new Form2();
form2.TopMost = true;
form2.FormClosing += new FormClosingEventHandler(form2_FormClosing);
form2.Show(this);
}
private void form2_FormClosing(object sender, FormClosingEventArgs e)
{
this.BeginInvoke(new MethodInvoker(delegate { this.Close(); }));
}
Another workaround can be, if you set the topmost to false and then set it back to true. It is strange, but it works. So the code could be the following for a form to be show with descending oppacity in a simple background thread:
for (int i = 0; i < 50; i++)
{
ppaForm.SetBitmap(bitmap, (byte)(255 - i * 5));
ppaForm.Show();
ppaForm.TopMost = false;
ppaForm.TopMost = true;
Thread.Sleep(6);
}
In this case ppaForm is a PerPixelAlphaForm, for which you can find a description here.

Categories