How to close a notification in Avalonia UI? - c#

Having used Avalonia.Controls.Notifications i'm using Show(INotification) method to show notification.
I can set a timer for notification to close it after timeout and can set an event handler for it to handle onClick.
How can I close notification from my code by calling a method or any other way?
I tried to emulate click event but hadn't success

You have to get the instance of of NotificationCard that was created and call Close() method
// NotificationManager is the instance of WindowNotificationManager used to show the notification
var cards = NotificationManager.GetVisualChildren().FirstOrDefault() is ReversibleStackPanel panel ?
panel.Children.OfType<NotificationCard>() : Array.Empty<NotificationCard>();
// Close the first notification if exists
cards.FirstOrDefault()?.Close();

Related

C# where does execution come after the handling the event?

Consider i have a "Form" and it contains Button. I started the compiling process (Ctrl +F5). When i click the button the event is occurs and event handler is executed. Where does execution come back after event is handled?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//some Code
}
}
Short Answer: It goes back to listening for more events.
Detailed Answer:
Under the hood, everything in Windows runs on top of the Win32 API. The Win32 API has at least 2 functions that all programs run. The window procedure is one and that is where our event messages get processed. The other one is called the message loop and it looks similar to this:
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
The message loop is the heart of all event-based Windows programs. GetMessage() gets a message from your application's message queue. Any time the user moves the mouse, types on the keyboard, clicks on your window's menu, or does any number of other things, messages are generated by the system and entered into your program's message queue. By calling GetMessage() you are requesting the next available message to be removed from the queue and returned to you for processing.
TranslateMessage() does some additional processing on keyboard events. Finally DispatchMessage() sends the message out to the window that the message was sent to.
In every winforms application is "hidden" main message loop.
Main message loop is basicaly while(true) ... loop and checks for input (and some other) events like Click, KeyDown, etc...
This main loop is executed inside Application.Run(...) is call. Probably in your Program.cs file.
Check the Events overview for Windows Forms
When an event is recorded by the application, the control raises the event by invoking the delegate for that event. The delegate in turn calls the bound method. In the most common case (a multicast delegate) the delegate calls each bound method in the invocation list in turn, which provides a one-to-many notification. This strategy means that the control does not need to maintain a list of target objects for event notification—the delegate handles all registration and notification.
So the control itself, calls the delegate. The code of the control raised the method. So when you click the control there is some code in the control that calls the delegate you have provided.
The code commonly calls the delegate as it would any other function and continuous it's code flow:
i.e.
// do something
deletat(...);
// continue doing something
You can find an even better example here: Understanding events and event handlers in C#
on how delegates are being called.

Wait for variable to change

I have a method that shows a window and then returns the value of the button clicked. What I have done is that when I click the button I change a variable and then the variable will be returned. What I need is someway to pause the method until the variable has been changed.
I program a game in unity and it's using mono.
Code:
public virtual Buttons Execute(){
this.holder.SetActive(true); //Set the window active
// Here wait for the user to click a button
return clicked;//Returns the button clicked.
}
The code that handles the user interface is event driven, so the sensible thing to do would be to use an event instead of using a method like you try to do.
It's possible to create a method that works that way, but you have to create your own message pump that runs while you are waiting:
public virtual Buttons Execute(){
this.holder.SetActive(true); // Set the window active
clicked = null; // Set the state as undetermined
while (clicked == null) { // Wait until it is set
Application.DoEvents(); // Process messages
Thread.Sleep(10); // Wait for a while
}
return clicked; // Returns the button clicked.
}
You can read in the question Use of Application.DoEvents() for explanations of the pitfalls of using DoEvents this way.

How to display message box without any buttons in C#

