current I have an event in my App.xaml.cs
public partial class App : Application
{
public static event EventHandler SettingsSaved;
private async void Application_Launching(object sender, LaunchingEventArgs e)
{
if (SettingsSaved != null)
{
SettingsSaved(this, null);
}
}
and in my MainPage.xaml.cs
public MainPage()
{
InitializeComponent();
App.SettingsSaved += App_SettingsSaved;
}
void App_SettingsSaved(object sender, EventArgs e)
{
//do something here
}
SettingsSaved works fine when the app is launched for the first time, but when the app is launched the second time, SettingsSaved becomes null. Is there a way to make sure SettingsSaved works the same as it does when the app is launched the first time?
I'm a novice coder and I'm pretty sure I'm missing something really fundamental here.
Instead of putting it in the public MainPage(), maybe try putting it in an App.Initialize event to ensure it absolutely happens on start-up.
I think I figured out the problem. I believe I have to subscribe to the event first before I can fire the event, in my code above, I wasn't able to subscribe to it first because App.xaml.cs is executed first before I can subscribe to it in my Mainpage.xaml.cs.
This works for me the first time I started my app because I had some additional code which awaited something.
My solution is more of a hack where I awaited a delayed task like this:
public partial class App : Application
{
public static event EventHandler SettingsSaved;
private async void Application_Launching(object sender, LaunchingEventArgs e)
{
//this await will cause the thread to jump to MainPage to subscribe to SettingsSaved event.
await Task.Delay(500);
if (SettingsSaved != null)
{
SettingsSaved(this, null);
}
}
Of course I would appreciate it very much if someone could come up with a more elegant solution where the MainPage can be initialized first before continuing with the code in App.xaml.cs
Related
I have an event handler on my form for a LinkLabel linkLabel2_LinkClicked:
private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
//code here
}
I need to call it from another method that does not have an object sender and any eventargs:
private void UpdateMethod()
{
linkLabel2_LinkClicked(this, ?????)
}
If it were a Button I would just call the PerformClick method. But there is no such for a LinkLabel that I could find.
What is the best practice to execute the code in the linkLabel2_LinkClicked event handler?
Update: I guess I was not clear on this. I wonder about the best practice as I have seen this approach. I can see from the answers that this is not the correct approach but to move the code to a separate method and call it directly from the other method. Please let me know if any other reasoning goes with this.
Update 2: I rewrote the code now as follows:
private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
CreatePreview();
}
private void UpdateMethod()
{
CreatePreview();
}
private void CreatePreview()
{
//code comes here
}
It works perfectly.
You can put null in event parameter :
linkLabel2_LinkClicked(this, null);
or create a new event object :
linkLabel2_LinkClicked(this, new LinkLabelLinkClickedEventArgs());
But the best way is create a separate methode and call it in every time you need it.
You could just pass null since you're not using the parameter anyway, but I'd recommend against that. It's discouraged to call an event directly, and it leads to code that's tough to read.
Just have the other method call CreatePreview().
private void UpdateMethod()
{
CreatePreview();
}
As you can see, I have two classes. RfidReaderHardware generates event in thread "th", but Form running at another thread. As you can see, in form if use Invoke method of ListViewControl. So, question is how to change RfidReaderHardware to resolve encapsulation problem.
public class RfidReaderHardware : IDisposable
{
public event EventHandler<RfidReaderEventArgs> OnNewPackage;
Thread th;
//This method will be called from thread "th"
private void FireNewPackageEvent(UHFPackage package)
{
... code ...
}
... some code ...
}
and we have example code, where this event is using
public partial class PassageForm : Form
{
RfidReaderHardware RfidReader = new RfidReaderHardware(...);
private void Form1_Load(object sender, EventArgs e)
{
RfidReader.OnNewPackage += NewRfidPackage;
}
//not sure, but i think it's running in thread "th"
private void NewRfidPackage(Object o, RfidReaderEventArgs e)
{
ListViewItem item = new ListViewItem();
//from point of encapsulation view it's wrong as you know
CPackageList.Invoke(new Action(() => {CPackageList.Items.Add(item); }));
}
}
question is how to change RfidReaderHardware to resolve encapsulation problem
In fact there is no encapsulation problem. By definition, the relation between event source and subscriber is one to many, hence the source cannot "encapsulate" a logic for a specific subscriber. It's the subscriber choice how to handle the notification. One can ignore it, or handle it immediately, or like in your case handle it on the UI thread either synchronously (using Control.Invoke) or asynchronously (using Control.BeginInvoke).
Not so sure there's any real need to fix this, having the UI object itself deal with the fact that event is fired on the "wrong" thread is not a flaw. As long as you know it is in fact fired on the wrong thread, a documentation requirement.
.NET however has a general mechanism to solve this, it is used in several places inside the .NET Framework code. Your RfidReaderHardware class constructor can copy the value of SynchronizationContext.Current and store it in a field. With the implicit assumption that the object is created by code that runs on the UI thread. When you are ready to fire the event, and the copied object isn't null, you can then use its Post() or Send() method. Which automagically makes the code resume on the UI thread. Regardless of the specific UI class library that was used, works just as well in a WPF or Universal app for example.
Some sample code, it doesn't take much:
public class RfidReaderHardware {
public event EventHandler Received;
public RfidReaderHardware() {
syncContext = System.Threading.SynchronizationContext.Current;
}
protected void OnReceived(EventArgs e) {
if (syncContext == null) FireReceived(e);
else syncContext.Send((_) => FireReceived(e), null);
}
protected void FireReceived(EventArgs e) {
var handler = Received;
if (handler != null) Received(this, e);
}
private System.Threading.SynchronizationContext syncContext;
}
Is it possible to call/trigger/throw/fire (don't know what the correct term is) events from inside a constructor in C#?
The reason I am asking is that I have a dilemma: I have a form that takes very long to initiate(go through its constructor) because it needs to load lots of files. So, I want a splash/loading screen to appear until the main form is initiated. Moreover, I want to update the splash screen with updates telling it what has loaded so far and what has not.
I run the splash screen in a separate thread and want to send the messages about what has loaded through events. Unfortunately, it seems I cannot fire events from within the constructor of the main form. Anyone have any suggestions as to what I could do? Or how I would trigger events from within a constructor?
Thanks in advance.
This question may help you
C# constructor event
It contains event calling procedure from constructor
If you are using winform then take a look on the following code
public partial class Form1 : Form //Your initial form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
LaunchWorkForm();
}
private void LaunchWorkForm()
{
var form2 = new Form2();
form2.OnStatusUpdated += form2_OnStatusUpdated;
form2.ShowDialog();
}
private void form2_OnStatusUpdated(string status)
{
//message comes from Working Form
//Invoke UI thread and update UI here
}
}
Now, this is your form or dialog having a lot of work to do
public partial class Form2 : Form
{
public delegate void UpdateStatusHandler(string status);
public event UpdateStatusHandler OnStatusUpdated;
public Form2()
{
//Start thread here
if (OnStatusUpdated != null)
{
OnStatusUpdated("I am going to start work");
}
//Doing a lot of work here
if (OnStatusUpdated != null)
{
OnStatusUpdated("Some of work has been done");
}
//Do other
if (OnStatusUpdated != null)
{
OnStatusUpdated("Now I am ready to load the form");
}
}
}
If you can pass in arguments to the constructor, then you can use a callback. Something like:
public class MyClass
{
public MyClass(Action<Progress> callback)
{
// Do work here...
callback(progress);
// More work, etc.
}
}
I am new to C# and I probably know somebody asked the same thing here before. I found some info on google and here on stackoverflow , but I just can't get it to work properly.
I need to call a non-static void (MainPage.cs / class MainPage) .
public async void UploadThat()
{
.
.
.
.
Messagebox.Show("Hello there!");
}
from a another cs file (WebServer.cs).
I tried to do it like this in Webserver.cs file:
using MainPage;
.
.
.
public MainPage test;
and than call: test.UploadThat();
It complied my app successfully, but it does not work.
Thanks in advance..
There are several ways to solve this. Here are the two most common:
call the method directly; since the method is not static, you need a reference to the MainPage instance. That instance could be passed to the constructor of WebServer, and stored as a field. Note that this approach causes high coupling between the classes, which is usually not desirable.
in WebServer.cs:
private readonly MainPage _mainPage;
public WebServer(MainPage mainPage)
{
_mainPage = mainPage;
}
...
_mainPage.UploadThat();
in MainPage.cs:
WebServer ws = new WebServer(this);
expose an event in the WebServer class; have MainPage handle this event by calling UploadThat; when WebServer wants to call UploadThat, it just raises the event, and MainPage takes care of it. This way, WebServer doesn't have to know anything about MainPage.
in WebServer.cs:
public event EventHandler UploadRequested;
private void OnUploadRequested()
{
EventHandler handler = UploadRequested;
if (handler != null)
handler(this, EventArgs.Empty);
}
...
// instead of calling UploadThat directly
OnUploadRequested();
in MainPage.cs:
WebServer ws = new WebServer();
ws.UploadRequested += ws_UploadRequested;
...
private void ws_UploadRequested(object sender, EventArgs e)
{
UploadThat();
}
As a side note, you should avoid async void methods, except for event handlers or method overrides. This article explains why.
I've reviewed the MSDN doc and a couple SO answers, and all signs point to this working. At this point, I think I've either completely misunderstood what to expect or I've missed one line of code I need.
In short, I've got a WinForms app with a button, and I want another function to "click" that button at one point in the code. Here's the relevant bits:
// form.Designer.cs
this.btnAddBranch.Click += new System.EventHandler(this.btn_add_Click);
// form.cs
// using statements
public partial class EditClient : Form
{
// ...
public TestClick()
{
//btnAddBranch.PerformClick(); <-- would like to know why this fails ...
btn_add_Click(this, EventArgs.Empty);
}
private void btn_add_Click(object sender, EventArgs e)
{
MessageBox.Show("You clicked it!");
}
}
The commented line for btnAddBranch.PerformClick() is what I was hoping would do the equivalent of the line below it. But it doesn't, it doesn't seem to do anything when TestClick() is called. If I do the uncommented line, it works fine.
Am I missing something, or am I totally misunderstanding something?
Your problem is that TestClick() is your form constructor. There are no Controls to call PerformClick() on until the Form Constructor is complete. If you really want to call the code that early then do something like the following.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//Do not call methods on controls here, the controls are not yet initialized
}
private void TestClick()
{
btn_add.PerformClick();
}
private void btn_add_Click(object sender, EventArgs e)
{
MessageBox.Show("You Clicked it");
}
private void Form1_Load(object sender, EventArgs e)
{
TestClick();
}
}
Calling your PerformClick() anywhere other than the form constructor will create the desired results.
Sorry, I've updated my answer to correct it. I initially thought it was because you were not calling Button.PerformClick() after Form.InitializeComponent() (from the Form.Designer.cs auto-generated code), but I was corrected that this still does not work.
It seems that the Form is not sufficiently created in the constructor to allow Button.PerformClick(). I theorized that this may due to the fact that the Modal message loop wasn't fully created yet, but after looking at Button.PerformClick's code in Reflector, that doesn't seem to be quite the case.
PerformClick's code looks like this:
public void PerformClick()
{
if (base.CanSelect)
{
bool flag;
bool flag2 = base.ValidateActiveControl(out flag);
if (!base.ValidationCancelled && (flag2 || flag))
{
base.ResetFlagsandPaint();
this.OnClick(EventArgs.Empty);
}
}
}
While looking through, the first failure I notice here is CanSelect will return false because the control is not currently Visible (ShowDialog has not yet been called). Therefore, PerformClick will do nothing as observed. This is by digging down through the CanSelect implementation:
internal virtual bool CanSelectCore()
{
if ((this.controlStyle & ControlStyles.Selectable) != ControlStyles.Selectable)
{
return false;
}
for (Control control = this; control != null; control = control.parent)
{
if (!control.Enabled || !control.Visible)
{
return false;
}
}
return true;
}
In the debugger, you can put a breakpoint in the constructor and see that Button1 will not yet be visible (makes sense).
However, I will suggest that you can accomplish what you want from the constructor, by separating your application logic from the Button's event handler. For example...
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
DoSomething();
}
private void DoSomething()
{
// application logic here...
MessageBox.Show("Hello World");
}
private void button1_Click(object sender, EventArgs e)
{
DoSomething();
}
}
Or, as the previous answer suggests you can call Button.PerformClick() from the Form.OnLoad method. However, it is probably better to just call the application logic directly from both spots instead of performing button clicks in the UI.
Sorry for the initially incorrect answer. Hope this helps explain.
Make sure your form is already Shown :)
If its hidden, or not shown, you cant perform a click.
Atleast this way it worked for me (i show a form for a short moment, perform a click, and hide it immidiately after).
And it works!