I have this method with its delegate that is used to append text to a multiline TextBox in the GUI from any of the threads in my WinForms application:
private delegate void TextAppendDelegate(TextBox txt, string text);
public void TextAppend(TextBox txt, string text)
{
if(txt.InvokeRequired)
txt.Invoke(new TextAppendDelegate(TextAppend), new object[] {txt, text });
else
{
if(txt.Lines.Length == 1000)
{
txt.SelectionStart = 0;
txt.SelectionLength = txt.Text.IndexOf("\n", 0) + 1;
txt.SelectedText = "";
}
txt.AppendText(text + "\n");
txt.ScrollToCaret();
}
}
It works great, I just call TextAppend(myTextBox1, "Hi Worldo!") from any thread and the GUI is updated. Now, is there some way to pass a delegate that invokes TextAppend to one of my utility methods in another project without sending any reference to the actual TextBox, something that might look like this from the caller:
Utilities.myUtilityMethod(
new delegate(string str){ TextAppend(myTextBox1, str) });
And in the callee, a definition similar to:
public static void myUtilityMethod(delegate del)
{
if(del != null) { del("Hi Worldo!"); }
}
So that when this function is called, it invokes the TextAppend method with that string and the predefined TextBox the caller wants to use. Is this possible or am I crazy? I know there are way easier options like using interfaces or passing the TextBox and delegate, but I want to explore this solution because it seems more elegant and hides stuff from the callee. The problem is that I'm still too novice in C# and barely understand delegates, so please help me with the actual syntax that would work.
Thanks in advance!
Assuming you're using C# 3 (VS2008) or later:
Utilities.myUtilityMethod(str => TextAppend(myTextBox1, str));
...
public static void myUtilityMethod(Action<string> textAppender)
{
if (textAppender != null) { textAppender("Hi Worldo!"); }
}
If you're using .NET 2.0, you can use an anonymous method instead of a lambda expression:
Utilities.myUtilityMethod(delegate(string str) { TextAppend(myTextBox1, str); });
If you're using .NET 1.x, you need to define the delegate yourself and use a named method:
delegate void TextAppender(string str);
void AppendToTextBox1(string str)
{
TextAppend(myTextBox1, str);
}
...
Utilities.myUtilityMethod(new TextAppender(AppendToTextBox1));
...
public static void myUtilityMethod(TextAppender textAppender)
{
if (textAppender != null) { textAppender("Hi Worldo!"); }
}
Related
I want to display the content asynchronously in textbox? Do anyone know the bug of my code listed below? I want to implement the text in textbox will be updated per second with new value? also i want to ask why checking the InvokeRequired each time before calling the invoke method for the controller?
private void Counting(int Num)
{
int i = 0;
string counter = null;
while (i < Num)
{
Thread.Sleep(1000);
counter = string.Format(" {0}", i);
tbxStatus.BeginInvoke(new UpdateStatusDelegate(UpdateStatus), new string[] { counter });
}
}
public void UpdateStatus(string data)
{
tbxStatus.Text += data;
}
public delegate void UpdateStatusDelegate(string data);
public delegate void CountDelegate(int num);
private void btnStart_Click(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.Invoke(new CountDelegate(Counting), new object[] { 5 });
}
else
Counting(5);
}
Thanks
Your InvokeRequired test should be inside the delegate:
public void UpdateStatus(string data)
{
if (this.tbxStatus.InvokeRequired)
{
UpdateStatusDelegate d = new UpdateStatusDelegate(UpdateStatus);
this.Invoke(d, new object[] { data });
}
else
{
this.tbxStatus.Text = data;
}
}
You can also make this a lot easier and cleaner looking if you use the following extension methods:
public static TResult SafeInvoke(this T isi, Func call) where T : ISynchronizeInvoke
{
if (isi.InvokeRequired) {
IAsyncResult result = isi.BeginInvoke(call, new object[] { isi });
object endResult = isi.EndInvoke(result); return (TResult)endResult;
}
else
return call(isi);
}
public static void SafeInvoke(this T isi, Action call) where T : ISynchronizeInvoke
{
if (isi.InvokeRequired) isi.BeginInvoke(call, new object[] { isi });
else
call(isi);
}
So if I want to call a method that I have defined in my UI thread (like a method defined in your form instance) you can do so with the following code (with no need to create any delegates or anything):
formInstance.SafeInvoke(f => f.myFormMethod("parameter1","parameter2"));
in your case, you could do the following:
formInstance.SafeInvoke(f => f.UpdateStatus(myCounterInt.toString));
or something like that.
I've written about using this on my blog but don't give me the credit as I was writing about this CodeProject article
I have recently come to a similar problem.
I am writing a networked game and I wanted to append text to a text box I have, however I would get an error saying I was trying to change a windows form control from a different thread, thus causing a not safe thread. This is because I am using ASyncCallback on my server side.
I had this previously: (The console method is a simple method that gets a string and appends it to the textbox).
console("message");
And to solve the problem I had to change it to this, solving the problem for now:
this.Invoke((MethodInvoker)delegate { console("message"); });
Hopefully this helps others that come across this problem. It probably isn't the best approach possible but it did the trick for me.
Regards.
This would be the first time I'd use delegates in c# so please bear with me. I've read a lot about them but never thought of how/why to use this construct until now.
I have some code that looks like this:
public class DoWork()
{
public MethodWorkA(List<long> TheList) {}
public void MethodWork1(parameters) {}
public void MethodWork2(parameters) {}
}
I call MethodWorkA from a method outside the class and MethodWorkA calls MethodWork 1 and 2. When I call methodA, I'd like to pass some sort of parameter so that sometimes it just does MethodWork1 and sometimes it does both MethodWork1 and MethodWork2.
So when I call the call it looks like this:
DoWork MyClass = new DoWork();
MyClass.MethodA...
Where does the delegate syntax fit in this?
Thanks.
public void MethodWorkA(Action<ParamType1, ParamType2> method) {
method(...);
}
You can call it using method group conversion:
MethodWorkA(someInstance.Method1);
You can also create a multicast delegate that calls two methods:
MethodWorkA(someInstance.Method1 + someInstance.Method2);
For what you described, you don't need delegates.
Just do something like this:
public class DoWork
{
public void MethodWorkA(List<long> theList, bool both)
{
if (both)
{
MethodWork1(1);
MethodWork2(1);
}
else MethodWork1(1);
}
public void MethodWork1(int parameters) { }
public void MethodWork2(int parameters) { }
}
If you're just experimenting with delegates, here goes:
public partial class Form1 : Form
{
Func<string, string> doThis;
public Form1()
{
InitializeComponent();
Shown += Form1_Shown;
}
void Form1_Shown(object sender, EventArgs e)
{
doThis = do1;
Text = doThis("a");
doThis = do2;
Text = doThis("a");
}
string do1(string s)
{
MessageBox.Show(s);
return "1";
}
string do2(string s)
{
MessageBox.Show(s);
return "2";
}
}
Considering that all methods are inside the same class, and you call MethodWorkA function using an instance of the class, I honestly, don't see any reason in using Action<T> or delegate, as is I understood your question.
When I call methodA, I'd like to pass some sort of parameter so that
sometimes it just does MethodWork1 and sometimes it does both
MethodWork1 and MethodWork2.
Why do not just pass a simple parameter to MethodWorkA, like
public class DoWork()
{
public enum ExecutionSequence {CallMethod1, CallMethod2, CallBoth};
public MethodWorkA(List<long> TheList, ExecutionSequence exec)
{
if(exec == ExecutionSequence.CallMethod1)
MethodWork1(..);
else if(exec == ExecutionSequence.CallMethod2)
MethodWork2(..);
else if(exec == ExecutionSequence.Both)
{
MethodWork1(..);
MethodWork2(..);
}
}
public void MethodWork1(parameters) {}
public void MethodWork2(parameters) {}
}
Much simplier and understandable for your class consumer.
If this is not what you want, please explain.
EDIT
Just to give you an idea what you can do:
Example:
public class Executor {
public void MainMethod(long parameter, IEnumerable<Action> functionsToCall) {
foreach(Action action in functionsToCall) {
action();
}
}
}
and in the code
void Main()
{
Executor exec = new Executor();
exec.MainMethod(10, new List<Action>{()=>{Console.WriteLine("Method1");},
()=>{Console.WriteLine("Method2");}
});
}
The output will be
Method1
Method2
In this way you, for example, can push into the collection only functions you want to execute. Sure, in this case, the decision logic (which functions have to be executed) is determined outside of the call.
I am creating an event driven class so that when I pass it a series of data, it will process and then return the value when ready.
Below is the code that I am currently using the below code however it is quite nasty and I'm not sure if can be simpler than this.
public delegate void MyEventHandler(double result);
public static MyEventHandler EventComplete;
public static void MakeSomethingHappen(double[] data)
{
ThreadPool.QueueUserWorkItem(DoSomething, data);
}
private static void DoSomething(object dblData)
{
InvokeEventComplete(AndSomethingElse((double[])dblData));
}
private static void InvokeEventComplete(double result)
{
if (EventComplete != null)
{
EventComplete(result);
}
}
public static double AndSomethingElse(double[] data)
{
//do some code
return result; //double
}
In my main class I simply hook up a method to the event like so,
MyClass.EventComplete += new MyClass.EventCompleteHandler(MyClass_EventComplete);
Here you are:
Exposed event as an actual event rather than a publicly accessible member delegate.
Eliminated extra delegate declaration and used generic delegate Action.
Eliminated extra invocation function which was simply verbose.
Used lambda expression for event registration.
Edited code is:
MyClass.EventComplete += (result) => Console.WriteLine("Result is: " + result);
public class MyClass
{
public static event Action<double> EventComplete;
public static void MakeSomethingHappen(double[] data)
{
ThreadPool.QueueUserWorkItem(DoSomething, data);
}
private static void DoSomething(object dblData)
{
var result = AndSomethingElse((double[])dblData);
if (EventComplete != null)
{
EventComplete(result);
}
}
public static double AndSomethingElse(double[] data)
{
//do some code
return result; //double
}
}
Some things to consider...
There's an EventHandler<T> where T : EventArgs in .NET, but the trade off is you end up writing a custom EventArgs to pass your double data instead of a custom delegate. Still I think that's a cleaner pattern to follow.
If you were to define your event as
public static MyEventHandler EventComplete = delegate {};
//using a no-op handler like this has implications on Garbage Collection
Does using a no-op lambda expression for initializing an event prevent GC?
you could save yourself the if(EventComplete != null) check everytime and hence make the Invoke... method redundant.
you can also simplify
MyClass.EventComplete += new MyClass.EventCompleteHandler(MyClass_EventComplete);
to
MyClass.EventComplete += MyClass_EventComplete;
Aside from that it looks fine. I presume all the static's around the code are just from working in a ConsoleApplication :-)
try using standart event pattern (thousands times used inside FCL)
// in [CompleteEventArgs.cs] file
public class CompleteEventArgs : EventArgs {
private readonly double _result;
public CompleteEventArgs(double result) {
_result = result;
}
public double Result {
get { return _result; }
}
}
// inside your class
// don't forget 'event' modifier(!) it prevents lots of illegal stuff
// like 'Complete = null' on the listener side
public static event EventHandler<CompleteEventArgs> Complete;
public static void MakeSomethingHappen(double[] data) {
ThreadPool.QueueUserWorkItem(DoSomething, data);
}
private static void DoSomething(object dblData) {
OnComplete(new CompleteEventArgs(AndSomethingElse((double[])dblData)));
}
// if you're working with a 'normal' (non-static) class
// here should be 'protected virtual' modifiers to allow inheritors
// use polymorphism to change the business logic
private static void OnComplete(CompleteEventArgs e) {
if (Complete != null)
Complete(null, e); // in 'normal' way here stands 'this' instead of 'null'
// this object (link to the sender) is pretty tricky
// and allows extra flexibility of the code on the listener side
}
public static double AndSomethingElse(double[] data) {
double result = 0;
//do some code
return result; //double
}
I'm writing a form app in c# and I need to be able to change the contents of a Rich Text Box from any thread, I tried using a delegate and InvokeRequired, but the delegate I made still gives me a cross-thread call error, and InvokeRequired crashes the form, without giving an error.
Function I need to be able to execute from any thread:
public static void updateSub(int what)
{
subDisplay.subBox.Text = tb[what];
}
The delegate I tried to use:
public delegate void UpdateDelegateVoid(int what);
static public UpdateDelegateVoid uSub = new UpdateDelegateVoid(updateSub);
uSub(0);
My InvokeRequired code:
public static void updateSub(int what)
{
if (subDisplay.subBox.InvokeRequired)
{
subDisplay.subBox.Invoke(new MethodInvoker(finish));
}
else
{
subDisplay.subBox.Text = tb[what];
}
}
I'm not really sure why the code above isn't working. Thanks!
Strictly speaking, when you check InvokeRequired and find it's true, you should marshall the call to the same method. I'm not sure it fixes your specific problem (I'd need to see more exception details and code) but this is what I mean:
public static void updateSub(int what)
{
if (subDisplay.subBox.InvokeRequired)
{
subDisplay.subBox.Invoke(new Action<int>(updateSub), what);
}
else
{
subDisplay.subBox.Text = tb[what];
}
}
If you're getting "weird behaviour", then check that the form is actually created on the main application thread. In WinForms this isn't forced (as it is in WPF) so it's just possible that the thread that the form was created on isn't actually the root thread of the app.
I mostly use this, and it works perfectly. For the exact same purpose are what you are intending.
public void UpdateSub(string message)
{
subDisplay.subBox.Invoke((Action)delegate {
subDisplay.subBox.Text = message;
});
}
Hope it help's your or someone else with it!
Try this - where you call the same method if an invoke is required.
public void UpdateSub(string message)
{
if (!subDisplay.subBox.InvokeRequired)
{
subDisplay.subBox.Text = message;
}
else
{
var d = new UpdateFormText(UpdateSub);
Invoke(d, new object[] { message });
}
}
Where UpdateFormText is the delegate
public delegate void UpdateFormText(string message);
I would like to make a delegate available to an entire class. The point of this is to allow a called method from an external class' backgroundWorker to continually report back through all of it's methods (ExternalClass.Run(); calls ExternalClass.Method2(); ExternalClass.Method3(); etc and they all need to send several progress reports. It seems inefficient to have to continually pass the delegate.
I've tried initializing an instance of the delegate globally and setting it to equal the passed instance in Run(); for each method to then have available to it but I am given an error that a null object cannot be implicitly converted.
thanks!
I cannot show the code I am working with as I do not currently have it with me (it's on my laptop) but I will try to better explain now. PSEUDO-CODE:
class form1 : form {
backgroundWorker_doWork()
{
Class2.Run();
}
backgroundWorker_OnProgressChange()
{
// do this
}
}
class class2{
Run(){
OtherMethod();ThirdMethod();
}
OtherMethod(){ //need to call backgroundWorker.ReportProcess(int, string)}
ThirdMethod(){ //need to call backgroundWorker.ReportProcess(int, string)}
}
I really don't want to have to pass it every time is the point, i'd like to somehow pass it to class2
You should show your code that isn't working and the exact error message. It should be fine - here's an example:
using System;
class Demo
{
private readonly Action action;
public Demo(Action action)
{
this.action = action;
}
public void FirstMethod()
{
Console.WriteLine("In first method");
action();
}
public void SecondMethod()
{
Console.WriteLine("In second method");
action();
}
}
class Test
{
static void Main()
{
Demo demo = new Demo(() => Console.WriteLine("Action called"));
demo.FirstMethod();
demo.SecondMethod();
}
}
You can use the InvokeMethod function from a backgroundWorker to allow the worker to execute any delegate, example below (also waits for the invoke to finish, which you may not need):
BackgroundWorker Function (C++.net)
BackgroundWorkerFunction()
{
::IAsyncResult ^ThreadResult;
SetTileCount_Delegate ^SetCountDel = gcnew SetTileCount_Delegate(this, &PartDetail::SetTileCount_Function);
//RecordingContainer is the class I am invoking into
ThreadResult = this->RecordingContainer->BeginInvoke(
SetCountDel, ThisTest->RecordingsCache->Count);
WaitForInvokeTimeOutOrCompletion(ThreadResult);
}
System::Void WaitForInvokeTimeOutOrCompletion(IAsyncResult ^ThreadResult)
{
if(ThreadResult == nullptr) return;
long SleepTotal = 0;
long SleepInterval = 100;
while ((SleepTotal <= 2000) && !ThreadResult->IsCompleted)
{
ThreadResult->AsyncWaitHandle->WaitOne(SleepInterval, false);
SleepTotal += SleepInterval;
}
}