I want warn my page that the transmitted data is completed. I create object, add event handler and call new Thread for async transmitted data to server. When data transmitted, and recive from server answer i callback my event, but throw exception 'invalid cross-thread access'.
Why don't run my event handler?
// My page (PhoneApplicationPage)
public partial class PageStart
{
private void btn_Send_Click(object sender, RoutedEventArgs e)
{
TransmitHolder holder = new TransmitHolder();
holder.onCompleted += new TransmitHolder.CompleteHandler(onCompleted);
// transmit async
new Thread(delegate() { Transmitter(holder).Start(); }).Start();
}
private void onCompleted(object sender, byte[] answer)
{
//some code
}
}
public class TransmitHolder
{
public delegate void CompleteHandler(object sender, byte[] answer);
public event CompleteHandler onCompleted;
public void Complete(byte[] answer)
{
if (onCompleted != null)
{
onCompleted(null, answer); // here throw exception `invalid cross-thread access`
}
}
}
public class Transmitter
{
private TransmitHolder holder;
public Transmitter(TransmitHolder holder)
{
this.holder = holder;
}
// send data from server
public void Start()
{
// send data using soket
NetworkManager nm = new NetworkManager();
// method Send execute Connect, Send and Recive data from server
byte[] answer = nm.Send(Encoding.UTF8.GetBytes("hello_word"));
holder.Complette(answer); // notify, send data completed
}
}
On the Windows Phone 7 Platform, all the UI logic should be done on the UI Thread. If you attempt to change the visual tree, or set/get a property of a DependencyObject (all the UI elements are DependencyObject(s) ) on a thread different thant the dedicated UI thread, you will get an Invalid Cross thread exception.
To perform UI logic on the right thread, use the adequate dispatcher.
Deployment.Current.Dispatcher.BeginInvoke(() => { <Put your UI logic here> });
Related
I have a class in which a method is called on the basis of events received from external application.
public void ProcessItems(Store id,Items items)
{
//Some logic
UpdateValidItems(id,validItems)
}
public void UpdateValidItems(Store id,Items items)
{
//Save in DB
}
The external application may invoke "ProcessItems" while UpdateValidItems is being processed. I want that if UpdateValidItems is being processed and event invoked during UpdateValidItems processing then it should wait until UpdateValidItems completed. Is there any way to do it?
Also, multiple stores can be processed at a time. So it should wait for store based only. If storeId is different then it should not wait.
I'd decouple incoming Events and processing:
Have a thread wait on a Blocking Queue
Event writes to Blocking Queue
Thread from 0.) gets notified, dequeues 1 "Row" (Id and Items)
Said Thread processes the Items
Thread waits again OR if meanwhile the Event added more Rows: Process until queue is empty, then wait again.
This ensures that:
Only one Store is mutated at a time
Event returns fast
Following events for same store do not interfere with current processing.
You may also have a look into DataFlow to implement a similar approach.
Edit / Basic Example:
public class Handler
{
private readonly BlockingCollection<QueueEntry> _queue = new BlockingCollection<QueueEntry>();
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
// I used a Form with a button to simulate events, so you'll have to adapt that..
public Handler(Form1 parent)
{
// register for incoming Items
parent.NewItems += Parent_NewItems;
// Start processing on a long running Pool-Thread
Task.Factory.StartNew(QueueWorker, TaskCreationOptions.LongRunning);
}
// Stop Processing
public void Shutdown( bool doitnow )
{
// Mark the queue "complete" - adding is now forbidden.
_queue.CompleteAdding();
// If you want to stop NOW, cancel all operations
if (doitnow ) { _cts.Cancel(); }
// Else the Task will run until the queue has been processed.
}
// This is all that happens on the EDT / Main / UI Thread
private void Parent_NewItems(object sender, NewItemsEventArgs e)
{
try
{
_queue.Add(new QueueEntry { Sender = sender, Event = e });
}
catch (InvalidOperationException)
{
// dontcare ? I didn't - You may, though.
// Will be thrown if the queue has been marked complete.
}
}
private async Task QueueWorker()
{
// While the queue has not been marked complete and is empty
while (!_queue.IsCompleted)
{
QueueEntry entry = null;
try
{
// Wait until an entry is available or until canceled.
entry = _queue.Take(_cts.Token);
}
catch ( OperationCanceledException )
{
// dontcare
}
if (entry != null)
{
await Process(entry, _cts.Token);
}
}
}
private async Task Process(QueueEntry entry, CancellationToken cancel)
{
// Dummy Processing...
await Task.Delay(TimeSpan.FromSeconds(entry.Event.Items), cancel);
}
}
public class QueueEntry
{
public object Sender { get; set; }
public NewItemsEventArgs Event { get; set; }
}
Of, course, this can be tuned to allow for some concurrency / parallel processing.
private object lock_object = new object();
public void ProcessItems(Store id,Items items)
{
//Some logic
lock(lock_object)
{
UpdateValidItems(id,validItems)
}
}
I am trying to implement a long-running background process, that periodically reports on its progress, to update the UI in a UWP app. How can I accomplish this? I have seen several helpful topics, but none have all of the pieces, and I have been unable to put them all together.
For example, consider a user who picks a very large file, and the app is reading in and/or operating on the data in the file. The user clicks a button, which populates a list stored on the page with data from the file the user picks.
PART 1
The page and button's click event handler look something like this:
public sealed partial class MyPage : Page
{
public List<DataRecord> DataRecords { get; set; }
private DateTime LastUpdate;
public MyPage()
{
this.InitializeComponent();
this.DataRecords = new List<DataRecord>();
this.LastUpdate = DateTime.Now;
// Subscribe to the event handler for updates.
MyStorageWrapper.MyEvent += this.UpdateUI;
}
private async void LoadButton_Click(object sender, RoutedEventArgs e)
{
StorageFile pickedFile = // … obtained from FileOpenPicker.
if (pickedFile != null)
{
this.DataRecords = await MyStorageWrapper.GetDataAsync(pickedFile);
}
}
private void UpdateUI(long lineCount)
{
// This time check prevents the UI from updating so frequently
// that it becomes unresponsive as a result.
DateTime now = DateTime.Now;
if ((now - this.LastUpdate).Milliseconds > 3000)
{
// This updates a textblock to display the count, but could also
// update a progress bar or progress ring in here.
this.MessageTextBlock.Text = "Count: " + lineCount;
this.LastUpdate = now;
}
}
}
Inside of the MyStorageWrapper class:
public static class MyStorageWrapper
{
public delegate void MyEventHandler(long lineCount);
public static event MyEventHandler MyEvent;
private static void RaiseMyEvent(long lineCount)
{
// Ensure that something is listening to the event.
if (MyStorageWrapper.MyEvent!= null)
{
// Call the listening event handlers.
MyStorageWrapper.MyEvent(lineCount);
}
}
public static async Task<List<DataRecord>> GetDataAsync(StorageFile file)
{
List<DataRecord> recordsList = new List<DataRecord>();
using (Stream stream = await file.OpenStreamForReadAsync())
{
using (StreamReader reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
// Does its parsing here, and constructs a single DataRecord …
recordsList.Add(dataRecord);
// Raises an event.
MyStorageWrapper.RaiseMyEvent(recordsList.Count);
}
}
}
return recordsList;
}
}
The code for the time check I got from following this.
As written, this code makes the app unresponsive with a large file (I tested on a text file on the order of about 8.5 million lines). I thought adding async and await to the GetDataAsync() call would prevent this? Does this not do its work on a thread aside from the UI thread? Through Debug mode in Visual Studio, I have verified the program is progressing as expected... it is just tying up the UI thread, making the app unresponsive (see this page from Microsoft about the UI thread and asynchronous programming).
PART 2
I have successfully implemented before an asynchronous, long-running process that runs on a separate thread AND still updates the UI periodically... but this solution does not allow for the return value - specifically the line from PART 1 that says:
this.DataRecords = await MyStorageWrapper.GetDataAsync(pickedFile);
My previous, successful implementation follows (most of the bodies cut out for brevity). Is there a way to adapt this to allow for return values?
In a Page class:
public sealed partial class MyPage : Page
{
public Generator MyGenerator { get; set; }
public MyPage()
{
this.InitializeComponent();
this.MyGenerator = new Generator();
}
private void StartButton_Click(object sender, RoutedEventArgs e)
{
this.MyGenerator.ProgressUpdate += async (s, f) => await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, delegate ()
{
// Updates UI elements on the page from here.
}
this.MyGenerator.Start();
}
private void StopButton_Click(object sender, RoutedEventArgs e)
{
this.MyGenerator.Stop();
}
}
And in the Generator class:
public class Generator
{
private CancellationTokenSource cancellationTokenSource;
public event EventHandler<GeneratorStatus> ProgressUpdate;
public Generator()
{
this.cancellationTokenSource = new CancellationTokenSource();
}
public void Start()
{
Task task = Task.Run(() =>
{
while(true)
{
// Throw an Operation Cancelled exception if the task is cancelled.
this.cancellationTokenSource.Token.ThrowIfCancellationRequested();
// Does stuff here.
// Finally raise the event (assume that 'args' is the correct args and datatypes).
this.ProgressUpdate.Raise(this, new GeneratorStatus(args));
}
}, this.cancellationTokenSource.Token);
}
public void Stop()
{
this.cancellationTokenSource.Cancel();
}
}
Finally, there are two supporting classes for the ProgressUpdate event:
public class GeneratorStatus : EventArgs
{
// This class can contain a handful of properties; only one shown.
public int number { get; private set; }
public GeneratorStatus(int n)
{
this.number = n;
}
}
static class EventExtensions
{
public static void Raise(this EventHandler<GeneratorStatus> theEvent, object sender, GeneratorStatus args)
{
theEvent?.Invoke(sender, args);
}
}
It is key to understand that async/await does not directly say the awaited code will run on a different thread. When you do await GetDataAsync(pickedFile); the execution enters the GetDataAsync method still on the UI thread and continues there until await file.OpenStreamForReadAsync() is reached - and this is the only operation that will actually run asynchronously on a different thread (as file.OpenStreamForReadAsync is actually implemented this way).
However, once OpenStreamForReadAsync is completed (which will be really quick), await makes sure the execution returns to the same thread it started on - which means UI thread. So the actual expensive part of your code (reading the file in while) runs on UI thread.
You could marginally improve this by using reader.ReadLineAsync, but still, you will be returning to UI thread after each await.
ConfigureAwait(false)
The first trick you want to introduce to resolve this problem is ConfigureAwait(false).
Calling this on an asynchronous call tells the runtime that the execution does not have to return to the thread that originally called the asynchronous method - hence this can avoid returning execution to the UI thread. Great place to put it in your case is OpenStreamForReadAsync and ReadLineAsync calls:
public static async Task<List<DataRecord>> GetDataAsync(StorageFile file)
{
List<DataRecord> recordsList = new List<DataRecord>();
using (Stream stream = await file.OpenStreamForReadAsync().ConfigureAwait(false))
{
using (StreamReader reader = new StreamReader(stream))
{
while (!reader.EndOfStream)
{
string line = await reader.ReadLineAsync().ConfigureAwait(false);
// Does its parsing here, and constructs a single DataRecord …
recordsList.Add(dataRecord);
// Raises an event.
MyStorageWrapper.RaiseMyEvent(recordsList.Count);
}
}
}
return recordsList;
}
Dispatcher
Now you freed up your UI thread, but introduced yet another problem with the progress reporting. Because now MyStorageWrapper.RaiseMyEvent(recordsList.Count) runs on a different thread, you cannot update the UI in the UpdateUI method directly, as accessing UI elements from non-UI thread throws synchronization exception. Instead, you must use UI thread Dispatcher to make sure the code runs on the right thread.
In the constructor get reference to the UI thread Dispatcher:
private CoreDispatcher _dispatcher;
public MyPage()
{
this.InitializeComponent();
_dispatcher = Window.Current.Dispatcher;
...
}
Reason to do it ahead is that Window.Current is again accessible only from the UI thread, but the page constructor definitely runs there, so it is the ideal place to use.
Now rewrite UpdateUI as follows
private async void UpdateUI(long lineCount)
{
await _dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
// This time check prevents the UI from updating so frequently
// that it becomes unresponsive as a result.
DateTime now = DateTime.Now;
if ((now - this.LastUpdate).Milliseconds > 3000)
{
// This updates a textblock to display the count, but could also
// update a progress bar or progress ring in here.
this.MessageTextBlock.Text = "Count: " + lineCount;
this.LastUpdate = now;
}
});
}
In an effort to learn c#, I'm writing an application that will continuously monitor UDP traffic on a particular port and update a WPF UI text block with received packet information. The following code works (UDP handler class instance d instantiated elsewhere in scope):
public MainWindow()
{
InitializeComponent();
Task.Run(async () =>
{
using (d.receiveClient)
{
while (true)
{
var receivedResults = await d.receiveClient.ReceiveAsync();
byte[] buffer = receivedResults.Buffer;
Console.Write("Receiving Data: ");
Console.WriteLine(buffer[0].ToString());
Dispatcher.BeginInvoke(new Action(delegate
{
MyTextBlock.Text = "Rx Data: " + buffer[0].ToString();
}));
}
}
});
}
While it works, it's certainly doesn't feel idiomatic or correct. I'd like to create a Task<byte[]> that contains the async receive logic in the class that currently contains receiveClient. Problem is it doesn't execute continuously; the task will execute once, then exit. I've tried restarting the task in .ContinueWith(), etc, and while the Task can be restarted, I seem to loose the hooks into the UI. What's the best way to accomplish an event driven, continuous receive that in turn updates WPF UI components in native c# (I'd rather not use WinPcap or its .Net equivalent)?
Rather than try to stick with an always running Task/Thread and passing messages back to the main application, I ultimately opted to use the BeginReceive() and EndReceive() methods with a custom event for handling data parsing. Essentially something like the following (distilled to essentials):
public void Listen()
{
receiveClient.BeginReceive(new AsyncCallback(ProcessIncoming), null);
}
private void ProcessIncoming(IAsyncResult res)
{
byte[] rec_bytes = receiveClient.EndReceive(res, ref rec_ep);
receiveClient.BeginReceive(new AsyncCallback(ProcessIncoming), null);
PacketReceivedEventArgs args = new PacketReceivedEventArgs();
args.IP = rec_ep.Address;
args.Port = rec_ep.Port;
args.Data = rec_bytes;
OnPacketReceived(args);
}
protected virtual void OnPacketReceived(PacketReceivedEventArgs e)
{
EventHandler<PacketReceivedEventArgs> handler = PacketReceived;
if (handler != null)
{
handler(this, e);
}
}
public event EventHandler<PacketReceivedEventArgs> PacketReceived;
public class PacketReceivedEventArgs : EventArgs
{
public byte[] Data { get; set; }
public IPAddress IP { get; set; }
public int Port { get; set; }
}
In the main app, connecting, listening, and packet handling becomes (where d is an instance of the class implementing the above methods):
d.Connect(someIPString, portInt);
d.PacketReceived += _SomeHandler;
d.Listen();
I come from an embedded C background and I am working on my first C# application and I have hit a wall on this and my research is not panning out so I thought I would ask here.
Simple app, so far. I have a MainWindow that, among a bunch of other stuff, starts a TCPClient thread on a button click:
public partial class MainWindow : Window
{
....
TCPConnection myCon = new TCPConnection();
....
private void connectButton_Click(object sender, RoutedEventArgs e)
{
networkListBox.Items.Add("Connecting...");
myCon.Connect("localhost", updateNetworkListBox);
}
}
....
public void updateNetworkListBox(string message)
{
networkListBox.Items.Add(message);
}
And in TCPConnection.cs:
public class TCPConnection
{
....
public void Connect(string server, ReportDelegate reportDelegate)
{
this.server = server;
clientThread = new Thread(() => Client(this.server));
clientThread.Start();
reportDelegate("Started client thread...");
}
static void Client(string server)
{
try
{
Int32 port = 25565;
TcpClient client = new TcpClient(server, port);
Byte[] outgoingBytes = new Byte[1024];
string outgoingString = "Hello! I am " + Guid.NewGuid();
outgoingBytes = System.Text.Encoding.ASCII.GetBytes(outgoingString);
NetworkStream stream = client.GetStream();
stream.Write(outgoingBytes, 0, outgoingBytes.Length);
stream.Close();
client.Close();
}
The first thing I would like to do, now that TCP connection works is send a message back to the UI such as "Client thread connecting...", "Client thread connected..." and have it show up in the networkListbox.
Within the Connect() method, I was able to do this by using the delegate but this obviously will not work in the new thread since one is not able to directly access UI controls from another thread.
I have read loads of articles on this and I know that I probably want to use the Dispatcher to to do this. However, almost all of the examples I have seen have created a new thread within the current class and, for example, passed an anonymous method to Dispatcher.Invoke().
One exception to this discussion which advocated using an EventHandler and initializing it in the main window. That seems less than ideal but maybe I am wrong.
Further down, someone else advocated data sharing. Again, that seems less than ideal to me.
Other articles I have read appear to be out of date.
So, I welcome any explanations on how to go about this. It may be that I am just getting hung up syntactically but I suspect that, although I think I am mostly clear on delegates, lambdas, etc., I am probably hung up on what exactly needs to get done.
If you can show how it would be done in this specific example with some explanation, I would greatly appreciate it.
And maybe some specific questions on some points that are a little hazy for me:
1) Can my worker task access on it on its own or must it be provided with the UI's Dispatcher?
2) Should the UI provide a delegate that performs the dispatch or should the dispatch be coded in the worker task, referencing the UI Dispatcher?
Thanks very much.
For your question about providing a sample, if there is a worker class like...
public class Worker
{
public Worker(Action<string>action)
{
Task.Run(() =>
{
int i = 0;
while (true)
{
++i;
Task.Run(() => { action("Current value " + i); });
Task.Run(() =>
{
// doing some work here
});
Thread.Sleep(1000);
}
});
}
}
...which is performing background work on different threads and advising the caller via the delegate. The delegate is a plain vanilla Action that takes a string. Then the View Model should be implemented such that it does not care on which thread the message originated. Here's the corresponding code in the VM...
private readonly SynchronizationContext _context = SynchronizationContext.Current;
private void StartWorker()
{
Worker w = new Worker((s) => _context.Post(delegate { StatusText = s; }, null));
}
This code uses a SynchronizationContext, but could just as easily use a dispatcher. The point being that the responsibility for sync'ing up on the UI thread doesn't belong to a worker. The worker shouldn't care, and similarly the VM is thread-agnostic and posts everything via its SynchronizationContext.
The code for the StatusText property looks like this...
private string _statusText;
public string StatusText
{
[DebuggerStepThrough]
get { return _statusText; }
[DebuggerStepThrough]
set
{
if (value != _statusText)
{
_statusText = value;
OnPropertyChanged("StatusText");
}
}
}
And finally, on the UI, it is presented like this...
<StatusBar DockPanel.Dock="Bottom">
<TextBlock Text="{Binding StatusText}"/>
</StatusBar>
...
So to recap your questions: the worker threads can access it, but they should not have to deal with sync'ing up the UI. That responsibility is the VM's. And VM should be thread-agnostic and sync the UI through the dispatcher or synchronization context or other methods.
Scheduling through the Dispatcher is appropriate if you are manipulating a collection that is the subject of a binding (e.g., an ObservableCollection); otherwise SynchronizationContext is appropriate (it's a bit more light-weight).
just add the delegate and pass a reference to your main form
public partial class MainWindow : Window
{
TCPConnection myCon = new TCPConnection();
private void connectButton_Click(object sender, RoutedEventArgs e)
{
networkListBox.Items.Add("Connecting...");
myCon.Connect("localhost", updateNetworkListBox);
}
public delegate void updateNetworkListBoxDelegate(string message);
public void updateNetworkListBox(string message)
{
if(this.invokeRequired())
{
this.invoke(new updateNetworkListBoxDelegate(updateNetworkListBox), message);
}
else
{
networkListBox.Items.Add(message);
}
}
}
in TCPConnection add a constructor that takes a MainWindow instance
public class TCPConnection
{
//add member to hold instance
private _mainWindow;
//add constructor taking instance
public TCPConnection(MainWindow mw)
{
_mainWindow = mw;
}
public void Connect(string server, ReportDelegate reportDelegate)
{
this.server = server;
clientThread = new Thread(() => Client(this.server));
clientThread.Start();
//reportDelegate("Started client thread...");
//call the method on the UI thread
_mainWindow.updateNetworkListBox("Started client thread...");
}
static void Client(string server)
{
try
{
Int32 port = 25565;
TcpClient client = new TcpClient(server, port);
Byte[] outgoingBytes = new Byte[1024];
string outgoingString = "Hello! I am " + Guid.NewGuid();
outgoingBytes = System.Text.Encoding.ASCII.GetBytes(outgoingString);
NetworkStream stream = client.GetStream();
stream.Write(outgoingBytes, 0, outgoingBytes.Length);
stream.Close();
client.Close();
//call the method ont he ui thread
_mainWindow.updateNetworkListBox("DONE!!")
}
}
}
I've searched and can't find a solution that helps me get text from a thread running in a separate class, back to a listbox on the form that created the thread.
Basically I have a class that holds a "test", it is called in it's own thread from a test window. What I want to be able to do is add text to a listbox on the main form to let the user know what is going on with a test. All the examples I can find on Invoke show how to do it within the same class.
Where I start the thread:
PermeabilityTest Run_Test = new PermeabilityTest();
public Thread WorkerThread;
private void button2_Click(object sender, EventArgs e)
{
//enable timer for test duration display
timer1.Enabled = true;
//create and start new thread.
WorkerThread = new Thread(Run_Test.RunTest);
WorkerThread.Start();
}
Here is my class that actually does the work, where I need to get text back to a listbox on a separate form from.
public class PermeabilityTest
{
//volatile alerts the compiler that it will be used across threads.
private volatile bool aborted;
public void RequestStop()
{
//handle saving data file here as well.
aborted = true;
}
public void RunTest()
{
//reference the comms class so we can communicate with the machine
PMI_Software.COMMS COM = new COMMS();
//some test stuffs here
int x = 0;
while( x < 100 && !aborted)
{
System.Diagnostics.Debug.Write("Well here it is, running it's own thread." + Environment.NewLine);
COM.Pause(1);
}
}
}
I would appreciate any one who could help me understand how to get some text back to a listbox on the same form that has the button which starts the thread.
Option 1: (Preffered) Add an event on PermeabilityTest and register on that event in your main form.
Then modify the content of your List box from within your main form.
Example:
Your main form:
PermeabilityTest Run_Test = new PermeabilityTest();
public Thread WorkerThread;
public form1()
{
// Register on the Progress event
Run_Test.Progress += Run_Test_Progress;
}
void Run_Test_Progress(string message)
{
if(listBox.InvokeRequired)
{
// Running on a different thread than the one created the control
Delegate d = new ProgressEventHandler(Run_Test_Progress);
listBox.Invoke(d, message);
}
else
{
// Running on the same thread which created the control
listBox.Items.Add(message);
}
}
private void button2_Click(object sender, EventArgs e)
{
//enable timer for test duration display
timer1.Enabled = true;
//create and start new thread.
WorkerThread = new Thread(Run_Test.RunTest);
WorkerThread.Start();
}
new Delegate:
public delegate void ProgressEventHandler(string message);
Modified PermeabilityTest class:
public class PermeabilityTest
{
//volatile alerts the compiler that it will be used across threads.
private volatile bool aborted;
public event ProgressEventHandler Progress;
public void RequestStop()
{
//handle saving data file here as well.
aborted = true;
}
public void RunTest()
{
//reference the comms class so we can communicate with the machine
PMI_Software.COMMS COM = new COMMS();
//some test stuffs here
int x = 0;
while (x < 100 && !aborted)
{
// Report on progress
if(Progress != null)
{
Progress("This message will appear in ListBox");
}
System.Diagnostics.Debug.Write("Well here it is, running it's own thread." + Environment.NewLine);
COM.Pause(1);
}
}
}
Option 2:
You could make PermeabilityTest an inner class of your main form, and by doing so, allow it to access private members of your main form.
Then you need to pass a reference of your main form to the constructor of PermeabilityTest and keep it as a member.
Option 3:
pass your list box to the constructor of PermeabilityTest
Don't forget to use Invoke on your control since you are running from a different thread.