I have a program with some kind of "Macro Manager" that can (or at least should) save and play macros - one after the other. The macros are functions that the user can select by himself.
For example if the user wants to create a new macro he is going to do the following steps:
Click Button "Create"
Click Button "Select function"
Click another Button (The button holds a function behind it)
Play the macro
So as you can see, the user should be able to choose which function he wants to use dynamically.
I tried using delegates, but I dont really understand them (even though I have read about it)
So this is my code:
The MacroManager (Which holds the macros and plays them one after the other):
namespace ControlCenter
{
public class ControlCenterMacroManager
{
public List<ControlCenterMacro> macroList = new List<ControlCenterMacro>();
public string macroName;
public void runMacroList()
{
Thread t = new Thread(new ThreadStart(runMacroList_t));
t.Start();
}
public void runMacroList_t()
{
foreach (ControlCenterMacro macro in macroList)
{
Console.Write("Playing Macro: ");
macro.Run();
}
}
}
}
This would be the macro:
namespace ControlCenter
{
public class ControlCenterMacro
{
public bool isTimeout=false;
public int timemilli=0;
public delegate int macroAction();
public macroAction action;
public void Run()
{
if (isTimeout)
{
Console.Write("Waiting " + timemilli + " milliseconds ");
Thread.Sleep(timemilli / 4);
Console.Write(".");
Thread.Sleep(timemilli / 4);
Console.Write(".");
Thread.Sleep(timemilli / 4);
Console.Write(".");
Thread.Sleep(timemilli / 4);
Console.WriteLine(" done");
}
else
{
Console.WriteLine("Playing action " + action.ToString());
action();
}
}
}
}
And this is one of the possible functions I want to lay behind it (which is located in another class in another project):
public int turnOn()
{
Console.WriteLine("Einschalten:");
if(HomeMaticHttpRequest.sendRequest(this.url + "statechange.cgi?ise_id=" + this.RecieverId + "&new_value=true")!=null)
return 0;
return 1;
}
Does anybody know how I can solve this problem without too much hardcoding? (Want to keep it relatively dynamical)
Here is a small example stripped down to its essentials.
The Macro:
public class Macro
{
public delegate int macroAction();
public macroAction action;
public void Run()
{
action();
}
}
A container class with different methods:
public class Container
{
public int turnOn()
{
Console.WriteLine("Einschalten");
return 1;
}
public int turnOff()
{
Console.WriteLine("Ausschalten");
return 1;
}
}
And a small test programm which assigns different methods:
void Main()
{
Container c = new Container();
List<Macro> MacroList = new List<Macro>();
for (int i = 0; i < 10; i++)
{
Macro m = new Macro();
if (i % 2 == 0)
{
m.action = c.turnOn;
}
else
{
m.action = c.turnOff;
}
MacroList.Add(m);
}
foreach (var m in MacroList)
{
m.Run();
}
}
For the more general version I have to comeback tomorrow, gotta catch my train ;)
Related
i am a C# beginner, so for now most of my code is inside the Main() method. I want to make my Program more object oriented so I want to move code from Main method to another class reliably(so i can do it with other programs as well).
static void Main()
{
int xLentgh = 20;
int yLength = 20;
Map.MapBuilder(xLentgh,yLength);
int oldPositionX = 0;
int oldPositionY = 0;
int newPositionX = 0;
int newPositionY = 0;
if (oldPositionX == 0)
{
Map.WriteAt(".",newPositionX, newPositionY);
}
for (int i = 0; i < 100; i++)
{
ConsoleKeyInfo KeyStroke;
KeyStroke = Console.ReadKey();
switch (KeyStroke.Key)
{
case ConsoleKey.RightArrow:
{
if (newPositionX < xLentgh-1)
{
oldPositionX = newPositionX;
oldPositionY = newPositionY;
newPositionX++;
}
break;
}
case ConsoleKey.LeftArrow:
{
if (newPositionX > 0)
{
oldPositionX = newPositionX;
oldPositionY = newPositionY;
newPositionX--;
}
break;
}
case ConsoleKey.UpArrow:
{
if (newPositionY > 0)
{
oldPositionX = newPositionX;
oldPositionY = newPositionY;
newPositionY--;
}
break;
}
case ConsoleKey.DownArrow:
{
if (newPositionY < yLength-1)
{
oldPositionX = newPositionX;
oldPositionY = newPositionY;
newPositionY++;
}
break;
}
default: break;
}
Map.WriteAt(".",newPositionX, newPositionY);
Map.WriteAt(" ",oldPositionX, oldPositionY);
}
}
In this code I create a "map" and using the switch statement in the for loop to "track" the position of the cursor. How do I write this code in a new class? I dont know where to start
You can try to create a class named as you want (we will call it RandomNameClass) by declaring it outside of the bloc class Program {}.
You should have something like this :
namespace NameYouGaveToProject
{
class RandomNameClass
{
}
class Program
{
static void Main(string[] args)
{
// Your actual code here
}
}
}
Above or under is fine but prefer having the class Program at the bottom if you write all your code in one file.
There you have your first custom class! Now try to add some functions in it. If you haven't learn about instantiating a class yet, just don't forget to add public static before the returning type of your function.
Example of what you could have :
namespace NameYouGaveToProject
{
class RandomNameClass
{
// Function that doesn't return anything, returns "void"
public static void SayHi()
{
Console.WriteLine("Hi!");
}
// Function that returns a string
public static string ReturnHi()
{
return "Hi!";
}
}
class Program
{
static void Main(string[] args)
{
// Your actual code here
}
}
}
And then you can call them by typing the name of the class, followed by a point and then the name of the function and "()" if there are no parameters to this function (there aren't in my example).
The syntax would be :
// Call the void function
RandomNameClass.SayHi();
// Call the function returning a string
string testVariable = RandomNameClass.ReturnHi();
Note that you can call as often as you want every function
And voilĂ ! You know the basics of creating a class and call functions from this class! Next thing you should learn is how to make functions properly, and then instantiating a class and manage it's content
Is there a way to access all the different types of object inherited from the same class using the same reference in an object without hard-coding it?
I'm developing on unity and I want to add a module in my game that could watch any particular float in a GameObject to then change another float in another GameObject once it reaches a certain value.
As an example: A "Trigger" Object/Module which set the value of Hunger=1 in a brain Object when the value of Fullness<0.5 is reached in a stomach Object.
As I'll have a big number of possible combinations I don't want to hardcode it by creating a daughter of the Trigger Class for each of them.
My initial idea was to use pointers that would be directed to the good floats to watch/change upon initialization. But apparently, we can't use unsafe code inside iterators (IEnumerator) so I'm not sure how to poll the value of Fullness.
To give an example of what I would like :
public Class Trigger{
private float* ToPoll;
private float* ToChange;
public void SetTrigger(float* poll, float* change){
ToPoll = poll;
ToChange = change;
// the loop would be a IEnumerator, not a litteral loop
while(*ToPoll < 0.5f){
sleep(0.1)
}
*ToChange = 1f
}
}
void Main(){
Trigger trigger1, trigger2;
trigger1.SetTrigger(&Stomach.fullness, &Brain.hunger)
trigger2.SetTrigger(&Sun.activityLevel, &Earth.radiationLevel)
// ^ Literally any float from any object
}
Do you have any ideas how to or better ways to implement it?
Expanding on the answer from #kara, the following code implements independent Stomach and Brain objects, and uses Being to wire them up.
What Being knows about Stomach:
it has a NeedsFoodEvent
What Being knows about Brain
there is a OnRaiseIsHungryEvent (i.e. a "hungry" signal -- who cares where it came from)
it has a IsHungryEvent
Keep in mind that in a real implementation there would likely be other objects listening for those events. e.g. maybe you have an emotion system that would switch to "hangry" and a goal-based AI that would switch to food-seeking mode. Neither system would need to be aware of the other, but both could respond to signals from the Brain. In this trivial implementation the Being responds to the Stomach signal and both notifies and responds to the Brain.
The important take-away from this is not the specific method of raising and responding to events (in this case the default .Net mechanism) but the fact that neither object knows anything about the internals of the other (see the different implementations of HumanStomach and ZombieStomach) and instead the connection is wired up at a more appropriate level (Being in this case). Also note the reliance on interfaces, which allows us to do things like create hybrid beings (i.e. pairing a ZombieBrain with a HumanStomach).
Code was written/tested with .Net Core CLI as a console app, but it should be compatible with most any version of .Net > 3.5.
using System;
using System.Linq;
using System.Threading;
namespace so_example
{
public class Program
{
static void Main(string[] args)
{
var person1 = new Being("Human 1", new HumanBrain(), new HumanStomach());
var zombie1 = new Being("Zombie 1", new ZombieBrain(), new ZombieStomach());
var hybrid1 = new Being("Hybrid 1", new ZombieBrain(), new HumanStomach());
var hybrid2 = new Being("Hybrid 2", new HumanBrain(), new ZombieStomach());
Console.WriteLine("Hit any key to exit");
Console.ReadKey();
}
}
public class HungryEventArgs : EventArgs
{
public string Message { get; set; }
}
public interface IStomach
{
event EventHandler<HungryEventArgs> NeedsFoodEvent;
}
public class Stomach : IStomach
{
public event EventHandler<HungryEventArgs> NeedsFoodEvent;
protected virtual void OnRaiseNeedsFoodEvent(HungryEventArgs e)
{
EventHandler<HungryEventArgs> handler = NeedsFoodEvent;
if (handler != null)
{
handler(this, e);
}
}
}
public class HumanStomach : Stomach
{
private Timer _hungerTimer;
public HumanStomach()
{
_hungerTimer = new Timer(o =>
{
// only trigger if breakfast, lunch or dinner (24h notation)
if (new [] { 8, 13, 19 }.Any(t => t == DateTime.Now.Hour))
{
OnRaiseNeedsFoodEvent(new HungryEventArgs { Message = "I'm empty!" });
}
else
{
Console.WriteLine("It's not mealtime");
}
}, null, 1000, 1000);
}
}
public class ZombieStomach : Stomach
{
private Timer _hungerTimer;
public ZombieStomach()
{
_hungerTimer = new Timer(o =>
{
OnRaiseNeedsFoodEvent(new HungryEventArgs { Message = "Need brains in stomach!" });
}, null, 1000, 1000);
}
}
public interface IBrain
{
event EventHandler<HungryEventArgs> IsHungryEvent;
void OnRaiseIsHungryEvent();
}
public class Brain : IBrain
{
public event EventHandler<HungryEventArgs> IsHungryEvent;
protected string _hungryMessage;
public void OnRaiseIsHungryEvent()
{
EventHandler<HungryEventArgs> handler = IsHungryEvent;
if (handler != null)
{
var e = new HungryEventArgs
{
Message = _hungryMessage
};
handler(this, e);
}
}
}
public class HumanBrain : Brain
{
public HumanBrain()
{
_hungryMessage = "Need food!";
}
}
public class ZombieBrain : Brain
{
public ZombieBrain()
{
_hungryMessage = "Braaaaaains!";
}
}
public class Being
{
protected readonly IBrain _brain;
protected readonly IStomach _stomach;
private readonly string _name;
public Being(string name, IBrain brain, IStomach stomach)
{
_stomach = stomach;
_brain = brain;
_name = name;
_stomach.NeedsFoodEvent += (s, e) =>
{
Console.WriteLine($"{_name}: {e.Message}");
_brain.OnRaiseIsHungryEvent();
};
_brain.IsHungryEvent += (s, e) =>
{
Console.WriteLine($"{_name}: {e.Message}");
};
}
}
}
Some Notes
To provide some output, I faked things in the 2 IStomach implementations. The HumanStomach creates a timer callback in the constructor which fires every 1 second and checks if the current hour is a meal hour. If it is, it raises the NeedsFoodEvent. The ZombieStomach also uses a callback every 1 second, but it just fires the NeedsFoodEvent every time. In a real Unity implementation you'd likely trigger the even based on some event from Unity -- an action the player took, after some preset amount of time, etc.
I'm not quite sure, what you want to do, but it sounds like you want to add triggers to you objects. In my understanding a trigger should be a delegate in this case.
Here an example how to define a delegate-type and add a list of triggers to your Brain-class.
Every brain can now have different triggers. I setup two derived brains to show you how to work with it:
public class TestBrain
{
private static int NextId = 1;
public TestBrain(List<MyTrigger> triggers)
{
this.Triggers = triggers;
this.Id = NextId++;
}
public int Id { get; private set; }
public int Hunger { get; set; }
public int StomachFullness { get; set; }
public List<MyTrigger> Triggers { get; private set; }
public void FireTriggers()
{
foreach (MyTrigger t in this.Triggers)
{
t.Invoke(this);
this.StomachFullness = 100;
}
}
public delegate void MyTrigger(TestBrain b);
}
public class HumanBrain : TestBrain
{
static readonly List<MyTrigger> defaultHumanTriggers = new List<MyTrigger>()
{
b => { if (b.StomachFullness < 50) { b.Hunger = 1; Console.WriteLine("{0} is hungry..", b.Id); } }
};
public HumanBrain() : base(defaultHumanTriggers)
{
}
}
public class RobotBrain : TestBrain
{
static readonly List<MyTrigger> defaultRobotTriggers = new List<MyTrigger>()
{
b => { if (b.StomachFullness < 50) { Console.WriteLine("{0} ignores hunger only want's some oil..", b.Id); } }
};
public RobotBrain() : base(defaultRobotTriggers)
{
}
}
static void Main()
{
// Create some test-data
List<TestBrain> brains = new List<TestBrain>()
{
new HumanBrain(),
new HumanBrain(),
new RobotBrain(),
new HumanBrain(),
};
Console.WriteLine(" - - - Output our Testdata - - -");
foreach (TestBrain b in brains)
{
Console.WriteLine("Status Brain {0} - Stomachfulness: {1} Hunger: {2}", b.Id, b.StomachFullness, b.Hunger);
}
Console.WriteLine(" - - - Empty stomachs - - -");
foreach (TestBrain b in brains)
{
b.StomachFullness = 0;
}
Console.WriteLine(" - - - Fire triggers - - -");
foreach (TestBrain b in brains)
{
b.FireTriggers();
}
Console.WriteLine(" - - - Output our Testdata - - -");
foreach (TestBrain b in brains)
{
Console.WriteLine("Status Brain {0} - Stomachfulness: {1} Hunger: {2}", b.Id, b.StomachFullness, b.Hunger);
}
}
I'm working with an C# .Net application that uses Cplex DLL's for an optimization operation, and during that operation I want to write status progress to a statusbar on the that initiated the operation.
This is the general layout of the specific form;
namespace ActResMain
{
public class FormOptimize : System.Windows.Forms.Form
{
private callCplex()
{
//...
cplex.Use(new Cplex_ContinuousCallback());
cplex.Solve()
}
public void Update_OptimizeStatusbarPanel(String strText)
{
statusBarPanel_1.Text = strText;
statusBar1.Refresh();
}
internal class Cplex_ContinuousCallback : Cplex.ContinuousCallback
{
FormOptimize formOpt = new FormOptimize();
public override void Main()
{
//From here I want to edit the statusbar at FormOptimize. I can write progress to console without any problems, but cannot reach function "Update_OptimizeStatusbarPanel".
//If I include "FormOptimize formOpt = new FormOptimize" here, i get Visual studio exception on illegal window reference.
}
}
}
}
I have also tried invoking the Update_OptimizeStatusbarPanel function like this:
internal class Cplex_ContinuousCallback : Cplex.ContinuousCallback
{
FormOptimize formOpt = new FormOptimize();
public override void Main()
{
FormCollection fc = Application.OpenForms;
var mpc = fc[1];
Type type = mpc.GetType();
MethodInfo dynMethod = type.GetMethod("Update_OptimizeStatusbarPanel");
dynMethod.Invoke(mpc, new object[] { String.Format("Running Optimization: {0} iterations ", Niterations)});
}
}
But then I get an exception from visual studio stating that an object created by one thread cannot be modified from another thread.
Maybe this is something stupid that I have missed, but help is greatly appriciated
EDIT: I edited the code as per Mohammad Dehghans suggestion,
public class FormOptimize : System.Windows.Forms.Form
{
private callCplex()
{
cplex.Use(new Cplex_ContinuousCallback(this));
cplex.Solve()
}
internal class Cplex_ContinuousCallback : Cplex.ContinuousCallback
{
FormOptimize _formOptimize;
public Cplex_ContinuousCallback(FormOptimize formOptimize)
{
this._formOptimize = formOptimize;
}
public override void Main()
{
if (Niterations % 10 == 0)
{
_formOptimize.Update_OptimizeStatusbarPanel(0, String.Format("Running Optimization: {0} iterations ", Niterations), 0);
}
}
}
public void Update_OptimizeStatusbarPanel(short panelIndex, String strText, short severity)
{
if (statusBar1.InvokeRequired)
statusBar1.Invoke(new Action<short, string, short>(Update_OptimizeStatusbarPanel), panelIndex, strText, severity);
else
{
if (panelIndex == 0)
{
//...
statusBarPanel_0.Text = strText;
}
else if (panelIndex == 1)
{
//...
statusBarPanel_1.Text = strText;
}
statusBar1.Refresh();
}
}
}
But by doing that I apparently broke something, as the application just ..stops after statusBar1.Invoke() is called the first time. If I pause the debugger it says that cplex.Solve() is executing, but then nothing more happens.
First of all, you need to pass the instance of your form to the implemented callback class, so when the Main method is called, you have access to the exact instance that is being shown on the screen.
Secondly, you need to use Invoke method to update the UI controls from anther thread (I've not worked with CPLEX so far, but I guess the callback is invoked from another thread. That's usual).
Read this for more information.
The complete code could be:
public class FormOptimize : System.Windows.Forms.Form
{
private callCplex()
{
//Misc code
cplex.Use(new Cplex_ContinuousCallback(this)); // <-- passing `this`
cplex.Solve()
//Misc code
}
public void Update_OptimizeStatusbarPanel(String strText)
{
if (statusBarPanel_1.InvokeRequired)
statusBarPanel_1.Invoke(Action<string>(Update_OptimizeStatusbarPanel), strText);
else
{
statusBarPanel_1.Text = strText;
statusBar1.Refresh();
}
}
internal class Cplex_ContinuousCallback : Cplex.ContinuousCallback
{
FormOptimize _formOptimize;
public Cplex_ContinuousCallback(FormOptimize formOptimize)
{
this._formOptimize = formOptimize;
}
public override void Main()
{
//...
_formOptimize.Update_OptimizeStatusbarPanel(String.Format("Running Optimization: {0} iterations ", Niterations));
}
}
}
I'm studying for an exam and I came across a question I couldn't figure out. It asks to Create a TurnOnRadio method for the Radio class. This method should remove any TV subscribers to the remote control object. I thought I could do this with just = without the += or -=. When I go to do this is says This event " RemoteControl.channelChange " can only be on the left hand side of += or -= (except when used from within the type 'Remote Control') Any help on accomplishing this task would be appreciated. Code posted below.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RemoteControlApp2
{
class RemoteControl
{
public delegate void ChannelChanged(object remote, RemoteEventsArgs re);
public event ChannelChanged channelChange;
private int currentChannel;
public void ChangeTheCrrentChannel(int newChannel)
{
RemoteEventsArgs newRe = new RemoteEventsArgs(newChannel);
if (channelChange!=null)
{
channelChange(this, newRe);
}
}
}
class RemoteEventsArgs : EventArgs
{
public int newChannel;
public RemoteEventsArgs(int nc)
{
this.newChannel = nc;
}
}
class Television
{
private int tvChannel;
//Your code here
public void TurnOnTV(RemoteControl Remote)
{
Remote.channelChange += new RemoteControl.ChannelChanged(TVChannelChanged);
Console.WriteLine(Remote.ToString() + " is detected");
}
public void TurnOffTV(RemoteControl Remote)
{
Remote.channelChange -= new RemoteControl.ChannelChanged(TVChannelChanged);
Console.WriteLine(Remote.ToString() + " is no longer detected");
}
public void TVChannelChanged(Object Remote, RemoteEventsArgs nc)
{
Console.WriteLine("The TV channel is changed. New channel is: {0}", nc.newChannel);
}
}
class Radio
{
private int radioChannel;
//Your code here
public void TurnOnRadio(RemoteControl Remote)
{
Remote.channelChange = new RemoteControl.ChannelChanged(TVChannelChanged);
Console.WriteLine(Remote.ToString() + " is deteceted")
}
//May need to write RadioChannelChanged method
}
class Program
{
static void Main(string[] args)
{
RemoteControl rc = new RemoteControl();
Television tv = new Television();
tv.TurnOnTV(rc);
rc.ChangeTheCrrentChannel(29);
rc.ChangeTheCrrentChannel(32);
tv.TurnOffTV(rc);
Console.ReadKey();
}
}
}
I took out event from public event ChannelChanged channelchange;
So now it is public ChannelChanged channelchange;
Next I finished the radio class and TurnOnRadio method and now that event has been removed I can use = to remove all other subscriptions and now subscribes whatever channel the remote is changed to in main. Radio class code posted below.
class Radio
{
private int radioChannel;
//Your code here
public void TurnOnRadio(RemoteControl Remote)
{
Remote.channelChange = new RemoteControl.ChannelChanged(RadioChannelChanged);
//Console.WriteLine(Remote.ToString() + " is deteceted");
}
public void RadioChannelChanged(object Remote,RemoteEventsArgs re)
{
radioChannel = re.newChannel;
Console.WriteLine("Radio channel is changed. New channel is :{0}", re.newChannel);
}
//May need to write RadioChannelChanged method
}
i have app with gui
I put function checkproxy() in Form1.cs it works correctly and i want move function checkproxy() to other class but if i put checkproxy() in other class it will error with Invoke and richTextBox3
namespace test3
{
public partial class Form1 : Form
{
public bool continueThreads = false;
string[] proxyList = null;
List<Thread> threadList = new List<Thread>();
int proxynum = 0;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int n = (int)numericUpDown1.Value;
Thread[] tl = new Thread[n + 1];
threadList = tl.ToList();
for (int i = 0; i <= n; i++)
{
threadList[i] = new Thread(new ThreadStart(checkproxy));
}
for (int i = 0; i <= n; i++)
{
threadList[i].Start();
}
continueThreads = true;
proxyList = richTextBox1.Lines;
}
public void checkproxy()
{
while (continueThreads)
{
if (proxynum >= proxyList.Length)
{
continueThreads = false;
}
if (proxynum < proxyList.Length)
{
string proxy = proxyList[proxynum];
proxynum += 1;
string info = "";
try
{
Thread.Sleep(1000);
info += "Live || " + proxy + Environment.NewLine;
this.Invoke(new Action(() => richTextBox3.Text += info));
}
catch
{
}
}
}
}
}
}
this is screenshot error
Your method checkproxy uses Form1 class members (continueThreads, proxynum and others) directly.
If you really want do move it outside of this class (I'm not sure it is good idea since this method looks very closely related to your class) - you need to refactor this method and pass all class members it uses as method input parameters like
public void checkproxy(bool continueThreads.....)
Because this is a System.Windows.Forms.Form in original context.
To be able to Invoke interface update from another thread/async task, you need to use it (as you did correctly in your original code).
But once you move the function into separate class, there is no more notion of a Conntrol or Form there, so this is a class itself, which does not have Invoke implementation.
One possible solution: you need to refactor your method in a way, that he is able to call Form's function, that internally calls Invoke.