I try to show a MESSAGE to the user while an operation is executed. The MESSAGE won't show any button. Just a MESSAGE (text) and maybe a background image.
The problem is the following:
MessageBox does not seem to be the good control (because of button and it blocks the running process).
Form.ShowDialog() also blocks the running process. I don't know what to do.
I want to show the message, run my process, and dispose the message when the process is done.
How to achieve this in C# ?
Create a simple form with the message (or expose a public property to be able to change the message, or a constructor with message parameter to pass it in) and show the form using this Show overload. Then disable the (entire) original (owner) form (or just disable the controls you don't want accesible).
So, in your "main" form do this:
Form f = new MessageForm();
f.Show(this); //Make sure we're the owner
this.Enabled = false; //Disable ourselves
//Do processing here
this.Enabled = true; //We're done, enable ourselves
f.Close(); //Dispose message form
Also, consider using a BackgroundWorker.
create custom form, and write own behavior
Create a custom form set it to minimal styles etc. Make sure it knows when the process is complete, say by passing in a reference to the process and checking it every now and then.
One way you could do it is create a worker class that raises an event when it is finished.
execute the worker class in a new thead so it runs it the backgroud.
create the modal form with a method to close it as the event handler for the "finished" event.
This way the ui still works and responds and the form will close once the worker thread is finished.

Serial Port - I cannot call form and make ShowDialog in the method of port_received?

I am listening the port and Once I receive the message doing some of processing than inserting into the database. All good so far.
The issue is that into the method of port_received I'd like to popup the form of showing that the device received message and depends user click the OK and seeing the message. And at the background of the popup form there is a timer and closing the form in 2 sec unless user doesnt click the button of see the message.
I am calling the form than .ShowDialog() after that I am loosing my serial port communication.
If I use .Show() I cannot see the properly
some of code:
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
data = comport.ReadLine();
ReceiveMessagePopup popUp = new ReceiveMessagePopup(data);
popUp.Location = new Point(150, 150);
popUp.ShowDialog();
/// after that code I cannot do anything even cannot show any MessageBox.
}
I would not put a ShowDialog or any other UI management in that method as it can be raised many times as soon as data is received.
I think that event handler should just receive and store the data somewhere and the ShowDialog or other notification or UI handling should be done out of that method.
see here for examples on how to use with that event handler and save the incoming data:
How do I use dataReceived event of the SerialPort Port Object in C#?
From the MSDN article on SerialPort.DataReceived
"The DataReceived event is raised on a secondary thread when data is received from the SerialPort object. Because this event is raised on a secondary thread, and not the main thread, attempting to modify some elements in the main thread, such as UI elements, could raise a threading exception. If it is necessary to modify elements in the main Form or Control, post change requests back using Invoke, which will do the work on the proper thread."
Use Control.BeginInvoke to execute code on the main UI thread to show the dialog. e.g.
assuming this code is in a class that inherits from Form
var data = comport.ReadLine();
_buffer.Append(data);
if (_buffer.IsValid)
{
BeginInvoke((Action) (() =>
{
ReceiveMessagePopup popUp = new ReceiveMessagePopup(buffer);
popUp.Location = new Point(150, 150);
popUp.ShowDialog();
}));
}
You don't want to do long running tasks in the event, and as Davide points out, showing the dialog every time the event is raised is probably not a good idea, as you may get many events raised, even for a single line of data from the serial port, so that's why I would add the data read from the port to a buffer, and if the buffer is valid (e.g. contains a whole line/message/packet/whatever) then show the dialog

How do I force and event to resolve from within another event

I have a Winforms App (.NET 3.X) That runs a method in a class to process some data. The method periodically raises a StatusUpdate event with a count of the number of items processed. I have a ToolStripStatuslabel on the Form that i would like to update with the count. The problem is that status label never updates with this count until the process is complete. Below is the code from the status update event handler
toolStripStatusLabel.Text = e.Count.ToString();
statusStrip.Refresh();
I think the problem is that the Refresh event is not firing because the processing method is being called from within a Button press event. I think there is a way to force the Refresh to process but I do not remember what it is.
My only other solution is to execute the processing in it's own thread.
Found the answer in another thread:
Call Application.DoEvents() after setting the label, but you should do all the work in a separate thread instead, so the user may close the window.
This is the command that I was thinking of...
Have you tried calling refresh on the label itself ?
toolStripStatusLabel.Refresh();

Categories