Sending parameter error in c# - c#

I wrote the following code in c# and after a lot of tries I still face the same error in the commented line
error message: "method name expected"
so please can you tell me the appropriate way to send the "tmp" variable for my LoadSpeceficSontrol function.
any help is appreciated in advance.
private void AddBox()
{
Thread thread= new Thread(() => LoadControls());
thread.Start();
}
delegate void LoadControlsCallback();
private void LoadControls()
{
int Nu = int.Parse(PageNumber.Text);
for (int i = (Nu - 1) * 100; i < Nu * 200 && i < MoviesList.Count; i++)
{
MovieControl tmp = new MovieControl(MoviesList[i]);
if (tmp.InvokeRequired || MoviesFlowPanel.InvokeRequired)
{
LoadControlsCallback d = new LoadControlsCallback(LoadSpeceficControl, new object[] {tmp}); // error here
this.Invoke(d);
}
else
MoviesFlowPanel.Controls.Add(tmp);
}
}
private void LoadSpeceficControl(MovieControl tmp)
{
MoviesFlowPanel.Controls.Add(tmp);
}
Code Version 2.0
private void AddBox()
{
Thread thread= new Thread(() => LoadControls());
thread.Start();
}
private void LoadControls()
{
int Nu = int.Parse(PageNumber.Text);
for (int i = (Nu - 1) * 100; i < Nu * 200 && i < MoviesList.Count; i++)
{
MovieControl tmp = new MovieControl(MoviesList[i]);
if (tmp.InvokeRequired || MoviesFlowPanel.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate { MoviesFlowPanel.Controls.Add(tmp); });
}
else
MoviesFlowPanel.Controls.Add(tmp);
tmp = null;
}
}

Should be something like this:
delegate void LoadControlsCallback(MovieControl tmp);
LoadControlsCallback d = LoadSpeceficControl;
d(tmp);

Your delegate definition of LoadControlsCallback should match signature. Like from how you using, it should look like:
delegate void LoadControlsCallback(Action<MovieControl> action, object[] objarray);

Related

Shortest way to invoke a method with parameters in C#

When I need to invoke some code in the specified thread, i am using something like this:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
delegate void MethodToInvokeDelegate(string foo, int bar);
void MethodToInvoke(string foo, int bar)
{
DoSomeWork(foo);
DoMoreWork(bar);
}
void SomeMethod()
{
string S = "Some text";
int I = 1;
dispatcher.BeginInvoke(new MethodToInvokeDelegate(MethodToInvoke), new object[] {S, I});
}
This code works fine, but it's quite heavy. I'd like to make it without declaring MethodToInvoke and MethodToInvokeDelegate - using an anonymous method. But I can't figure out how to pass parameters to it.
I can't write this like:
dispatcher.BeginInvoke((Action)delegate() { DoSomeWork(S); DoMoreWork(I); });
I need to actually pass parameters to method.
Is it any way to write it short and simple?
Example:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
int[] ArrayToFill = new int[3];
void SomeMethod()
{
for (int i = 0; i < 3; i++)
dispatcher.BeginInvoke( { ArrayToFill[i] = 10; } );
}
This code will not work: method will be called with i = 1, 2, 3 and will raise IndexOutOfRange exception. i will be incremented before method begins to execute. So we need to rewrite it like:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
int[] ArrayToFill = new int[3];
delegate void MethodToInvokeDelegate(int i);
void MethodToInvoke(int i)
{
ArrayToFill[i] = 10;
}
void SomeMethod()
{
for (int i = 0; i < 3; i++)
dispatcher.BeginInvoke(new MethodToInvokeDelegate(MethodToInvoke), new object[] {i});
}
if you wish to avoid creating a delegate type for each call, make use of Action<>, Action<,>, etc
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
string S = "Some text";
int I = 1;
dispatcher.BeginInvoke(
(Action<string, int>)((foo, bar) =>
{
MessageBox.Show(bar.ToString(), foo);
//DoSomeWork(foo);
//DoMoreWork(bar);
}),
new object[] { S, I }
);
an example with ArrayToFill[j] = 10; action can be fixed very simple:
for (int i = 0; i < 3; i++)
{
int j = i;
// lambda captures int variable
// use a new variable j for each lambda to avoid exceptions
dispatcher.BeginInvoke(new Action(() =>
{
ArrayToFill[j] = 10;
}));
}
Try this:
string S = "Some text";
int I = 1;
dispatcher.BeginInvoke(new Action(() =>
{
DoSomeWork(S);
DoMoreWork(I);
}));
[EDIT]
In response to your modified question:
The issue you are seeing there is modified closure problem.
To fix it, you merely need to copy the argument before invoking the method:
Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
int[] ArrayToFill = new int[3];
for (int i = 0; i < 3; i++)
{
int index = i;
dispatcher.BeginInvoke(new Action(() => { ArrayToFill[index] = 10; } ));
}
yourUIcontrol.BeginInvoke(new MethodInvoker(delegate {
//your code goes here
}));

