Godot C# "Error calling method from signal" - c#

Given my scene tree:
Main_control (Type:Control) (Parent)
mnk_game (Type: Control) (Child)
I can run methods in mnk_game's script using signals from Main_control, but it won’t work the other way around (calling a method in Main_control using a signal from mnk_game)
Error:
emit_signal: Error calling method from signal 'mnk_game_finished': 'Control(Main_control.cs)::mnk_show_game': Method not found..
Parent's code:
public class Main_control : Control
{
public override void _Ready()
{pass}
public void mnk_show_game()
{
GD.Print("mnk_show_game reached"); //What I want to reach
}
}
Child code:
public class mnk_game : Control
{
[Signal]
public delegate void mnk_game_finished();
private Godot.Control game_controller;
public override void _Ready()
{
game_controller = (Control)GetParent<Godot.Control>();
this.Connect("mnk_game_finished", game_controller, "mnk_show_game");
}
public void any_method()
{
this.EmitSignal("mnk_game_finished");
}
}
When I call the any_method method at the child's script, I want to be able to reach mnk_show_game method in the parent's script. Can I do this? If so, how?

I don't have much experience using Godot with C#, but I can see that mnk_game_finished was defined without parameters and mnk_show_game also does not take parameters. However, you are emitting the signal with a parameter this.EmitSignal("mnk_game_finished", ds.board). Try to emit the signal without a parameter like so: this.EmitSignal("mnk_game_finished") or define your delegate and function with parameters.

Related

Xamarin forms: How to access "tabBarController: shouldSelectViewController:"

I need to have control of this method so that I can make a change in my app. But I couldn't make this implementation work, can anyone help?
Here is the Custom Renderer of my TabbedPage:
public class MainTabbedPageRenderer : TabbedRenderer, IUITabBarControllerDelegate
{
[Export("tabBarController:shouldSelectViewController:")]
public bool ShouldSelectViewController(UITabBarController tabBarController, UIViewController viewController)
{
return false;
}
}
The breakpoint does not stop there at all.
I have the impression that it does not stop at breakpoint because TabBarController is always null, but the screen loads and performs navigations normally, I also could not make this TabBarController be filled.
You can click on tabbar items using this method:
[Export("tabBar:didSelectItem:")]
public void ItemSelected(UITabBar tabbar, UITabBarItem item)
{
}
I don't see where you are assigning your delegate. That is likely why it is not hit, you have not assigned the delegate to the UITabBarController (which is the base class for TabbedRenderer). Also TabbedRenderer already assigns a delegate, so you likely do not want to replace it.
That said, Xamarin.iOS actually defines a C# delegate, called UITabBarSelection, for the ShouldSelectViewController protocol method. And there is a property on TabbedRenderer called ShouldSelectViewController that allows you to set this delegate method, so you should be able to just do this:
public class MainTabbedPageRenderer : TabbedRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
this.ShouldSelectViewController = ShouldSelectViewControllerHandler;
}
bool ShouldSelectViewControllerHandler(UITabBarController tabBarController, UIViewController viewController)
{
return false;
}
}

C#: Trying to use control elements in different class - "object reference is required"

