I have been studying MANY other answers and examples about this and I am just getting more and more confused on how to set this up. I need to raise an event in the Robot class based on the result of the performMove method in the form class. I know I can't raise the event from another class, so what I have obviously doesn't work. But I'm really not grasping how to set this up properly. I have read the delegates and events articles on codeProject, dreamInCode, and in this site, amongst many others. This is for a beginner c# class, and I'm pretty new to this, as I'm sure everyone can tell :)
namespace Assignment12
{
public delegate void ErrorHandler();
public partial class frmRobot : Form
{
Robot moveRobot = new Robot();
public frmRobot()
{
InitializeComponent();
reset_Position();
current_Position_Display();
moveRobot.outOfRange += new ErrorHandler(moveRobot.coor_Within_Range);
}
...
private void performMove()
{
Point loc = lblArrow.Location;
int x = moveRobot.Move_Robot_XAxis(loc.X);
int y = moveRobot.Move_Robot_YAxis(loc.Y);
if (x < -100 && x > 100)
{
moveRobot.outOfRange();
x = loc.X;
}
if (y < -100 && y > 100)
{
moveRobot.outOfRange();
y = loc.Y;
}
this.lblArrow.Location = new Point(x, y);
current_Position_Display();
}
class Robot
{
public event ErrorHandler outOfRange;
...
public void coor_Within_Range()
{
System.Console.WriteLine("TestOK");
}
}
This question is quite confusing.
The question you should be posing to yourself is: who is in charge of declaring and enforcing policy? You have two entities: "form" and "robot". You have some policy about what a legal position is for the robot. What class is responsible for coming up with that policy? Does the robot know when it is out of range, and it informs the form of that fact? Or does the form know when the robot is out of range, and it informs the robot of that fact?
The thing that wishes to be informed is the event listener. The thing that wishes to inform others of a policy violation is the event source. It is totally unclear which one of these things you want to be the listener and which one you want to be the source. But the rule you are violating is clear: the event listener is not the thing that is allowed to say when the event happens. The person listening to the concert does not get to stand up and yell instructions to the pianist about what keys to press! That's the pianist's decision, and the listener merely gets to decide whether to listen or not, and how to react.
If the form gets to decide when the robot is out of range then the robot needs to be the listener. If the robot gets to decide when the form is out of range then the form needs to be the listener. Right now you've got the form being the listener, and yet it is trying to tell the robot when it is out of range.
You don't seem to need an event. Right now it's just a complicated way to call moveRobot.coor_Within_Range(). Cut out the middleman:
if (x < -100 && x > 100)
{
moveRobot.coor_Within_Range();
x = loc.X;
}
Although Within_Range and outOfRange are curiously opposite names.
You would need an event to inform the Form about something happening in the Robot. I posted an answer here about how to do that.
Your coor_Within_Range needs to raise the event:
public void coor_Within_Range()
{
System.Console.WriteLine("TestOK");
if (this.outOfRange != null) {
this.outOfRange();
}
}
Then in your Form class you need to handle the event:
public frmRobot()
{
// snipped
moveRobot.outOfRange += new ErrorHandler(this.oncoor_Within_Range);
}
public void oncoor_Within_Range() {
Console.WriteLine("robot within range");
}
Related
This question already has an answer here:
Pass event from class C through class B to class A
(1 answer)
Closed 1 year ago.
Ok so here is my use case.
I have written an MMO server game engine, and the way I have it architected right now is mostly EDA. When the server receives a packet from a client, the core server publishes an event that other classes are subscribed to which carries the packet payload in the EventType e argument. The message has a header in the first bytes of the message, the first half of the byte carries bitwise information that determines which Class should pick up the message and do something with it, while the second half of the byte determines which method in the class needs to process the message. And the classes that shouldn't process anything just drops it.
This evaluation is done through a series of if statements on each class, first asking...if (headervalue != myexpectedheader) return; ... for clarity, it's actually a double if (lessthan) || (morethan) return; because the set of header values that could belong to me is a range, because the first half of the byte addresses the class while the second half of the byte addressed the method, So the class can't really evaluate "what's mine" but rather "what's not mine" in order to keep that if statement at the top of the conditions set because it's more likely NOT MINE, than it is mine. This works just fine as is. The class that evaluates the header and determines the payload is for it, does so flawlessly, and the ones that shouldn't .. do not. I do not need help with this part, it was just asked that I explain it for others to understand.
Because this is an MMO server expected to recevied, process and respond to potentially several 1000s of users sending potentially hundreds of packets per second during network intensive activities, my concern is having a large number of classes performing condition evals for EVERY message received from untold numbers of clients.
Compound this with the fact that it is highly likely that 90 to 95% of the messages received should probably be picked up by one or two of the classes. So a LOT of system time will be wasted on evaluating "not for me" by every class, but also especially since 90% of the messages probably will go to the most used class.
I therefore am trying to build a message router that will subscribe to the incoming message event on the core server Class, perform the "which Class" condition evals just once for each message, and publish new events post-evaluation so that only the one or two other classes that really need to consume the event can subscribe to that new event and eliminate the untold numbers of wasteful evaluations that result in essentially " if (not for me) return;"
The scope of the question is really summed below, what's written above is not in scope for the actual question, it's just an explanation of how the evaluations are being conducted, and why this use case makes the question relevant.
I have a Class A which has a primary event. That event will fire off very rapidly. I have a high number of Class C's which need to potentially receive the information from Class A event. However because I have a high number of Class C subscribers, I want to create a Class B middle man as an event router to reduce the number of direct subscribers (and thus system overhead) to Class A
I want Class B to subscribe to Class A, and Class Cs to subscribe to Class B, with the final result that the correct Class C has effectively picked up the event from Class A.
I have already written the logic to sort the events, but I don't know how to write that pass through event so that Class C subscriber consumes the Class A Event by listening to the Class B event.
I'm not sure I understand the problem correctly, but to start somewhere, here's an example of what I think you're asking for (see fiddle for a test run: https://dotnetfiddle.net/abEgV4):
public class Program
{
public static void Main()
{
var source = new ClassA();
var middleman = new ClassB(source);
var subscribers = Enumerable.Range(0, 10)
.Select(_ => new ClassC(middleman))
.ToArray();
Console.WriteLine("Fire 1!");
source.FireEvent();
Console.WriteLine("Fire 2!");
source.FireEvent();
Console.WriteLine("Fire 3!");
source.FireEvent();
Console.WriteLine("Fire 4!");
source.FireEvent();
Console.WriteLine("Fire 5!");
source.FireEvent();
}
}
class ClassA
{
public delegate void SomeAEventHandler(object sender, string msg);
public event SomeAEventHandler SomeAEvent;
public void FireEvent()
{
SomeAEvent?.Invoke(this, "Event A fired");
}
}
class ClassB
{
public event ClassA.SomeAEventHandler SomeAEvent;
private ClassA _eventSource;
public ClassB(ClassA eventSource)
{
_eventSource = eventSource;
eventSource.SomeAEvent += SomeAEventHappened;
}
private void SomeAEventHappened(object sender, string msg)
{
var rnd = new Random().Next(10);
if (rnd % 2 == 0)
{
// Instead of 'this' use 'sender' if needed
SomeAEvent?.Invoke(this, msg);
}
}
}
class ClassC
{
private readonly ClassB _myMiddleman;
public ClassC(ClassB middleman)
{
_myMiddleman = middleman;
middleman.SomeAEvent += SomeAEventHappened;
}
private void SomeAEventHappened(object sender, string msg)
{
Console.WriteLine("ClassC got an event!");
}
}
Does that cover the problem or can you elaborate on what's missing?
I am writing a piece of code that takes a user through a guided script. The user will have a few seconds to answer before the answer will be displayed.
So far, my code looks like this:
GuidedExercise3 exercise3 = new GuidedExercise3();
string AntonioAnswer = string.Empty; // expected answer
int upperBound = exercise3.Script.Count - 1; // zero-based counting
for(int i = 0; i < upperBound; i += 2)
{
labelInstructions.Text = exercise3.Script[i].TextToSpeak;
AntonioAnswer = exercise3.Script[i+1].TextToSpeak; // answer
SetTimer(AntonioAnswer, txtAntonio); // set timer sending in the answer and the TextBox object.
sysTimer.Start();
}
The odd lines of a List contain the question and the even lines contain the expected answer. My question is how do I display the question for X seconds and then get the user's answer in this WinForms app and then display the answer when the timer elapses, keeping the user from going to the next step of the script but allowing them to answer the question (which is in a Textbox).
I examined this StackOverflow question, but it doesn't match: Implementing a loop using a timer in C#
Here's how I would handle something like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
MoveNextQuestion();
timerAnswer.Interval = 5000;
timerAnswer.Start();
}
private string[] _questionsAndAnswers = new[]
{
"What colour is the sky?",
"Blue",
"What do chickens lay?",
"Eggs",
};
private int _currentIndex = -2;
private void timerAnswer_Tick(object sender, EventArgs e)
{
MoveNextQuestion();
}
private void buttonAnswer_Click(object sender, EventArgs e)
{
MoveNextQuestion();
}
private void MoveNextQuestion()
{
_currentIndex += 2;
if (_currentIndex < _questionsAndAnswers.Length)
{
labelQuestion.Text = _questionsAndAnswers[_currentIndex];
}
else
{
timerAnswer.Stop();
}
}
}
I was able to get this working fairly easily with a BackgroundWorker object. See the following article at MSDN for the exact coding. BackgroundWorker Class. In particular they have two examples in the documentation and the first example is sufficient. The BackgroundWorker class is allowing my UI to continue to accept user input while waiting on a timed answer. It displays the correct answer on the RunWorkerComplete event. So the BackgroundWorker's RunAsync gets called in my for loop.
I've run into the additional issue of the BackgroundWorker not returning control to my loop. I'm looking into that problem separately.
I'm writing a simple game, like tic tac toe (only mine is bigger). The game play is simple: my turn, check if won, bot's turn, check if won. I have simple UI and API that uses Domain Entites (that's not important now). So when user's moves, API will update the board, will know that next move is bot's move, so will do it and... has to notify UI. Here is my problem.
My question is:
How to notify UI about bot's move? I mean, to keep it simple but stick to the best programming practices.
My first thought was to create an event in GameAPI class. Is that good idea? Today will all new stuff, C# 6, etc.. I'm not sure:/ Right now UI is WinForms, but I would like to use this API in other UIs, like WPF or even mobile. Here is my simplified code of UI:
EDIT: Right now I'm talking about single player game. Both UI and API is a Client. There will be multiplayer through central server in next step, but right now, single player.
public partial class Form1 : Form
{
private GameAPI api;
public Form1()
{
InitializeComponent();
api = new GameAPI();
}
private void boardClick(object sender, EventArgs e)
{
Field field = GetClickedField(e);
MoveResult result = api.MakeMove(clickedColumn);
if (result != null && result.Row >= 0)
{
MessageBox.Show(result.Row + "," + clickedColumn);
if (result.IsConnected)
{
MessageBox.Show("Success!");
}
}
}
}
and API:
public class GameAPI
{
public IGame CurrentGame { get; set; }
public void CreateGame(GameType type)
{
CurrentGame = new SinglePlayerGame();
}
public Result Move(int column)
{
if (CurrentGame == null) return null;
Player player = CurrentGame.GetNextPlayer();
if (player.Type == PlayerType.Human) return CurrentGame.Move(column, player.Id);
}
public Result MoveBot()
{
// Simulate Bot's move...
}
}
My first thought was to create an event in GameAPI class. Is that good idea?
Yes, why not? Let take for example the modern UI frameworks data binding. The key point of making data binging work is providing a property change notification (read - event) when some property value of the object is modified. Usually that's implemented via IPropertyNotifyChanged interface, which is simply a polymorphic way of declaring support for PropertyChanged event. This way, if you set the object property via code, the UI updates automatically. Hope you see the similarity with your case - the API does something and raises an event, UI (being attached handler to that event as some earlier point) receives the event and updates accordingly.
I'm trying to reproduce the simple window interface objects in C# XNA like labels, listboxes, textboxes and panels. All objects consequentially derive from basic abstract class (XNAInterfaceObject) that draws an object and updates it. In update method it interacts with a mouse and keyboard and raises various events.
The problem is when two interface objects are one over another (e.g. popup context menu over listbox) and both have non-null events - the code fires both events, when I just need the event of the topmost object. How can I check which object is the topmost? Or make somehow the top object overlap the lower. I thought about global variable which would keep the reference for the last clicked object, and other objects would check if this variable is null to proceed with their events, but I think it is a rough solution and there exists far more elegant one.
Sorry for my language, I'm not a native English-speaker.
I would probably break this issue down into two components:
Determining the order of interface objects.
Only triggering the events on the top-most object when there's an overlap.
Addressing part one is simple. Include a 'layer' field/property in the base class that specifies the depth of the object. In most game node classes I include this regardless, as it's useful in drawing. You may want a separate layering system for interface ordering if things get a bit more complex, and the downside to this approach is that you can get overlaps in which the layers are the same.
As #Attila has suggested, you can otherwise manage a Z-Ordered list of interface elements. In this case ordering is managed by index, and it's easy to manage but you can't also use this information for drawing without some additional processing and it won't be as quick as a simple value comparison.
Property
public class InterfaceComponent
{
// Class members...
private float layer;
public float Layer { get { return layer; } set { layer = Math.Abs(value); } }
public bool InFrontOf(InterfaceComponent other) { return this.Layer < other.Layer; }
}
Z-Ordered List
public class InterfaceComponent
{
private static List<InterfaceComponent> zOrder = new List<InterfaceComponent>();
// Class Members....
public InterfaceComponent()
{
// Construct class...
zOrder.Add(this);
}
private void SetZOrder(int order)
{
if (order < 0 || order >= zOrder.Count)
return;
zOrder.Remove(this);
zOrder.Insert(order, this);
// There are more efficient ways, but you get the idea.
}
public void SendBack() { SetZOrder(zOrder.indexOf(this) + 1); }
public void SendToFront() { SetZOrder(0); }
// etc...
}
Part Two
There are multiple ways to approach part two. The most obvious is to run a check against all interface components for intersection and layer property, or in the case of a Z-Ordered list, all components higher up the list (approaching 0 in my example) for intersection.
This can end up being pretty expensive, even if you use screens to make the list smaller. Instead you can manage a list of raised events and process them after you handle input. For example...
public static class InterfaceEvents
{
public static List<EventData> List = new List<EventData>();
public static void Resolve()
{
while (List.Count > 0)
{
for (int i = List.Count - 1; i > 0; i--)
{
if (List[i].EventType == List[0].EventType && List[i].Sender.Intersects(List[0].Sender))
{
if (List[i].Sender.Layer < List[0].Layer) // However you choose to manage it.
{
List[0] = List[i];
List.RemoveAt(i);
}
else
List.RemoveAt(i);
}
}
// Toggle event from List[0]
List.RemoveAt(0);
}
}
}
public struct EventData
{
public InterfaceComponent Sender;
public int EventType;
}
Anyway, those are my thoughts. It's pretty late at night, so I hope everything's remained sensible and there are no glaring mistakes.
Usually in GUI there is a list of visibility ordering (z-order) that maintains what is on top of what. Using this technique (assigning a z order to each of your component) you can check if there is anything more toward the top of a clicked component that also includes the clicked coordinates -- if there is, do not handle the click (som other component is on top, that will handle it); otherwise this component is the topmost one to handle the click
A simple solution is creating a list in your Game class:
List<XNAInterfaceObject> controls;
You can then use the order of the list for your problem. Think of the first element in your list as the control that is at the front. In the GetControlAt() method of your game, you can loop through the controls from front to back:
protected override void Update(GameTime gameTime)
{
...
MouseState ms = Mouse.GetState();
if (ms.LeftButton == ButtonState.Pressed)
{
XNAInterfaceObject control = GetControlAt(ms.X, ms.Y);
if (control != null)
control.MouseClickMethod(ms);
}
...
}
private XNAInterfaceObject GetControlAt(int x, int y)
{
for (int i = 0; i < controls.Count; i++)
{
if (controls[i].Rectangle.Contains(x, y)
{
return controls[i];
}
}
return null;
}
This means that a XNAInterfaceObject should have a Rectangle property and a MouseClickMethod(). Keep in mind that when drawing your controls, you have to loop through the list backwards.
I'm making a simple Guess-The-Number game with a GUI. I need to wait on a loop waiting for the user to input a number in a text box and press "OK". How do I wait for an event inside a loop?
Note: I don't want message boxes. This is done in the main window, hence the need to wait for input.
EDIT: I should have explained myself better. I know that there's a loop inside the GUI. What I want is another loop inside a method. Maybe there's a better way to do this. I could code stuff inside the button's event handler, now that I think about it. Although I'd need global variables. Whataver, I'll think about it, but I hope my question is clearer now.
EDIT 2: Sorry that my question wasn't clear and the edit didn't do much help. First of all, the code is too big to be posted here. I'd probably have to post a screenshot of the GUI, so it wouldn't be of much use. Basically, I have two fields, "Max number" and "Number of allowed guesses". The user enters these two and clicks "Play". A new panel becomes available, with a text box and a "Guess" button. The user enters a guess, and the program checks to see if it's correct.
The purpose of the second infinite loop is to avoid global variables. See, each time the user clicks "Play", the game has to generate a new random number as the correct guess. If everything is done inside a method, no problem. But if the "Guess" button's event handler is called multiple times, the number has to be stored as an instance variable of the Form. Sure, it's not big deal, but I think the number should be a property of the method directing the current game, not of the Form.
I'd also have to keep track of the remaining number of guesses outside of the method. Again, it's no big deal. I just want to avoid globals if I can.
Again, I'm sorry that my question wasn't too clear. I'm kind of tired, and I didn't feel like writing too much. If this still isn't clear, then don't bother. I'll think of something.
C# automatically loops infinitely waiting for events until your form is closed. You just need to respond to the button click event.
Jason Down's suggestion is wise, create a new GuessingGame class and add it to your project. I know you're worried about "global variables" (which everyone is taught in school never to use unless you absolutely have to), but think about your design specifications for a minute.
But if the "Guess" button's event handler is called multiple times, the number has to be stored as an instance variable of the Form. Sure, it's not big deal, but I think the number should be a property of the method directing the current game, not of the Form.
As an alternative, store an instance of your GuessingGame class in the form. This is not a global variable! You said so yourself, the point of the game is keep track of the guesses and generate new numbers to guess every time "Play" is clicked. If you store an instance of the game in the form then open another form (e.g. a Help or About box), then the game's instance would not be available (thus, not global).
The GuessingGame object is going to look something like:
public class GuessingGame
{
private static Random _RNG = new Random();
private bool _GameRunning;
private bool _GameWon;
private int _Number;
private int _GuessesRemaining;
public int GuessesRemaining
{
get { return _GuessesRemaining; }
}
public bool GameEnded
{
get { return !_GameRunning; }
}
public bool GameWon
{
get { return _GameWon; }
}
public GuessingGame()
{
_GameRunning = false;
_GameWon = false;
}
public void StartNewGame(int numberOfGuesses, int max)
{
if (max <= 0)
throw new ArgumentOutOfRangeException("max", "Must be > 0");
if (max == int.MaxValue)
_Number = _RNG.Next();
else
_Number = _RNG.Next(0, max + 1);
_GuessesRemaining = numberOfGuesses;
_GameRunning = true;
}
public bool MakeGuess(int guess)
{
if (_GameRunning)
{
_GuessesRemaining--;
if (_GuessesRemaining <= 0)
{
_GameRunning = false;
_GameWon = false;
return false;
}
if (guess == _Number)
{
_GameWon = true;
return true;
}
else
{
return false;
}
}
else
{
throw new Exception("The game is not running. Call StartNewGame() before making a guess.");
}
}
}
This way, all the data related to the game is encapsulated within the class. Hooking up the events is easy in the codebehind of the form:
GuessingGame game = new GuessingGame();
private void btnPlay_Click(object sender, EventArgs e)
{
int numberOfGuesses = Convert.ToInt32(txtNumberOfGuesses.Text);
int max = Convert.ToInt32(txtMax.Text);
game.StartNewGame(numberOfGuesses, max);
}
private void btnGuess_Click(object sender, EventArgs e)
{
int guess = Convert.ToInt32(txtGuess.Text);
bool correct = game.MakeGuess(guess);
if (correct)
lblWin.Visible = true;
if (game.GameEnded)
{
// disable guess button, show loss label
}
}
You should probably look for a book to actually learn windows programming.
The very basics:
1) There is already an infinite loop deep down in the windows code somewhere. Any windows program is constantly looping and scanning for input.
2) Once input is found, this loop fires off an Event.
3) Your mission, should you choose to accept it, is to write event handlers to handle those events.
you are most likely doing it wrong as it has already been pointed out, but you can use this
Application.DoEvents();
to process events when you are on an actual loop
to do it the right way
- don't use a loop
- use an edit box for the input, then a button
- implement the button onclick event
Yes, and What if I am waiting for Speech events, it could happen anytime event when a function is running, I need to handle that without recursively call a function