Issue running C# function from another C# application - c#

I have a C# Windows Form that contains a function called automation. I then have a C# console application that I am trying to use to call the function of the Windows Form. I have created the reference and have gotten this far:
Form1 FormInstance = new Form1();
FormInstance.automation += new EventHandler(?);
My question is, I have tried to add something where my question mark is but I continue getting an error. If I set it up like this:
FormInstance.automation += new EventHandler(NewHandler);
I get "NewHandler" does not exist in the current context.
And if I create
public void NewHandler(object sender, EventArgs e)
I get An object reference is required for the non-static field, method, or property.
I can not figure out what I am doing wrong.

It is supposed to be object.NewHandler, where object may be this if this occurs within the context of a member method. You can be forgiven for tripping this up because most member references can be implicit but this one has to be explicit.

At a high level it works something like this:
public static void Main(string[] args)
{
Form x = new Form();
x.Method = new EventHandler(MyHandler);
}
public static void MyHandler(object sender, EventArgs e)
{
// Stuff
}
It looks like you haven't marked your method with the static keyword (if invoking this via a static method like a console main). You also need to make sure you're assigning the appropriate delegate to the event; i.e. automation in your method needs to be able to accept an EventHandler delegate.

The simplest way is to make your event handler method static
public static void NewHandler(object sender, EventArgs e)

Related

How can I pass a function to a C# class dll, that I am calling from another C# app? The function is defined in the app where the dll is called