I am brand new to C# (I apologise if my question is noobish - I'm teaching myself, so it's a bumpy process). I am trying to develop a winform and since some of the methods are pretty long, I am trying to keep it in a couple classes. This is what I'm kind of hoping to achieve:
public partial class formMainForm : Form
{
public formMainForm()
{
InitializeComponent();
}
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations.LongMethod1();
}
}
public class longCalculations
{
private void LongMethod1()
{
// Arbitrarily long code goes here
}
}
I'm doing this in an attempt to keep the formMainForm class tidy and be able to split any calculations into manageable chunks. However, I'm encountering problems with using form controls (e.g. check boxes, numeric up-down controls, etc.) in my non-form classes.
If I leave them as is (e.g. CheckBox1) I get a the name does not exist in the current context error. I searched around and I found that it's because that box is defined in a different class. However, if I change it to formMainForm.CheckBox1, the error is now an object reference is required for the non-static field, method or property. Again, I looked around and it appears that that is due to the form initialization method not being static.
If I change public formMainForm() to static formMainForm(), the error now moves to InitializeComponent(); and I do not know where to go from here. I also tried making an instantiation of the formMainForm() method, but that didn't do anything (the code I attempted to use is below. I found it somewhere on this site as an answer to a similar problem).
private void formLoader(object sender, EventArgs e)
{
shadowrunMainForm runForm = new shadowrunMainForm();
runForm.Show();
}
How can I use the formcontrol names in other classes?
P.S. It is my first post here - I am super sorry if I have missed this question already being asked somewhere. I did search, but I didn't find what I was looking for.
EDIT
It seems I hadn't made myself clear - this was just an example of code and my problem is with the second class, not the first one. I have now simplified the code to:
public partial class formMainForm : Form
{
public formMainForm()
{
InitializeComponent();
}
}
public class longCalculations
{
private void LongMethod1()
{
List<CheckBox> listOfBoxes = new List<CheckBox>();
listOfBoxes.Add(CheckBox1);
// The code displays an "object reference is required for the non-static field, method or property" error at this stage. Changing the "CheckBox1" to formMainForm.CheckBox1 doesn't help
// Arbitrarily long code goes here
}
}
LongMethod1 works perfectly fine when placed in the formMainForm partial class. Moving it to the other form makes it unable to take data from those checkboxes.
I believe this line longCalculations.LongMethod1(); is throwing error cause you are trying to access a instance method as if it's a static method and as well it's defined as private method which won't be accessible outside the class. You need to create an instance of longCalculations class before accessing any of it's member or method(s) and mark the method public like
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations ln = new longCalculations();
ln.LongMethod1();
}
public class longCalculations
{
public void LongMethod1()
{
// Arbitrarily long code goes here
}
}
(OR) If you really want it to be a static method then define accordingly with static modifier like
public class longCalculations
{
public static void LongMethod1()
{
// Arbitrarily long code goes here
}
}
Now you can call it like the way you are trying
public static class longCalculations
{
public static void LongMethod1()
{
// Arbitrarily long code goes here
}
}
If you're going to make a call longCalculations.LongMethod1();, then you need to make your class static as such.
Or you leave it as not static method by calling
longCalculations lc = new longCalculations()
lc.LongMethod1();
As for accessing controls in separate classes, you can pass in the form and make the controls public which can be dangerous.
So on your Form.designer.cs, change any control you may have to public modifier. Then you would make a call like this...
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations.LongMethod1(this);
}
public void LongMethod1(Form1 form)
{
// Arbitrarily long code goes here
form.label1.Text = someString;
//more settings and whatnot
}
Or do something like this:
public class longCalculations
{
public string LongMethod1()
{
// Arbitrarily long code goes here
return myString;
}
}
longCalculations lc = new longCalculations()
string result = lc.LongMethod1();
this.label1.Text = result;
Ideally, your longCalculations class would not attempt to modify the form directly. Instead it would return an object that the form could use to update its controls.
If you need to access the form directly from the longCalculations class, first change the method to accept an instance of your form
public void LongMethod1(formMainForm myForm)
Then you can pass the form itself as a parameter
var calc = new longCalculations();
calc.LongMethod1(this);
In your other class, you need to have an instance of your formMainForm class:
var myForm = new formMainForm();
Then you can access its members like this:
myForm.CheckBox1.Checked = true;

C# trouble using delegates for cross threading

