Calling non-static void from another cs file - c#

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.

Related

Xamarin.Android, How to call another method from another .cs file

Needed some help here, so I tried to run method from another .cs, I had the following code running in my mainActivity.cs
protected override void OnCreate(Bundle savedInstanceState)
{
startGame();
}
public void startGame()
{
firstNum = FindViewById<TextView>(Resource.Id.tvFirstNum);
secondNum = FindViewById<TextView>(Resource.Id.tvSecondNum);
firstNum.Text = Convert.ToString(2);
secondNum.Text = Convert.ToString(2);
}
Heres the thing, I tried to run the code from another CS file
private void BtnRestart_Click(object sender, EventArgs e)
{
MainActivity mp = new MainActivity();
mp.startGame();
}
However I got the error of
java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.app.Activity.findViewById(int)' on a null
object reference
Does anyone know why?
Thanks!
You are instantiating your MainActivity class yourself, which does not load the accompanying Layout. That's because the lifecycle methods that Android uses aren't called, so your OnCreate method will never fire (which usually handles the layout). Therefore the FindViewById will return a null value.
A note: You shouldn't call views from another class (especially if it's another Activity) like you are trying to do here. If you still want to call this from another class, you can pass the Activity as a parameter, but I wouldn't recommend that approach.
I would recommend you to read the Activity Lifecycle documentation.

How to make correct encapsulation with multithreading .NET C#

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;
}

C# Delegate and Events for Beginners

I am a beginner C# programmer just stepping into the advanced world of plugins.
What I have at the moment: I have a base architecture for plugins to provide GUIs, Functions, and classes and each instance of GUI, function and class can be accessed by other plugins. (For ex. if the state of one plugin (plugin a) changes because the user has changed then it can change the text in a label in plugin b to the new user name).
What I am trying to get working: In one word. Events. If plugin a has an event I want plugin b to be able to subscribe to it. I am using a generic event handler delegate but it doesn't want to subscribe.
Resources I have seen already: http://www.dreamincode.net/forums/topic/78974-using-reflection-to-load-unreferenced-assemblies-at-runtime/ - Extremely useful
c# Plugin Event Handling
Firing events within a plug-in architecture vs single application
The issue is that most people are trying to subscribe to an event in a plugin from an application. I wish to subscribe one plugin to the event of a second plugin
My code at the moment:
Plugin 1 Events:
public class Events
{
public event tester testingevt;
public delegate void tester(object o, EventArgs e);
public void fireIt()
{
if (testingevt != null)
{
testingevt(this, null);
}
}
}
Plugin 2 (subscription):
public void onLoad()
{
object tempInstance = pf.getInstance("thisisaplugin", "Events");
Type t = tempInstance.GetType();
t.GetEvent("testingevt").AddEventHandler(tempInstance, new EventHandler(tester));
}
I have also seen various MSDN articles but none of them try to subscribe one plugin to another.
The code I am using came directly from the dreamincode.net link.
I have tried many different ways by creating delegate types, taking eventinfo variables to store the event and this was the closest I got to gathering it but the error this code throws is:
Object of type 'System.EventHandler' cannot be converted to type 'Test_Plugin_for_Server.Events+tester'
Please can anyone help me out?
Thanks in advance.
Your question is a bit vague, it seems that you want something like that
public class Events {
// Usually, you don't have to declare delegate:
// there's a special class for it - EventHandler or EventHandler<T>
public event EventHandler TestingEvt; // <- let's make it readable
public void fireIt() {
if (TestingEvt != null) {
// Passing null is a bad practice, give EventArgs.Empty instead
TestingEvt(this, EventArgs.Empty);
}
}
...
}
...
private void tester(Object sender, EventArgs e) {
// Events that fired the event - if you need it
Events caller = sender as Events;
...
}
...
public void onLoad() {
// Get the instance
Events tempInstance = pf.getInstance("thisisaplugin", "Events") as Events;
// Or just create an isntance
// Events tempInstance = new Events();
...
// Assigning (adding) the event
tempInstance.TestingEvt += tester;
...
}

Trigger a custom event for an "external" value change

I'm reading values from a certain process memory. Let's say that I fetch them in the following way:
var foo = memoryService.GetFoo();
var bar = memoryService.GetBar();
Since it doesn't exist any events for memory changes, I would like to create custom events using polling (if you don't have any other suggestions).
Since I don't know when the values might change, the polling interval has to be set to a suitable value. I don't know how to actually write this, but something like this might do (not sure if it compiles):
public class MemoryChange : INotifyPropertyChanged
{
private Timer _timer;
public SomethingChanged(double polingInterval)
{
_timer = new Timer();
_timer.AutoReset = false;
_timer.Interval = polingInterval;
_timer.Elapsed += timer_Elapsed;
_timer.Start();
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
}
}
Do I need to create one class that implements INotifyPropertyChanged for each value (foo and bar in this case)?
Is there any way to make it run on a non blocking thread (using a Task perhaps?)?
Do I have to use polling to make this work?
Any input is much appreciated!
If you have access to your MemoryService from your main view model, then you could define a simple delegate to solve your problem.
In your MemoryService, define the delegate and related property:
public delegate void DataUpdate(object someData);
public DataUpdate OnDataUpdate { get; set; }
In the parent view model, attach a handler for the delegate:
MemoryService memoryService = new MemoryService();
memoryService.OnDataUpdate += MemoryService_OnDataUpdate;
Back in MemoryService when the data is ready:
var foo = memoryService.GetFoo();
// Always check for null
if (OnDataUpdate != null) OnDataUpdate(foo);
Now in the parent view model:
public void MemoryService_OnDataUpdate(object someData)
{
// Do something with the new data here
}
You can find out more about using delegate objects from the Delegates (C# Programming Guide) page on MSDN.
I am not sure in what context you will be using your memory service though I will give it a try to answer your quesiton.
Yes, you will have to implement INotifyPropertyChanged in every class.
Yes there is a way, Google knows it.
You can use polling or you could listen to PropertyChanged event. That would be the callback approach where you get notified when a changes happened.

Event is null after restarting app

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

Categories

Resources