Ive been playing around with delegates trying to learn and I ran into one small problem Im hoping you can help me with.
class myClass
{
OtherClass otherClass = new OtherClass(); // Needs Parameter
otherClass.SendSomeText(myString);
}
class OtherClass
{
public delegate void TextToBox(string s);
TextToBox textToBox;
public OtherClass(TextToBox ttb) // ***Problem***
{
textToBox = ttb;
}
public void SendSomeText(string foo)
{
textToBox(foo);
}
}
the form:
public partial class MainForm : Form
{
OtherClass otherClass;
public MainForm()
{
InitializeComponent();
otherClass = new OtherClass(this.TextToBox);
}
public void TextToBox(string aString)
{
listBox1.Items.Add(aString);
}
}
Obviously this doesnt compile because the OtherClass constructor is looking for TextToBox as a parameter. How would you recommend getting around the issue so I can get an object from myClass into the textbox in the form?
You can change the OtherClass to something like
class OtherClass
{
public delegate void TextToBox(string s);
TextToBox textToBox;
public OtherClass()
{
}
public OtherClass(TextToBox ttb) // ***Problem***
{
textToBox = ttb;
}
public void SendSomeText(string foo)
{
if (textToBox != null)
textToBox(foo);
}
}
But I am not quite sure what you wish to achive with
class myClass
{
OtherClass otherClass = new OtherClass(); // Needs Parameter
otherClass.SendSomeText(myString);
}
Related
I'm trying to create a class (in the context of a Windows Application) that can update progress (or send some user message) back to the main form UI via delegates. The problem I have is that the compiler won't allow any of the constructs I attempt because of missing object references. This has been discussed here but no answers had to do with writing to an object on a Form.
in c++ I would do this:
void LogToUI(string s)
{
if(Form1)
Form1->update(s);
}
void TForm1::update(string s)
{
listbox->Items->Add(s);
}
// so that any function, anywhere, can update the listbox (thread safety aside)
in C#:
namespace test
{
public delegate void callback(String msg);
public partial class Form1 : Form
{
public void writeToListbox(String s)
{
listbox.Items.Add(s);
}
public static void writeToConsole(String s)
{
System.Console.WriteLine(s);
}
public void createclass
{
callback ui_update = writeToConsole; // this is ok
callback ui_update = writeToListbox; // not allowed
someclass SC = new someclass(ui_update);
}
}
class someclass
{
callback cb;
void someclass(callback T)
{
this.cb = T;
}
void logthis(string s)
{
cb("it's me!");
}
}
}
I understand the problem with having to assign a static method to the delegate, and the Form1 method is non-static. I would like to use the delegate method because it seems the cleanest; I just can't find a way to write this in such a way as to make it work, short of passing a pointer back to the Form, which seems messy.
I believe I just came across the answer. You have to expose a static reference to a UI object, in this case a ListBox. Then you can assign the callback delegate to a function that makes sure the listbox reference is not null. You just need to make sure you assign the static reference when the form is created:
namespace test
{
public delegate void callback(String msg);
public partial class Form1 : Form
{
public static ListBox callbackListBox; // add this
public void writeToListbox(String s)
{
if(null == callbackListBox)return; // add this check
// also make this threadsafe:
if (callbackListBox.InvokeRequired)
{
callbackListBox.Invoke(new MethodInvoker(() => { writeToListbox(s); }));
}else{
callbackListBox.Items.Add(s);
callbackListBox.TopIndex = callbackListBox.Items.Count - (callbackListBox.Height / callbackListBox.ItemHeight);
}
}
public static void writeToConsole(String s)
{
System.Console.WriteLine(s);
}
public void createclass
{
callback ui_update = writeToListbox; // now OK
someclass SC = new someclass(ui_update);
}
// and add this to the form's constructor:
public Form1()
{
InitializeComponent();
callbackListBox = listbox1;
}
}
class someclass
{
callback cb;
void someclass(callback T)
{
this.cb = T;
}
void logthis(string s)
{
cb("it's me!");
}
}
}
I still have to try this, but at least the compiler is not complaining.
I'm trying to inherit from an instantiated class. Why is the value of Inherited, in the code below, a null value? Is there a way to do this correctly?
namespace Sample {
public class Class1 {
static void Main() {
Class2 SecondClass = new Class2();
SecondClass.StartSomething("hello world");
}
}
public class Class2 {
public string Inherited;
public void StartSomething(string value) {
Inherited = value;
InheritSomething();
}
public void InheritSomething() {
Class3 ThirdClass = new Class3();
ThirdClass.DoSomething();
}
}
public class Class3 : Class2 {
public void DoSomething() {
Console.WriteLine(Inherited);//when complied Inherited is null
Console.ReadLine();
}
}
}
Inheriting occurs at compile time. (Therefore 'Inherited' does not have a value yet)
Values are assigned at run-time.
Inheriting from a class does not inherit the INSTANCE of that class at instantiation of the inherited class. Instead, you'd need to pass along the instance of that class. One option is to inject it into the constructor of class 3
public class Class1
{
static void Main()
{
Class2 SecondClass = new Class2();
SecondClass.StartSomething("hello world");
}
}
public class Class2
{
public string Inherited;
public void StartSomething(string value)
{
Inherited = value;
InheritSomething();
}
public void InheritSomething()
{
Class3 thirdClass = new Class3(this);
thirdClass.DoSomething();
}
}
public class Class3 : Class2
{
private Class2 _class2;
public Class3(Class2 class2)
{
_class2 = class2;
}
public void DoSomething()
{
Console.WriteLine(_class2.Inherited);
Console.ReadLine();
}
}
How can I add a method from class A to a delegate of class B without knowing in advance which method I will be adding and what class A is? And then call that delegate from class A?
class Class {
public string someProperty;
public delegate void myDelegate(Class obj);
myDelegate handler = new myDelegate(mainClassMethod); //here is the problem..
public void someMethod() {
handler();
}
}
class MainClass {
public static void Main() {
Class classObj = new Class();
classObj.someProperty = "hello";
public void mainClassMethod(Class obj) {
System.Console.WriteLine(obj.someProperty);
}
classObj.someMethod();
}
}
Should I use something other than delegates for this? By the way I am doing this in C#!
make mainClassMethod static and access it via class name MainClass. Also you cant declare nested functions as class members, you need to declare mainClassMethod separately.
class MainClass {
public static void Main()
{
Class classObj = new Class();
classObj.someProperty = "hello";
classObj.someMethod();
}
public static void mainClassMethod(Class obj)
{
System.Console.WriteLine(obj.someProperty);
}
}
Also you declared delegate void myDelegate(Class obj); so you need to pass instance of a Class as a parameter. In my example I pass object found by this reference, which is an object that you call someMethod at.
Now you can write:
class Class {
public string someProperty;
public delegate void myDelegate(Class obj);
myDelegate handler = new myDelegate(MainClass.mainClassMethod); //no error
public void someMethod()
{
handler(this);
}
}
I'm unsure as to what is the best approach for passing events down the line to parent classes and in need of some feedback.
The example code below tries to illustrate what I want to achieve.
namespace test {
public delegate void TestCompletedEventHandler(object sender,
TestCompletedEventArgs e);
public class Manager {
CarList m_carlist = null;
public CarList Cars {
get { return m_carlist; }
set { m_carlist = value; }
}
public Manager() {
Cars = new CarList(this);
}
public void Report(bool successfull) {
//...
}
}
public class CarList : List<Car> {
protected internal event TestCompletedEventHandler
Car_TestCompleted = null;
protected readonly Manager m_manager = null;
public Manager Manager {
get { return m_manager; }
}
public CarList(Manager manager) {
m_manager = manager;
}
public void Test() {
foreach(Car car in this) {
bool ret = car.Test();
manager.Report(ret);
}
}
public void Add(Car car) {
//Is this a good approach?
car.TestCompleted +=
new TestCompletedEventHandler(Car_TestCompleted_Method);
base.Add(car);
}
private void Car_TestCompleted_Method(object sender,
TestCompletedEventArgs e)
{
if(Car_TestCompleted != null) Car_TestCompleted(sender, e);
}
}
public class Car {
protected internal event TestCompletedEventHandler
TestCompleted = null;
public bool Test() {
//...
if(TestCompleted != null) TestCompleted(this,
new TestCompletedEventArgs())
}
}
public class TestCompletedEventArgs : EventArgs {
//...
}
}
using test;
Manager manager = new Manager();
manager.Cars.Car_TestCompleted +=
new TestCompletedEventHandler (Car_TestCompleted_Method);
manager.Cars.Test();
Another more specific example:
//Contains DataItems and interfaces for working with them
class DataList
{
public List<DataItem> m_dataitems { get; set; }
public TestManager m_testmanager { get; set; }
// ...
}
class DataItem
{
// ...
}
//A manager class for running tests on a DataList
class TestManager
{
public List<TestSource> m_sources { get; set; }
public WorkerManager m_workermanager { get; set; }
// ...
}
//A common interface for Tests
abstract class TestSource
{
public event EventHandler<EventArgs<object>> Completed = null;
protected TestManager m_owner { get; set; }
public abstract void RunAsync();
// ...
}
//A test
class Test1 : TestSource
{
public virtual void RunAsync()
{
//Add commands
//Run workers
//Report progress to DataList and other listeners (like UI)
//Events seem like a bad approach since they need to be forwarded through many levels of abstraction
if(Completed != null) Completed(this, new EventArgs<object>(null));
}
// ...
}
//Manages a number of workers and a queue of commands
class WorkerManager
{
public List<MyWorker> m_workers { get; set; }
public Queue<Command> m_commands { get; set; }
}
//Wrapper for BackgroundWorker
class MyWorker
{
// ...
}
//Async command
interface Command
{
// ...
}
I think you may have just over implemented this a bit... It looks like you are trying to use async operations. Even if you are using sync operations though, typically you'd just use callback methods instead of events in a case like this...
Here is an example of things to change to use callbacks here:
//new delegate
public delegate void CarReportCallback(Car theCar, bool result);
//in the Manager class, make report conform to delegate's signature
public void Report(Car theCar, bool result)
{
//do something, you know which car and what the result is.
}
//in the CarList class pass a reference to the report method in
public void Test()
{
foreach(Car car in this)
{
car.Test(manager.Report);
}
}
//in the Car class use the delegate passed to invoke the reporting
public void Test(CarReportCallback callback)
{
//... do stuff
callback(this, isTestCompleted);
}
It seems reasonable, but I'm not really sure what the use case is and how this would be used.
You've got a strong concept of containment going on, but I'm not really sure why. Also, it's kind of weird that the CarList 'sort of' seems to have ownership of the individual cars.
Additionally, I don't know why Test() on the Car class would both return a result and raise an event. It seems like you're having two different paths to return the same data. And the Manager class seems completely redundant with the CarList class at first glance.
What is the problem you're actually trying to solve here? That might help me with defining a good solution to it.
It wouldn't make sense to just have each car call an event which calls an event on the parent list. I would do it more like this:
namespace test {
public delegate void TestCompletedEventHandler(object sender,
TestCompletedEventArgs e);
public class Manager {
CarList m_carlist = null;
public CarList Cars {
get { return m_carlist; }
set { m_carlist = value; }
}
public Manager() {
Cars = new CarList(this);
}
public void Report(bool successful) {
//...
}
}
public class CarList : List<Car> {
protected readonly Manager m_manager = null;
protected List<Action<object, TestCompletedEventArgs>> delegatesList = new List<Action<object, TestCompletedEventArgs>>();
public Manager Manager {
get { return m_manager; }
}
public CarList(Manager manager) {
m_manager = manager;
}
public void Test() {
foreach(Car car in this) {
bool ret = car.Test();
manager.Report(ret);
}
}
public void Add(TestCompletedEventHandler e) {
foreach (Car car in this) {
car.OnTestCompleted += e;
}
delegatesList.Add(e);
}
public void Add(Car car) {
foreach(Action a in delegatesList)
{
car.OnTestCompleted += a;
}
base.Add(car);
}
}
public class Car {
protected internal event TestCompletedEventHandler OnTestCompleted = null;
public bool Test() {
//...
if (OnTestCompleted != null) OnTestCompleted(this, new TestCompletedEventArgs());
}
}
public class TestCompletedEventArgs : EventArgs {
//...
}
}
using test;
Manager manager = new Manager();
Manager.Cars.Add(new Car());
manager.Cars.Add(new Car());
manager.Cars.Add(new Car());
manager.Cars.Add((sender, args) =>
{
//do whatever...
})
manager.Cars.Test();
manager.Cars.Add(new Car());
I am experimenting with calling delegate functions from a delegate array. I've been able to create the array of delegates, but how do I call the delegate?
public delegate void pd();
public static class MyClass
{
static void p1()
{
//...
}
static void p2 ()
{
//...
}
//...
static pd[] delegates = new pd[] {
new pd( MyClass.p1 ),
new pd( MyClass.p2)
/* ... */
};
}
public class MainClass
{
static void Main()
{
// Call pd[0]
// Call pd[1]
}
}
EDIT: The reason for the array is that I need to call the delegate functions by an index as needed. They are not run in response to an event. I see a critical (stupid) error in my code as I had tried to execute the delegate function using the pd[] type rather than the name of the array (delegates).
If they're all the same type, why not just combine them into a single multicast delegate?
static pd delegateInstance = new pd(MyClass.p1) + new pd(MyClass.p2) ...;
...
pd();
public class MainClass
{
static void Main()
{
pd[0]();
pd[1]();
}
}
In .Net, any delegate is in fact actually a "multicast" delegate (it inherits from this built-in base class), and therefore contains an internal linked list which can contain any number of target delegates.
You can access this list by calling the method GetInvocationList() on the delegate itself. This method returns an array of Delegates...
The only restriction is that all the delegates inside of a given delegate's linked list must have the same signature, (be of the same delegate type). If you need your collection to be able to contain delegates of disparate types, then you need to construct your own list or collection class.
But if this is ok, then you can "call" the delegates in a given delegate's invocation list like this:
public delegate void MessageArrivedHandler(MessageBase msg);
public class MyClass
{
public event MessageArrivedHandler MessageArrivedClientHandler;
public void CallEachDelegate(MessageBase msg)
{
if (MessageArrivedClientHandler == null)
return;
Delegate[] clientList = MessageArrivedClientHandler.GetInvocationList();
foreach (Delegate d in clientList)
{
if (d is MessageArrivedHandler)
(d as MessageArrivedHandler)(msg);
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
pd[0]();
pd[1]();
}
public delegate void delegates();
static delegates[] pd = new delegates[]
{
new delegates(MyClass.p1),
new delegates(MyClass.p2)
};
public static class MyClass
{
public static void p1()
{
MessageBox.Show("1");
}
public static void p2()
{
MessageBox.Show("2");
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
pd[0](1);
pd[1](2);
}
public delegate void delegates(int par);
static delegates[] pd = new delegates[]
{
new delegates(MyClass.p1),
new delegates(MyClass.p2)
};
public static class MyClass
{
public static void p1(int par)
{
MessageBox.Show(par.ToString());
}
public static void p2(int par)
{
MessageBox.Show(par.ToString());
}
}
}