I have a problem using delegates to change a Textbox from a thread that isn't the main form thread.
I have two class, a main Form1.cs class with the UI and another class, LINClass.cs where I wrote a device functions.
In the Form1 I start a backgroundworker that poll the device continuously, and another thread that retrieve data from the device (RXTask()), all the functions of the two threads are from LINCLass.cs.
The thread that retrieve data from the device contains a delegate that point to a Form1.cs function that permit to change the Form1 textboxes:
public class LINClass : Form
{
private delegate void FormUpdater(int devnum, string rpm, string current, string temp);
//some other variables and procedure
public void RXTask()
{
FormUpdater frmUpdt = new FormUpdater(Form1.GUIupdate);
//other procedures and a loop containing the invoke...
this.Invoke(frmUpdt, new object[]{devnum, rpm,
current,
temperature});
}
The Form1 class contain the method invoked, written as below
public static void GUIupdate(int eWPnum, string rpm, string current, string temp)
{
//take the parameters and write them in the textbox
}
Now when I run the code, threads are running but I have an exception when invoke the function.
http://s13.postimg.org/9ohuj9d7r/exception.png
It says, "InvalidOperationException was not managed, Invoke or BeginInvoke cannot be called on a control until the window handle has been created"
You should use a command pattern and put the command classes into a queue from one thread, and let the other thread read from it.
You will need to prevent this.Invoke() from being called unless the form's window has been created.
The easiest way to do this is to override OnLoad() and set a flag:
private bool isLoaded;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Volatile.Write(ref isLoaded, true);
}
Then check the flag before you invoke:
public void RXTask()
{
FormUpdater frmUpdt = new FormUpdater(Form1.GUIupdate);
//other procedures and a loop containing the invoke...
if (Volatile.Read(ref isLoaded))
{
this.Invoke(frmUpdt, new object[]
{
devnum, rpm,
current,
temperature
});
}
}
(If your version of .Net doesn't have Volatile.Read()/Volatile.Write(), declare the flag as volatile instead.)

Implementing a Windows form that changes during run-time based on a Listener class

I am currently designing a GUI for a Leap Motion device (although my problem could arise with any type of listener device).
I am running my application in a Windows Form with the following code:
public partial class FormRecord : Form
{
public FormRecord()
{
InitializeComponent();
}
public void UpdateGUI(Frame frame)
{
//get information from captured frame
//update the GUI (specifically labels)
customLabel0.Text = someValueFromFrame.ToString();
}
//this method code was provided by Leap Motion on their website
public static void RunMain()
{
// Create a sample listener and controller
SampleListener listener = new SampleListener();
Controller controller = new Controller();
//Controller is included in Leap.dll (from SDK) and is an instance of controller
// Have the sample listener receive events from the controller
controller.AddListener(listener);
Console.WriteLine("Press Enter to quit...");
Console.ReadLine();
// Remove the sample listener when done
controller.RemoveListener(listener);
controller.Dispose();
}
//This class was also provided in the Leap Motion SDK
class SampleListener : Listener
{
private Object thisLock = new Object();
private void SafeWriteLine(String line)
{
lock (thisLock)
{
Console.WriteLine(line);
}
}
public override void OnInit(Controller controller)
{
SafeWriteLine("Initialized");
}
public override void OnConnect(Controller controller)
{
SafeWriteLine("Connected");
}
public override void OnDisconnect(Controller controller)
{
//Note: not dispatched when running in a debugger.
SafeWriteLine("Disconnected");
}
public override void OnExit(Controller controller)
{
SafeWriteLine("Exited");
}
public override void OnFrame(Controller controller) //
//public void OnFrame(Controller controller)
{
SafeWriteLine("Framed");
//Do something useful with the captured frame
// get the current frame
Frame frame = controller.Frame();
/* This is where my problem occurs */
// attempt to use information from this form and call UpdateGUI(Frame frame)
}
}
}
Basically, the problem is arising because of the difference in static vs. non-static nature of the two classes. For example, my application (Windows Form) is non-static because it is a form and you must be able to create several instances by nature. However, that is why I cannot simply call:
Form aForm = new Form();
aForm.UpdateGUI();
^^This creates a new form. I want to be able to fun the UpdateGUI() method on the original form.
I have also tried
guiForm = ActiveForm;
and calling the label from there
ActiveForm.customlbl0.Text = valueToDisplay;
More generally, I am trying to update a Windows Form based on data received from a Listener. This is causing me problems because I am having to struggle between static and non-static members. I would make it all one class, however I need to implement both form and Listener for the two components. How can I update a display with real-time data from a listener?
Edit: The listener is an implementation from the SDK file "LeapCSharp.Net4.0dll"
I would make the constructor of SampleListener take an instance of your form class. When you create the Listener pass in a reference to the form and store it in a private field. That way you can call methods on it from inside the listener.
Another option would be to make your SampleListener class raise events for each event. You can then hook the events from inside your form.
How about something like:
public partial class FormRecord : Form
{
Controller controller;
public FormRecord()
{
InitializeComponent();
controller = new Controller();
}
public void UpdateGUI()
{
Frame frame = controller.frame();
//get information from captured frame
//update the GUI (specifically labels)
customLabel0.Text = someValueFromFrame.ToString();
}
If you use listeners be aware that each listener callback is called on its own thread. You usually cannot update objects accessed directly by a GUI framework (like Windows Forms, etc) from any thread other than the main thread. (I don't know the best way to do cross-thread communication in Windows forms, though.)

c#, .net, delegate, asynchronous callback. What am I doing wrong here?

Heres a little class for a button in a menu in a game.
I'd like to be able to pass a delegate method _triggerMethod when I'm instantiating each button. Then that delegate method will get called when that button instances trigger method is called.
I'm trying out delegates in C# for the first time here. And as far as I'm interpreting the documentation here what I'm doing should work but visual studio is giving me a compile error in the Trigger method.
According to msdn article the code calling the delegate doesnt need to know about the original methods paramaters and such. What am I doing wrong?
Also in the msdn article they are only typing "Del" and that does not work for me. I must type "Delegate" which is odd.
class MenuItem
{
private Rectangle clickArea;
private string displayText;
private Vector2 _position;
private Delegate _triggerMethod;
public MenuItem(Vector2 pos,string txt,Delegate trig)
{
displayText = txt;
_position = pos;
_triggerMethod = trig;
}
public void Draw(SpriteBatch sb)
{
}
public void Select()
{
}
public void DeSelect()
{
}
public void IsMouseOnMe()
{
}
public void Trigger()
{
_triggerMethod();
}
}
You haven't created any delegate definition.
Example (from the MSDN-page you linked):
public delegate void Del(string message);
Then, you need to use that as your Type:
** snip **
private Del _triggerMethod;
public MenuItem(Vector2 pos,string txt,Del trig)
{
displayText = txt;
_position = pos;
_triggerMethod = trig;
}
** snip **
public void Trigger()
{
_triggerMethod("some message");
}
You can pass references of the delegate around without actually knowing what arguments it expects (since it's just a normal reference), but when you want to invoke it, you do need to give it the correct parameters.
You need to define the Del type if you want to use it:
public delegate void Del(string message);
public class MenuItem
{
private Del _triggerMethod;
public void Trigger()
{
_triggerMethod("Message");
}
}
Note that you can use the built-in Action<string> delegate type instead of defining your own:
Action<string> _triggerMethod;
_triggerMethod("Message");
If you just use the Delegate type, you can invoke it using DynamicInvoke:
public void Trigger()
{
_triggerMethod.DynamicInvoke();
}

Categories

Resources