|
BeginReceive is used in my class for receiving data over TCP/IP.
When reaching the callback of BeginReceive, the class fires an event and puts the received data in the EventArgs.
I use the class in a Form that displays received data. But I can't show the data without Invoke.
Does anyone know how to fire the Event without the necessity of Invoke outside the class?
class1 (receives TCP/IP data)
{
public event EventHandlerDataReceived DataReceived;
private byte[] recPacket = new byte[32000];
private void WaitForData()
{
sockClient.BeginReceive(recPacket, 0, recPacket.Length, SocketFlags.None, new AsyncCallback(OnDataReceived), null);
}
private void OnDataReceived(IAsyncResult asyn)
{
sockClient.EndReceive(asyn)
OnDataReceived(this, new DataReveivedEventArgs(recPacket)
}
public void OnDataReceived(object sender, DataReveivedEventArgs e)
{
if (DataReceived != null) { DataReceived(this, e); }
}
class2 (Form)
{
class1 tcpClass = new class1();
public class2()
{
tcpClass.DataReceived += new tcpClass.EventHandlerDataReceived(tcpClass_DataReceived);
}
private void tcpClass_DataReceived(object sender, DataReveivedEventArgs e)
{
txtData.Text = e.Data.ToString();
}
}
|
|
|
|
|
No, you have to use Invoke.
GUI controls can only be accessed from the GUI thread. Here you are trying to access it from another thread.
A nice readable way to do this would be have a separate method to perform the update.
public void UpdateTextBox(String data)
{
if (this.InvokeRequired)
{
this.Invoke(new Action<string>(UpdateTextBox), data);
return;
}
txtData.Text = data;
} This is a pretty standard pattern.
Simon
|
|
|
|
|
Isn't it possible to place an Invoke in the function that fires the event?
In a Form can be used InvokeRequired and BeginInvoke.
But in my TCP class I can't find any possibility for Invoke.
|
|
|
|
|
Kurt wrote: Isn't it possible to place an Invoke in the function that fires the event?
Not really because the class that is firing the event doesn't know what thread it should be invoking on.
The form is a GUI control, so it knows what thread the GUI thread is.
The class that is creating the event shouldn't be forced to raise the event on the GUI thread, that would be bad design, sometimes you might not want it on the GUI thread, particularly if you are doing things in the background.
It is the form that should be responsible for transferring the control to the GUI thread when updating controls.
Simon
|
|
|
|
|
First: Thank you for yor help!
Hmm, I thought of making a DLL, so the users can double click the event in the property window and fill in individual code. But the user would be forced to use invoke.
We can use so many different controls in our projects and use their events without invoke. Do all those controls doesn't use asynchronous processes?
|
|
|
|
|
Kurt wrote: Hmm, I thought of making a DLL, so the users can double click the event in the property window and fill in individual code. But the user would be forced to use invoke.
Yes, they would, but this is how winforms works so they should understand that. All GUI controls must be accessed from the GUI thread, so any calls coming from a different thread must use invoke to transfer control to the GUI thread.
Kurt wrote: We can use so many different controls in our projects and use their events without invoke. Do all those controls doesn't use asynchronous processes?
All GUI controls only use the GUI thread, so their events are all raised on the GUI thread, so it isn't a problem.
The difference with your code is that the event is coming from an callback provided by your sockClient object. This is only natural, incoming data could come in at any point, so the object watching for the data must be doing it on a different thread, otherwise it would block the GUI. So when it triggers the callback, it's coming from a different thread, that is why an invoke onto the GUI thread is required.
Simon
|
|
|
|
|
You could add a property to the class of type ISynchronizeInvoke. Then when you create the instance, assign the form to that property. When raising the event, you can check InvokeRequired and perform a BeginInvoke on the ISynchronizeInvoke object.
|
|
|
|
|
Hi Kurt,
The System.ComponentModel namespace contains the AsyncOperation class which enables a thread to raise events on the GUI thread. I won't try and modify your code as my knowledge of network programming is minimal but instead I present a simple example showing the basics.
using System;
using System.ComponentModel;
using System.Threading;
namespace WorkerThreadEvent {
class EventThread {
private AsyncOperation operation;
public event EventHandler<ProgressChangedEventArgs> ProgressChanged;
private void OnProgress(Object progress) {
EventHandler<ProgressChangedEventArgs> handler = ProgressChanged;
if (handler != null) {
ProgressChangedEventArgs args = new ProgressChangedEventArgs((int)progress, null);
handler(this, args);
}
}
public void Run() {
operation = AsyncOperationManager.CreateOperation(null);
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), null);
}
private void ThreadProc(Object state) {
try {
for (int i = 1; i <= 100; i++) {
Thread.Sleep(100);
operation.Post(new SendOrPostCallback(OnProgress), i);
}
} finally {
operation.OperationCompleted();
}
}
}
}
The only real changes to standard event coding are
1) Creation of an AsyncOperation
2) Use of the operation's Post method to marshal the event to the thread that called AsyncOperationManager.CreateOperation(null)
3) Ending the operation correctly when it no longer needed
You can incorporate this class in a simple winforms app and you'll find that the ProgressChanged event is raised on the GUI thread and there will be no need to use invoke to update the display.
I use the AsyncOperation quite often now as it really simplifies UI coding in a multithreaded programme and I'm sure that many more people would too if only the documentation on MSDN was better. An example like the one above might help!
Alan.
By the way I think that the technique I have shown is similar to the way that the BackgroundWorker class marshals events to the GUI thread.
And it would be remiss of me not to reference this excellent article by Leslie Sanford.
http://www.codeproject.com/KB/cpp/SyncContextTutorial.aspx[^]
modified on Friday, October 24, 2008 2:29 PM
|
|
|
|
|
I searched for ISynchronizeInvoke and found a complete solution for thread safe events instead.
This solution is from http://www.gmbsg.com/works/index.php?title=Events_threadsicher_aufrufen_in_.NET[^]
public static class ThreadSafe
{
public static void Invoke(Delegate method, object[] args)
{
if (method != null)
{
foreach (Delegate handler in method.GetInvocationList())
{
if (handler.Target is Control)
{
Control target = handler.Target as Control;
if (target.IsHandleCreated)
{
target.BeginInvoke(handler, args);
}
}
else if (handler.Target is ISynchronizeInvoke)
{
ISynchronizeInvoke target = handler.Target as ISynchronizeInvoke;
target.BeginInvoke(handler, args);
}
else
{
handler.DynamicInvoke(args);
}
}
}
}
}
public void OnDataReceived(object sender, DataReveivedEventArgs e)
{
if (DataReceived != null) { ThreadSafe.Invoke(this.DataReceived, new object[] { this, e });
}
It works great! No invoke outside my class is needed anymore!
|
|
|
|
|
Hi
We've developed open-source ASP.NET shopping cart. nopCommerce is a open source e-commerce solution that is ASP.NET 3.5 (C#) based with a MS SQL 2005 (or higher) backend database. nopCommerce is available for free. If somebody will be interested in reviewing it please visit http://www.nopCommerce.com
Thank you!
nopCommerce is the open-source eCommerce solution. nopCommerce is available for free.
http://www.nopCommerce.com
|
|
|
|
|
Hi all,
Does someone know if it is possible to access a variable and change the name of the variable based on a condition. (This does not make much sense but let me explain it using the example below.
I have two foreach loops, both doing the exact same thing. But it is accessing different variables. I would prefer it if i were to have one foreach loop and access the different variable based on the string that was passed to the function.
Thus having something like (string.Concat(context,"ReadOnlyProperties"))
private void CustomizeEditor(string context)
{
DetailView detailViewCore = (DetailView)View;
Object obj = detailViewCore.CurrentObject;
if (context == "live")
{
foreach (string liveTargetPropertyName in liveReadOnlyProperties.Keys)
{
CriteriaOperator criteria = CriteriaOperator.Parse(liveReadOnlyProperties[liveTargetPropertyName]);
UpdateProperty(detailViewCore, obj, liveTargetPropertyName, criteria);
}
}
else
{
foreach (string saveTargetPropertyName in saveReadOnlyProperties.Keys)
{
CriteriaOperator criteria = CriteriaOperator.Parse(saveReadOnlyProperties[saveTargetPropertyName]);
UpdateProperty(detailViewCore, obj, saveTargetPropertyName, criteria);
}
}
}
Thanks
|
|
|
|
|
You can make a method which contains the loop, and call the method twice passing the variable to loop through..
|
|
|
|
|
private void CustomizeEditor(string context)
{
DetailView detailViewCore = (DetailView)View;
Object obj = detailViewCore.CurrentObject;
string parse, propertyName;
if (context == "live"){
parse = liveReadOnlyProperties[liveTargetPropertyName];
propertyName = liveTargetPropertyName;
keys = liveReadOnlyProperties.Keys;
}
else{
parse = saveReadOnlyProperties[saveTargetPropertyName];
propertyName = saveTargetPropertyName;
keys = saveReadOnlyProperties.Keys;
}
foreach (string propertyName in keys)
{
CriteriaOperator criteria = CriteriaOperator.Parse(parse);
UpdateProperty(detailViewCore, obj, propertyName , criteria);
}
}
|
|
|
|
|
Why not simply pass in the appropriate collection?
|
|
|
|
|
Hello Is there any way to generate automatic customer id in c# windows form. Backend will be SQL Server..
|
|
|
|
|
Make a datatable. Make the customer id field primary key and set its autoincrement property to true.
Ahsan Ullah
Senior Software Engineer
|
|
|
|
|
nt_virus wrote: Backend will be SQL Server..
Use identity column for customer id.
|
|
|
|
|
|
Can u provide a sample code to generate GUID?
|
|
|
|
|
|
|
Try googling or MSDN once in a while, you could have found it in 5 minutes if you tried...
|
|
|
|
|
So I have this idea in my head that will make work easier. Many companies are now implementing web applications. This can be annoying at times. Below I listed some problems and solutions I have with web applications. I am wondering if I should create a stand alone C# application that will run in the task bar to collect any IE windows that have a specific URL or if I should create an IE Addin. The only problem with creating an Addin, is we might be locked down from installing addins, due to virus/spyware. Also, any ideas YOU have, please feel free to share. If I do get a program like this up and running I will share the source code. Thanks, Chris
Problem A:
If you access an external link (ie, from Excel or messaging program) a new web browser will open up.
Solution A:
Use Application/IE Addin to collect IE windows that have the same begining URL (which you could set in a config file)
---
Problem B:
If you are idle for two long your session times out and are asked to log back in before you can resume.
Solution B:
The Application/IE Addin will notice you have gone back to the login page and automatically log you back in. NOTE: We do not want to save the login information; but rather keep it as a varriable in the Application/IE Addin
---
Problem C:
Sometimes if you have lag to the web server you will get a page can not load error and you lose all the date you typed in a web text box.
Solution C:
Everytime you leave a page the applcation/IE Addin will copy the text to your clipboard.
|
|
|
|
|
Can someone please explain me what the above 3 are & how are they to be used in development & how they interact with each other.
Thanks.
|
|
|
|
|