Ping Completed Event Handler not working [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
When I execute this code in command line, it's working fine:
class Program
{
private static List<Ping> pingers = new List<Ping>();
private static List<string> value = new List<string>();
private static int instances = 0;
private static object #lock = new object();
private static int result = 0;
private static int timeOut = 2500;
private static int ttl = 7;
public static void Main()
{
string baseIP = "192.168.1.";
Console.WriteLine("Pinging destinations of D-class in {0}*", baseIP);
CreatePingers(254);
PingOptions po = new PingOptions(ttl, true);
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
byte[] data = enc.GetBytes("");
SpinWait wait = new SpinWait();
int cnt =1;
Stopwatch watch = Stopwatch.StartNew();
foreach (Ping p in pingers)
{
lock (#lock)
{
instances += 1;
}
p.SendAsync(string.Concat(baseIP, cnt.ToString()), timeOut, data, po);
cnt += 1;
}
//while (instances > 0)
//{
// wait.SpinOnce();
//}
watch.Stop();
for (int i = 0; i < value.Count; i++)
{
Console.WriteLine(value[i]);
}
DestroyPingers();
Console.WriteLine("Finished in {0}. Found {1} active IP-addresses.", watch.Elapsed.ToString(), result);
Console.ReadKey();
}
public static void Ping_completed(object s, PingCompletedEventArgs e)
{
lock (#lock)
{
instances -= 1;
}
if (e.Reply.Status == IPStatus.Success)
{
string sa = string.Concat("Active IP: ", e.Reply.Address.ToString());
value.Add(sa);
//Console.WriteLine(sa);
String diachiip = e.Reply.Address.ToString();
result += 1;
}
else
{
//Console.WriteLine(String.Concat("Non-active IP: ", e.Reply.Address.ToString()))
}
}
private static void CreatePingers(int cnt)
{
for (int i = 1; i <= cnt; i++)
{
Ping p = new Ping();
p.PingCompleted += Ping_completed;
pingers.Add(p);
}
}
private static void DestroyPingers()
{
foreach (Ping p in pingers)
{
p.PingCompleted -= Ping_completed;
p.Dispose();
}
pingers.Clear();
}
}
But when I convert from it to window form, it doesn't work. I don't kwow why, I have tried many different ways...
Code is here:
public partial class Form1 : Form
{
public static List<Ping> pingers = new List<Ping>();
public static List<string> value = new List<string>();
public static int instances = 0;
public static object #lock = new object();
public static int result = 0;
public int timeout = 2500;
public static int ttl = 7;
public Form1()
{
InitializeComponent();
}
public void btnscan_Click(object sender, EventArgs e)
{
string baseIP = "192.168.1.";
//int kt = Int32.Parse(txtkt.Text);
//int start = Int32.Parse(txtstart.Text);
CreatePingers(254);
PingOptions po = new PingOptions(ttl, true);
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
byte[] data = enc.GetBytes("");
int cnt = 1;
Stopwatch watch = Stopwatch.StartNew();
foreach (Ping p in pingers)
{
lock (#lock)
{
instances += 1;
}
p.SendAsync(string.Concat(baseIP, cnt.ToString()), timeout, data, po);
cnt += 1;
}
watch.Stop();
//Result alway return 0
lst1.Items.Add(result.ToString());
lst1.Items.Add(value.Count.ToString());
for (int i = 0; i < value.Count; i++)
{
lst1.Items.Add(value[i]);
lst1.Items.Add("\n");
}
DestroyPingers();
string a = "Finished in " + watch.Elapsed.ToString() + ". Found " + result + " active IP-addresses.";
lst1.Items.Add(a);
}
public static void CreatePingers(int kt)
{
for (int start = 1; start <= kt; start++)
{
// class System.Net.NetworkInformation.Ping
Ping p = new Ping();
p.PingCompleted += Ping_completed();
pingers.Add(p);
}
}
public static PingCompletedEventHandler Ping_completed()
{
PingCompletedEventHandler a = new PingCompletedEventHandler(abc);
return a;
}
static void abc(object s, PingCompletedEventArgs e)
{
value.Add("abc");
lock (#lock)
{
instances -= 1;
}
if (e.Reply.Status == IPStatus.Success)
{
string abcd = string.Concat("Active IP: ", e.Reply.Address.ToString());
value.Add(abcd);
result += 1;
}
}
public static void DestroyPingers()
{
foreach (Ping p in pingers)
{
p.PingCompleted -= Ping_completed();
p.Dispose();
}
pingers.Clear();
}
}
What is wrong in this code?
Method SendAsync returns 0 because you are not waiting for it to complete. You are missing await and async (see msdn):
async void btnscan_Click(object sender, EventArgs e)
{
...
await p.SendAsync(string.Concat(baseIP, cnt.ToString()), timeout, data,
...
}
SpinWait was making code to work in console application. In winforms you should not use SpinWait (nor Sleep) in UI thread. You can create another thread (e.g. by using Task) and then you can copy/paste code from console application 1-to-1. But then you will need to use Invoke each time when you want to access UI controls.
async/await is really better.. if it will work (I concluded that from method name, I've no idea what method does, nor how to use it).
Perhaps I miss one thing, if SendAsync returns value, then you can get it by (the requirement to mark method where you use await with async still):
var result = await p.SendAsync(...);

How can we run two threads paralleling?

public class Program
{
static void Main(string[] args)
{
var myThread = new TestThread();
Thread t = new Thread(new ThreadStart(myThread.PrintName));
Thread t1 = new Thread(new ThreadStart(myThread.PrintType));
t.Start();
t1.Start();
Console.Read();
}
}
public class TestThread
{
public void PrintName()
{
for (int i = 1; i <= 50; i++)
{
Console.WriteLine("Name {0}", i);
}
}
public void PrintType()
{
for (int i = 100; i <= 180; i++)
{
Console.WriteLine("Type {0}", i);
}
}
}
Here How can i fixed it show that i can generate output in sequential i.e
first output of Name then only output of Type... Also I want to know about using Lock() in threads? where can i get good example. I am beginners in threading and need v.simple example.
Try this:
var myThread = new TestThread();
var x=Task.Factory.StartNew(() => myThread.PrintName());
x.ContinueWith(p => PrintType());
x.Wait();
You can look at this
There are multiple other articles, just google for 'introduction threading c#'.
The purpose of threads is to allow things to happen at the same time. If you want things to happen one after another (i.e. sequentially), then do not use threads:
var obj = new TestThread();
obj.PrintName();
obj.PrintType();
Console.Read();
Or put PrintName and PrintType into the same thread, in order to keep the UI responsive:
var myThread = new TestThread();
Thread t = new Thread(new ThreadStart(
() => {
myThread.PrintName(); myThread.PrintType();
}
));
t.Start();
// Do things in the UI meanwhile
for (i = 0; i < 100; i++) {
Console.WriteLine("UI thread {0}", i);
}
Console.Read();
//This will run two operation in sequence.
public class TestThread
{
public object obj = new object();
public void PrintName()
{
Monitor.Enter(obj);
for (int i = 1; i <= 50; i++)
{
Console.WriteLine("Name {0}", i);
}
Monitor.Exit(obj);
}
public void PrintType()
{
Monitor.Enter(obj);
for (int i = 100; i <= 180; i++)
{
Console.WriteLine("Type {0}", i);
}
Monitor.Exit(obj);
}
}
That will do the trick, you should read carefully and try to do it with 3 loops by yourself:
private static void SimpleLockTest()
{
Task[] myTasks = new Task[2];
myTasks[0] = Task.Factory.StartNew(() =>
{
LockTestThreadOne();
});
myTasks[1] = Task.Factory.StartNew(() =>
{
LockTestThreadTwo();
});
Task.WaitAll(myTasks);
Console.WriteLine("Done, press ENTER to quit");
Console.ReadLine();
}
private static object locker = new object();
private static void LockTestThreadOne()
{
Monitor.Enter(locker);
for (int i = 1; i <= 50; i++)
{
Console.WriteLine("Name {0}", i);
Monitor.Pulse(locker);
Monitor.Wait(locker);
}
Monitor.Exit(locker);
}
private static void LockTestThreadTwo()
{
Monitor.Enter(locker);
for (int i = 100; i <= 180; i++)
{
Console.WriteLine("Type {0}", i);
Monitor.Pulse(locker);
Monitor.Wait(locker, 10);
}
Monitor.Exit(locker);
}

ThreadStart with Parameter method

I am trying to learn Threading in .Net.
Many of you must have seen this:
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(loop));
t.Start();
}
private void loop()
{
for (int i = 0; i < 100000; i++)
{
textBox1.Text = i.ToString();
}
}
It works fine, but what if my loop method has parameters in it, like:
private void loop(string str)
{
for (int i = 0; i < 100000; i++)
{
textBox1.Text = i + str;
}
}
Then how to call this method in my ThreadStart as ThreadStart accepts just the method name. Then how to call loop method in a different thread?
Thread t = new Thread(new ParameterizedThreadStart(loop));
t.Start("Hello world");
private void loop(object obj)
{
string str = (string)obj;
for (int i = 0; i < 100000; i++)
{
// Don't do this: you can't change a control from another thread. Danger Will Robinson!
textBox1.Text = i + str;
}
}
Note that the loop method must accept an object parameter, so you'll have to upcast the object to your type. If you don't want, you can use a closure and an anonymous method:
string str = "Hello world";
Thread t = new Thread(() => {
for (int i = 0; i < 100000; i++)
{
// Don't do this: you can't change a control from another thread. Danger Will Robinson!
textBox1.Text = i + str;
}
});
t.Start();
In this way the anonymous method will "close" around str and it will be similar as if you had passed the parameter. Similar because there are differences/problems on closing variables. In reality I would write something similar to:
string str = "Hello world";
{
string str2 = str;
Thread t = new Thread(() => {
for (int i = 0; i < 100000; i++)
{
// Don't do this: you can't change a control from another thread. Danger Will Robinson!
textBox1.Text = i + str2;
}
});
t.Start();
}
so that no one else can "touch" str2.
If you need I can find some answer on SO that explain this "problem"
You'd use ParameterizedThreadStart instead: http://msdn.microsoft.com/en-us/library/system.threading.parameterizedthreadstart.aspx
Thread t = new Thread(new ParameterizedThreadStart(loop));
t.Start("Foo");
// Note the use of Object here to match the delegate signature
private void loop(Object state)
{
var str = state as String;
for (int i = 0; i < 100000; i++)
{
// For what it is worth, this is illegal:
// textBox1.Text = i + str;
// You need to Invoke back to the UI thread to access a control's properties:
textBox1.Invoke(()=> { textBox1.Text = i + str; });
}
}
There is a ParameterizedThreadStart class that Delegates with a single parameter can be cast to when instantiating a Thread:
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(loop));
t.Start(str);
}
private void loop(string str)
{
for (int i = 0; i < 100000; i++)
{
//the code you had is a no-no when you are multithreading;
//all UI updates must occur on the main thread
//textBox1.Text = i + str;
UpdateTextBoxText(textBox1, i+str);
}
}
private void UpdateTextBoxText(TextBox textBox, string text)
{
//the method will invoke itself on the main thread if it isn't already running there
if(InvokeRequired)
{
this.Invoke((MethodInvoker)(()=>UpdateTextBoxText(TextBox textBox, string text)));
return;
}
textBox.Text = text;
}
If you don't need very fine-grained control over when the thread starts and stops, you can leave it to the ThreadPool and use Delegate.BeginInvoke:
private void button1_Click(object sender, EventArgs e)
{
Action<string> method = loop;
method.BeginInvoke(str, null, null);
}
private void loop(string str)
{
for (int i = 0; i < 100000; i++)
{
//textBox1.Text = i + str;
UpdateTextBoxText(textBox1, i+str);
}
}
private void UpdateTextBoxText(TextBox textBox, string text)
{
//the method will invoke itself on the main thread if it isn't already running there
if(InvokeRequired)
{
this.Invoke((MethodInvoker)(()=>UpdateTextBoxText(textBox, text)));
return;
}
textBox.Text = text;
}
Like this:
new Thread(() => loop("MyString")).Start();
You don't even have to mess with ThreadStart/ParameterizedThreadStart.
Take a look at ParameterizedThreadStart, it allows you to pass parameters into your thread start function.

c# text difference

I have two words:
Source: John
ConvertTo: Jack
and I want to show the effect of convert all letters from "Source" at the same time to the "ConvertTo" word. I already create a program to accomplish that but processing one letter at a time, to show the effect I use Threads, the thing is that to process all letters at the same time I suppose I need one thread per letter, and every thread will call the same function that process the letter, and I use global variables.
Here is the code (works only for texts with same lenght):
private void button1_Click(object sender, EventArgs e)
{
lblResult.Text = "";
lblResult2.Text = "";
ThreadPool.QueueUserWorkItem(new WaitCallback(Process));
}
int movement = 0;
string CumulateText;
private void Process(object stateinfo)
{
int value;
int operation; //0->[+] 1->[-]
CumulateText = "";
for (int i = 0; i <= textBox1.Text.Length - 1; i++)
{
if (textBox1.Text[i] != ' ')
{
value = (char)textBox1.Text[i] - (char)textBox2.Text[i];
if (value >= 0)
operation = 1;
else
operation = 0;
for (int ii = 0; ii <= Math.Abs(value); ii++)
{
if (operation == 1)
movement = (char)textBox1.Text[i] - ii;
else
movement = (char)textBox1.Text[i] + ii;
this.Invoke(new EventHandler(ShowMovement));
System.Threading.Thread.Sleep(10);
}
}
CumulateText += textBox2.Text[i].ToString();
}
}
private void ShowMovement(object sender, EventArgs e)
{
lblResult.Text = CumulateText + Convert.ToString((char)movement);
}
I hope I made myself understood.
please any advise to accomplish that.
thanks
To clarify more what I want to accomplish here is an example:
Source: John
ConvertTo: Jack
J - same J
o - decrease till a (o, n, m, ..., a)
h - decrease till c (h, g, f, ..., c)
n - decrease till k (n, m, l, k)
I once had to do something similar for a small little project I was working on for fun.
I do not see why you would need to create a thread for each letter to create a transition between two words unless I'm not understanding what you are pretending to do correctly.
Check and study the following code, see if its any help:
static class Program
{
static void Main()
{
TextTranstition transition = new TextTranstition();
transition.TransitionFinished += TransitionTicked;
transition.TransitionTicked += TransitionTicked;
transition.StartTransition("AmazingWordTransition", "MyNewWordAppearing", 100);
Thread.CurrentThread.Join();
Console.ReadKey();
}
public static void TransitionTicked(object sender, TranstitionEventArgs e)
{
Console.Clear();
Console.Write(e.TransitionText);
}
}
public class TranstitionEventArgs : EventArgs
{
private readonly string transitionText;
public string TransitionText { get { return this.transitionText; } }
public TranstitionEventArgs(string transitionText)
{
this.transitionText = transitionText;
}
}
public class TextTranstition
{
private struct StartInfo
{
public StartInfo(string initialText, string finalText, int timeStep)
{
this.initialText = initialText;
this.finalText = finalText;
this.timeStep = timeStep;
}
private readonly string initialText;
public string InitialText { get { return this.initialText; } }
private readonly string finalText;
public string FinalText { get { return this.finalText; } }
private readonly int timeStep;
public int TimeStep { get { return this.timeStep; } }
}
public EventHandler<TranstitionEventArgs> TransitionFinished;
public EventHandler<TranstitionEventArgs> TransitionTicked;
public void StartTransition(string initialText, string finalText, int timeStep)
{
StartInfo startInfo = new StartInfo(initialText, finalText, timeStep);
Thread t = new Thread(startTransition);
t.Start(startInfo);
}
private void startTransition(object info)
{
StartInfo startInfo = (StartInfo)info;
string initialText = startInfo.InitialText;
string finalText = startInfo.FinalText;
if (initialText.Length < finalText.Length)
{
initialText = initialText.PadRight(finalText.Length);
}
if (TransitionTicked != null) TransitionTicked(this, new TranstitionEventArgs(initialText));
while ((initialText = transition(initialText, finalText)) != finalText)
{
Thread.Sleep(startInfo.TimeStep);
if (TransitionTicked != null) TransitionTicked(this, new TranstitionEventArgs(initialText));
}
if (TransitionFinished != null) TransitionFinished(this, new TranstitionEventArgs(finalText));
}
private string transition(string initialText, string finalText)
{
StringBuilder b = new StringBuilder(finalText.Length);
for (int i = 0; i < finalText.Length; i++)
{
char c = initialText[i];
int charCode = (int)c;
if (c != finalText[i])
{
if (charCode == 122 || charCode==32) charCode = 65;
else if (charCode == 90) charCode = 97;
else
{
charCode += 1;
}
}
b.Append((char)charCode);
}
return b.ToString();
}
}
Use BackgroudWorker for this kind of stuff.

Categories

Resources