I am calling a C# class dll in my C# service app. But in the class dll, at some point there has to be executed a method that is defined on the caller app. So I want to pass, like a parameter, a whole method to the dll, that has to be executed at a specific time.
The challainging point is that the function has to be executed in the dll, in a timer event. How can I pass my function in this case?
My C# app where I call the dll.
using MyClassLibrary; // my dll
namespace Concheetah_Service_Bahmuller
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
MyClassLibrary.Main_Prog main_Prog = new MyClassLibrary.Main_Prog();
main_Prog.Main_Start(); // starting point of my dll
}
public void func_passed()
{
// some supplementary code
}
}
}
MyClassLibrary
System.Timers.Timer timer1 = new System.Timers.Timer();
public void Main_Start()
{
Initialize_timer1(); // starting point of the dll
}
public void Initialize_timer1()
{
timer1.Elapsed += new ElapsedEventHandler(OnTimedEvent_timer1);
timer1 = 35;
timer1.Start();
}
private void OnTimedEvent_timer1(object sender, EventArgs e)
{
//some code
func_passed(); // at this point my passed function should be executed.
}
Have a look at Delegates, Anonymous Methods and Lambda Expressions.
Note that it makes no difference whether the code is in another DLL (in another assembly in C# terms) or not as long as you have a reference to this other project or assembly and the things you want to access are public.
Change the library like this (showing only changed things):
private Action _timerAction;
public void Main_Start(Action timerAction)
{
_timerAction = timerAction;
Initialize_timer1();
}
private void OnTimedEvent_timer1(object sender, EventArgs e)
{
//some code
_timerAction();
// If _timerAction can be null, call it like this instead:
_timerAction?.Invoke();
}
Then call it like this from the application:
main_Prog.Main_Start(func_passed);
Make sure not to add braces () after func_passed since we don't want to call the function here, we want to pass the function itself as an argument.
There are different Action and Func Delegates having a different number of parameters. Unlike Action, Func has a return type other than void.
Another way to solve the problem is to have the library expose an event the application can subscribe to.
See also: Handle and raise events

How can I utilize a button to perform an action that is inside of a static class? [duplicate]

This question already has answers here:
how to call static method inside non static method in c#
(4 answers)
Closed 3 years ago.
I'm a beginner c# student and we have just started working with WinForms. For an assignment we have been given a GUI that we have to create and a few classes with methods to go along with it. I won't put all of the info here because it will be too much. Basically one of the key components of the winform is for the user to be able to type in a txt file name and click the "load" button and have it display the contents of the file. I know how to read from a file and all that.
My problem is that I don't know how I can utilize the Load method that I have since it is in a static class. My instructor has specified in the requirements that it must be a static class which looks like this:
public static class DataStore
{
public static Catalog Load(string filePath)
{
}
public static void Save(Catalog catalog, string filePath)
{
}
}
Catalog is another class I have but I don't feel it's relevant to my question. What I'm wondering is, how am I supposed to call the Load method in my button click event which looks like this:
private void Load_btn_Click(object sender, EventArgs e)
{
}
I'm having trouble figuring out how I'm supposed to link these two things: the method and the click event.
Just pass the Load method the filepath?
private void Load_btn_Click(object sender, EventArgs e)
{
// get the file path from the textbox, probably want a validation check to
// ensure that it's a valid path
Catalog catalog = DataStore.Load(filePath);
}
You can call it directly
private void Load_btn_Click(object sender, EventArgs e)
{
var data = DataStore.Load("filepath");
}

C#- using a variable in an 'enclosing' local scope?

I am trying to add some new features to a C# application- in particular, trying to replicate some of its behavior, but inside a web browser, rather than in the application, as it currently is.
I am trying to call a method that has been defined in the Browser.cs class from inside a method in the MainWindow.cs class.
The method is defined in Browser.cs with:
public partial class Browser : Form{
public Browser(){
...
}
public void Browser_Load(object sender, EventArgs e){
webKitBrowser1.Navigate("https://google.com");
}
...
}
I am then trying to call it from MainWindow.cs as follows:
public partial class MainWindow : Window{
...
public MainWindow(){
...
Browser mBrowser = new Browser();
Object sender = new Object();
EventArgs e = new EventArgs();
mBrowser.Browser_Load(sender, e);
...
}
...
}
But, I'm getting a compile error that says:
A local or parameter named 'e' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
What does this mean? I've never come across this error before- I am using the variable inside the same scope as where it has been declared- what does it mean by 'enclosing local scope'? Is that because I'm using e inside the parenthesis for the method call to mBrowser.Browser_Load(sender, e)?
Surely, since the call to this method is inside the same scope as where I've defined e, it shouldn't be an issue of scope?
I did try performing the call with:
mBrowser.Browser_Load(sender, EventArgs e);
but this gave me a compile error saying:
'EventArgs' is a type, which is not valid in the given context.
Can anyone point out what I'm doing wrong here, and what I should be doing to be able to call this method correctly?
The error is pretty clear, you have already defined e named variable in your scope, (Probably in the part of code that you haven't shown).
But more importantly, you shouldn't be calling the Load event like that, instead extract the functionality in a separate method and call the method from your Load event and other places.
Like:
public void SomeMethodToBeCalledOnLoad()
{
webKitBrowser1.Navigate("https://google.com");
}
public void Browser_Load(object sender, EventArgs e)
{
SomeMethodToBeCalledOnLoad();
}
public MainWindow(){
...
Browser mBrowser = new Browser();
Object sender = new Object();
EventArgs e = new EventArgs();
SomeMethodToBeCalledOnLoad();//here
...
}
You already have a variable named e in the scope.
try to call your method like this
mBrowser.Browser_Load(this, EventArgs.Empty);
and the error should go.

Using Control.Invoke in an optimal way

I have started a typical windows forms project (c#) with visual studio. I'm using a BackgroundWorker to fill up a TreeView control and display current progress for user. I have to use a Control.Invoke method to get access for the my TreeView control's methods (like TreeView.Nodes.Add(string ...) ). I have two questions.
Is it possible to "automatically" get reference to the object which invoke delegate method? For example, when I call myTree.Invoke(tbu, new object[] {myTree}) , I send a myTree object as an argument for the method. Is it the only possible way or I can do it in a someway like EventHandlers do (like an "Object sender" argument)?
And what is the best practice: to declare a class method used for delegate as static (TreeBU in this code), or as I have done below - Declare a static public variable for MainForm object and then use it when initialize a delegate object ( TreeStart tbu = Program.thisForm.TreeBU )?
Sorry for my c# and english, and thanks in advance!
namespace SmartSorting
{
public delegate void TreeStart(TreeView xmasTree);
static class Program
{
public static MainForm thisForm;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
thisForm = new MainForm();
Application.Run(thisForm);
}
}
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
treeView1.Nodes.Clear();
backgroundWorker1.RunWorkerAsync(treeView1);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker1 = (BackgroundWorker) sender;
e.Result = stage1(worker1, (TreeView)e.Argument);
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null) MessageBox.Show(e.Error.Message);
}
private bool stage1(BackgroundWorker wrkr, TreeView myTree)
{
TreeStart tbu = Program.thisForm.TreeBU;
myTree.Invoke(tbu, new object[] {myTree});
return true;
}
public void TreeBU (TreeView xmasTree)
{
xmasTree.BeginUpdate();
}
}
}
You usually assign a delegate by directly passing it a function (which must match the delegate signature!):
MyCrossThreadDelegateInstance += invokeMe;
or
new MyCrossThreadDelegate(invokeMe);
Check this:
Youre on different thread and would like to update the TreeControl using your invokeMe() method.
private void invokeMe()
{
MyTree.BeginUpdate();
}
Due to this call on MyTree.BeginUpdate() is coming from a different thread, crossthread exception is thrown.
To prevent this we modify our invokeMe() method to avoid throwing the exception:
private void invokeMe()
{
if (MyTree.InvokeRequired)
MyTree.Invoke(new CrossThreadDelegate(invokeMe);
else
MyTree.BeginUpDate();
}
Before invoking u check if invoke is required - this is the case when u try to access a control from a different thread then the one the control was created on. This way it tries to find the thread which owns and created the control by bubbling up you thread tree.
If Control.InvokeRequired returns true, the same method (passed over by the delegate) is called again from the next thread. This is repeated until the owning thread is found. Now Control.InvokeRequired returns false and your ELSE-block is executed on the proper thread whithout throwing a crossthread exception.
For more details see MSDN Control.Invoke
There is no need to declare anything static except you want your delegate to be available in a global scope.
Edit: If you would use the BackgroundWorker like it was meant to be, the ProgressChanged event would do the job since this event is risen on the proper thread (UI thread). This event is fired by calling the BackgroundWorker.ReportProgress() member. See MSDN - BackgroundWorker class for more details

Set up single event handler for multiple forms

I have some forms, and in them i have some event functions which are basically identical
I have tried to implement a 'Shared' class and link the Eventhandler to that function, but when i give the function the necessary protection level, it complains about it's non-static-ness and i have to make it static also.
I'm not a fan of static functions, and so ask: Is there a better way to do it?
(In case the above is unclear: I want to do this: Set up single event handler for multiple buttons in .NET? but with multiple forms instead of multiple controls)
EDIT: as per request for more info:
I'm fairly OCD about code duplication, and my program has multiple forms active/hidden at the same time, and obviously i want to close the whole program when the 'x' is pressed so:
class Shared
{
public static void FormClosed(object sender, FormClosedEventArgs e)
{
Application.Exit();
}
public static void FormClosing(object sender, FormClosingEventArgs e)
{
if (MessageBox.Show("Are you sure you want to exit?", "Confirm exit", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) {
e.Cancel = true;
}
}
}
Very simple functions, i know, but i don't like duplication :P
The above 'configuration' of 'public static' works fine, but i just wondered if there was a 'better way' (tm)
You can use static method and then delegate handling to instance and only then use all prettiness of OOP
public static void GeneralHandler(object sender, EventArgs args)
{
instance.Handle(sender, args);
}
private static MyProcessingClass instance = new MyProcessingClass();
Subscribe like
button1.Event1 += GeneralHandler;
Button1.Event2 += GeneralHandler;
Button1.Event1 += GeneralHandler;
You can further enhance your implementation to support Dependency Injection, like introduce HandlerProvider and encapsulate creating mechanism there, while exposing only interface outside
If you don't want a static class, you have 2 easy options to suit most preferences:
singleton
pass parameter to form ctor
For a singleton:
class EventMangler {
private static readonly _instance = new SomeHandler ();
// although you don't like static methods :(
static EventMangler Instance {
get { return _instance; }
public void SomeEventHandler (object sender, EventArgs e) {
// handle event
}
}
// use EventMangler.Instance
public MyForm () {
InitializeComponent();
button1.Click += EventMangler.Instance.SomeEventHandler;
}
To pass a parameter to the Form's constructor, you have more choices: (a) pass reference to the handler's object, or (b) pass a reference to the handler itself. I prefer option (b) for a single handler. Otherwise, if the parent object - e.g. EventMangler - has multiple handlers, use option (a):
// remove singleton Instance method from EventMangler
// instantiate EventMangler in Program and pass to Form ctors
// pass a single handler reference as Action
public MyForm (Action<object, EventArgs> handler) {
InitializeComponent();
button1.Click += handler;
}

Categories