I asked in a previous question how to "Threading 2 forms to use simultaneously C#".
I realize now that I was not explicit enough and was asking the wrong question.
Here is my scenario:
I have some data, that I receive from a local server, that I need to write to a file.
This data is being sent at a constant time rate that I cant control.
What I would like to do is to have one winform for the initial setup of the tcp stream and then click on a button to start reading the tcp stream and write it to a file, and at the same time launch another winform with multiple check-boxes that I need to check the checked state and add that info simultaneously to the same file.
This processing is to be stopped when a different button is pressed, closing the stream, the file and the second winform. (this button location is not specifically mandatory to any of the winforms).
Because of this cancel button (and before I tried to implement the 2nd form) I used a background worker to be able to asynchronously cancel the do while loop used to read the stream and write the file.
private void bRecord_Click(object sender, EventArgs e)
{
System.IO.StreamWriter file = new System.IO.StreamWriter(AppDomain.CurrentDomain.BaseDirectory + DateTime.Now.ToString("yyyy-dd-M--HH-mm-ss") + ".xml", true);
data_feed = client.GetStream();
data_write = new StreamWriter(data_feed);
data_write.Write("<SEND_DATA/>\r\n");
data_write.Flush();
exit_state = false;
string behavior = null;
//code to launch form2 with the checkboxes
//...
worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.DoWork += new DoWorkEventHandler((state, args) =>
{
do
{
int var = data_feed.ReadByte();
if (var != -1)
{
data_in += (char)var;
if (data_in.IndexOf("\r\n") != -1)
{
//code to check the checkboxes state in form2
//if (form2.checkBox1.Checked) behavior = form2.checkBox1.Text;
//if (form2.checkBoxn.Checked) behavior = form2.checkBoxn.Text;
file.WriteLine(data_in + behavior);
data_in = "";
}
}
}
while (exit_state == false);
});
worker.RunWorkerAsync();
}
private void bStop_Click(object sender, EventArgs e)
{
exit_state = true;
worker.CancelAsync();
}
I hope I've been clearer now.
I not experienced in event programming and just started in C# so please try to provide some simple examples in the answers if possible.
At first would it be enough to use one Winform? Disable all checkboxes, click a button which enables the checkboxes and start reading the tcpstream? If you need two Forms for other reasons let me know, but i think this isn't needed from what i can see in your question.
Then i would suggest you to use the Task Library from .Net. This is the "modern" way to handle multithreading. BackgroundWorker is kind of old school. If you just able to run on .Net 2.0 you have to use BackgroundWorker, but don't seem to be the case (example follows).
Further if you want to cancel a BackgroundWorker operation this isn't only call CancelAsync();. You also need to handle the e.Cancelled flag.
backgroundWorker.WorkerSupportsCancellation = true;
private void CancelBW()
{
backgroundWorker.CancelAsync();
}
private void backgroundWorker_DoWork += ((sender, args)
{
//Handle the cancellation (in your case do this in your loop for sure)
if (e.Cancelled) //Flag is true if someone call backgroundWorker.CancelAsync();
return;
//Do your stuff.
});
There is no common way to directly cancel the backgroundWorker
operation. You always need to handle this.
Now let's change your code to the modern TAP-Pattern and make some stuff you want to have.
private void MyForm : Form
{
private CancellationTokenSource ct;
public MyForm()
{
InitializeComponent();
checkbox1.Enable = false;
//Disable all checkboxes here.
ct = new CancellationTokenSource();
}
//Event if someone click your start button
private void buttonStart_Click(object sender, EventArgs e)
{
//Enable all checkboxes here
//This will be called if we get some progress from tcp
var progress = new Progress<string>(value =>
{
//check the behaviour of the checkboxes and write to file
file.WriteLine(value + behavior);
});
Task.Factory.StartNew(() => ListenToTcp(ct, progress as IProgress<string)); //starts the tcp listening async
}
//Event if someone click your stop button
private void buttonStop_Click(object sender, EventArgs e)
{
ct.Cancel();
//Disable all checkboxes (better make a method for this :D)
}
private void ListenToTcp(CancellationToken ct, IProgess<string> progress)
{
do
{
if (ct.IsCancellationRequested)
return;
int temp = data_feed.ReadByte(); //replaced var => temp because var is keyword
if (temp != -1)
{
data_in += (char)temp;
if (data_in.IndexOf("\r\n") != -1)
{
if (progress != null)
progress.Report(data_in); //Report the tcp-data to form thread
data_in = string.empty;
}
}
while (exit_state == false);
}
}
This snippet should do the trick. I don't test it so some syntax error maybe occur :P, but the principle will work.
The most important part is that you are not allowed to access gui
components in another thread then gui thread. You tried to access the
checkboxes within your BackgroundWorker DoWork which is no possible
and throw an exception.
So I use a Progress-Object to reuse the data we get in the Tcp-Stream, back to the Main-Thread. There we can access the checkboxes, build our string and write it to the file. More about BackgroundWorker vs. Task and the Progress behaviour you can find here.
Let me know if you have any further questions.
Related
When I run a WinForm program to a line, I would like to check if a textbox already has user input, if not, I will ask user to type in the textbox and wait till user types in some input, before running the next line of the code. I was wondering how to do the wait?
The program has to wait for the information required as input for the next line of code.
Thanks.
Waiting for something to happen in the GUI (using a timer, loops from other threads, etc...) is a massive waste of resources. Almost all functional programming languages have Events including C#
From Wikipedia:
event-driven programming is a programming paradigm in which the flow
of the program is determined by events such as user actions (mouse
clicks, key presses), sensor outputs, or message passing from other
programs or threads. Event-driven programming is the dominant paradigm
used in graphical user interfaces and other applications (e.g.,
JavaScript web applications) that are centered on performing certain
actions in response to user input. This is also true of programming
for device drivers (e.g., P in USB device driver stacks).
You can do it like this with the help of Control.TextChanged event inherited by the Textbox control:
private void Form1_Load(object sender, EventArgs e)
{
ValidateGUI();
}
private const int MIN_CHARS_TO_DO_SOMETHING = 8;
private const string NOT_VALID = "Oh No There is No User Input )-:";
private const string VALID = "Great We Can Do Something (-:";
private void textBox1_TextChanged(object sender, EventArgs e)
{
ValidateGUI();
}
private void ValidateGUI()
{
if (textBox1.Text.Length < MIN_CHARS_TO_DO_SOMETHING)
{
lblMessege.Text = NOT_VALID;
}
else
{
lblMessege.Text = VALID;
// Execute some code..
//...
//...
}
}
I'm going to assume you have a valid reason for waiting instead of monitoring input.
You just need to use background workers and then you need to set the DoWork event to wait for a specified amount of time, and the RunWorkerCompleted event to run your code checking if input is being made.
Here's an example assuming a label and a textbox are on the form already. Alternatively you can just add the background worker as a form element instead of creating it in code:
public Form1()
{
InitializeComponent();
waitForInput();
}
private void waitForInput()
{
BackgroundWorker waiter = new BackgroundWorker();
waiter.WorkerSupportsCancellation = true;
waiter.WorkerReportsProgress = true;
waiter.DoWork += wait10Seconds;
waiter.RunWorkerCompleted += doneWaiting;
waiter.RunWorkerAsync();
}
private void wait10Seconds(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(10000);
}
private void doneWaiting(object sender, RunWorkerCompletedEventArgs e)
{
if(textBox1.Text == "")
{
label1.Text = "Why haven't you typed anything?";
}
}
If I understand what you're getting at, a synchronization object like SemaphoreSlim might be a good fit for something like this. This declaration sets the initial count to 0 so the semaphore will block. The initSync method pauses halfway through and will await the textbox Enter key to release the semaphoreSlim before executing the next line. However, the UI thread is not blocked during the waiting period.
SemaphoreSlim _waitForText = new SemaphoreSlim(0, maxCount: 1);
private async Task initAsync()
{
richTextBox1.AppendText(
$"The async method that populates this RichTextBox waits indefinitely for input.");
richTextBox1.AppendText($"{Environment.NewLine}>");;
richTextBox1.SelectionColor = Color.Red;
// "check if a textbox already has user input"
if (string.IsNullOrWhiteSpace(textBox1.Text))
{
// "ask user to type"
textBox1.Text = "Enter ID";
await _waitForText.WaitAsync();
}
else onUserInputOK();
// The MOCK login has completed. Enable the app.
richTextBox1.Enabled = true;
richTextBox1.AppendText(
$"{Environment.NewLine}Now this method will complete, and you'll see a message box in 5 seconds");
}
Example
public MainForm() => InitializeComponent();
protected override async void OnLoad(EventArgs e)
{
base.OnLoad(e);
// Disable UI response until "logged in"
richTextBox1.Enabled = false;
// Subscribe to TextChanged event
textBox1.KeyDown += detectUserInput;
await initAsync();
await Task.Delay(TimeSpan.FromSeconds(5));
MessageBox.Show("All done");
}
private void detectUserInput(object sender, KeyEventArgs e)
{
if (e.KeyData == Keys.Return)
{
e.Handled = e.SuppressKeyPress = true;
if (!string.IsNullOrWhiteSpace(textBox1.Text))
{
onUserInputOK();
}
}
}
private void onUserInputOK()
{
richTextBox1.AppendText($"{textBox1.Text}");
Text = textBox1.Text; // Start echo to title bar
richTextBox1.SelectionColor = Color.DarkGreen;
// Remove this listener. Install normal runtime hook.
textBox1.KeyDown -= detectUserInput;
textBox1.TextChanged += normalTextboxListener;
_waitForText.Release();
}
private void normalTextboxListener(object sender, EventArgs e) => Text = textBox1.Text;
My program works like this:
I press a radio button which opens the port.
Next i press a button "Read" which starts a thread that reads data continously from the Serial Port using port.ReadLine() and prints it in a textbox;
I have another radio which should first join the thread and after that close the port;the problem is the printing goes well until i close the port when the UI freezes.
public Form1()
{
mythread = new Thread(ReadFct);
myPort = new SerialPort("COM3", 9600);
myPort.ReadTimeout = 3500;
InitializeComponent();
foreach (var t in Constants.ComboParameters)
this.paramCombo.Items.Add(t);
radioClose.CheckedChanged += new EventHandler(radioButtonCheckedChanged);
radioOpen.CheckedChanged += new EventHandler(radioButtonCheckedChanged);
}
Below is the function attached to the thread
void ReadFct()
{
string aux = "";
while (readCondition)
{
if (myPort.IsOpen)
aux = myPort.ReadLine();
this.SetText(aux);
}
}
Below is the radio button event handler
public void radioButtonCheckedChanged(object sender,EventArgs e)
{
if (radioOpen.Checked && !myPort.IsOpen)
try
{
myPort.Open();
mythread.Start();
}
catch (Exception)
{
MessageBox.Show("Nu s-a putut deschide port-ul");
}
if (radioClose.Checked && myPort.IsOpen)
{
readCondition = false;
mythread.Join();
myPort.Close();
// myPort.DataReceived -= DataReceivedHandler;
}
}
The read button function:
private void readbtn_Click(object sender, EventArgs e)
{
if (!myPort.IsOpen)
MessageBox.Show("PORT NOT OPENED!");
else
{
// myPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
readCondition = true;
if (!mythread.IsAlive)
{
mythread = new Thread(ReadFct);
mythread.Start();
}
}
I have used what MSDN suggest when changing control from another thread:
private void SetText(string text)
{
if (this.textBox1.InvokeRequired)
{
StringTb del = new StringTb(SetText);
this.Invoke(del, new object[] { text });
}
else
SetData = text;
}
It's hard to know exactly what you need, lacking a good Minimal, Complete, and Verifiable code example to illustrate the question. That said, the issue here is that the Thread.Join() method causes that thread to stop doing any other work, and the thread you use to call that method is the thread that handles all of the user interface. Worse, if your port never receives another newline, the thread you're waiting on will never terminate, because you're stuck waiting on the ReadLine() method. Even worse, even if you do get a newline, if that happens while you're stuck waiting on the Thread.Join(), the call to Invoke() will deadlock, because it needs the UI thread to do its work, and the Thread.Join() call is preventing it from getting the UI thread.
In other words, your code has multiple problems, any one of which could cause problems, but all of which together mean it just can't possibly work.
There are a variety of strategies to fix this, but IMHO the best is to use await. The first step in doing that is to change your I/O handling so that it's done asynchronously instead of dedicating a thread to it:
// Ideally, you should rename this method to "ReadFctAsync". I am leaving
// all names intact for the same of the example though.
async Task ReadFct()
{
string aux = "";
using (StreamReader reader = new StreamReader(myPort.BaseStream))
{
while (true)
{
aux = await reader.ReadLineAsync();
// This will automatically work, because the "await" will automatically
// resume the method execution in the UI thread where you need it.
this.SetText(aux);
}
}
}
Then, instead of creating a thread explicitly, just create a Task object by calling the above:
public Form1()
{
// In this approach, you can get rid of the "mythread" field altogether
myPort = new SerialPort("COM3", 9600);
myPort.ReadTimeout = 3500;
InitializeComponent();
foreach (var t in Constants.ComboParameters)
this.paramCombo.Items.Add(t);
radioClose.CheckedChanged += new EventHandler(radioButtonCheckedChanged);
radioOpen.CheckedChanged += new EventHandler(radioButtonCheckedChanged);
}
public async void radioButtonCheckedChanged(object sender,EventArgs e)
{
if (radioOpen.Checked && !myPort.IsOpen)
{
try
{
myPort.Open();
await ReadFct();
// Execution of this method will resume after the ReadFct() task
// has completed. Which it will do only on throwing an exception.
// This code doesn't have any continuation after the "await", except
// to handle that exception.
}
catch (Exception)
{
// This block will catch the exception thrown when the port is
// closed. NOTE: you should not catch "Exception". Figure out what
// *specific* exceptions you expect to happen and which you can
// handle gracefully. Any other exception can mean big trouble,
// and doing anything other than logging and terminating the process
// can lead to data corruption or other undesirable behavior from
// the program.
MessageBox.Show("Nu s-a putut deschide port-ul");
}
// Return here. We don't want the rest of the code executing after the
// continuation, because the radio button state might have changed
// by then, and we really only want this call to do work for the button
// that was selected when the method was first called. Note that it
// is probably even better if you just break this into two different
// event handlers, one for each button that might be checked.
return;
}
if (radioClose.Checked && myPort.IsOpen)
{
// Closing the port should cause `ReadLineAsync()` to throw an
// exception, which will terminate the read loop and the ReadFct()
// task
myPort.Close();
}
}
In the above, I have completely ignored the readbtn_Click() method. Lacking a good MCVE, it's not clear what role that button plays in the overall scheme. You seem to have a radio button group (of two buttons) that control whether the port is open or closed. It is not clear why then you have an additional regular button that is seemingly able to also open the port and start reading, independently of the radio group.
If you want that extra button, it seems to me that all it ought to do is change the radio group state, by checking the "open" radio button. Then let the radio group buttons handle the port state and reading. If you need more specific advice as to how to fully integrate my code example above with your entire UI, you will need to provide more detail, preferably in a new question. That new question must include a good MCVE.
I'm new to using event handlers and backgroundworkers, so I may be missing something completely obvious here. Still, I've been trying to fix this for two days, so I thought I might as well see what anyone had to say.
I have a backgroundworker called SqlExpressDownloader. It starts running at the beginning of my program, the rest of the work runs, and then it should wait for the operations in the SqlExpressDownloader_DoWork() method to complete before continuing. The only problem is that for some reason whenever I do while(SqlExpressDownloader.IsBusy), it always responds as busy and therefore will wait forever.
The code for the event handler is here:
private void SqlExpressDownloader_DoWork(object sender, DoWorkEventArgs e)
{
string sSource = string.Format("{0}\\{1}", Paths.Settings_Common, "sqlexpr_x64_enu.exe");
Debug.WriteLine(sSource);
Debug.WriteLine("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe");
if (!System.IO.File.Exists(sSource))
{
WebClient oWebClient = new WebClient();
oWebClient.DownloadProgressChanged += DownloadProgressChanged;
oWebClient.DownloadDataCompleted += DownloadComplete;
oWebClient.DownloadFileAsync(new System.Uri("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe"), sSource);
while (oWebClient.IsBusy)
{
Thread.Sleep(100);
}
e.Result = "";
DownloadFinished = true;
}
}
I have watched the code and have watched it complete this method. I even added a return after the DownloadFinished = true, but it still responds as busy. What I want to know is how to make the backgroundworker respond as not busy.
EDIT
The events are all added in the constructor as shown here:
SqlExpressDownloader = new BackgroundWorker();
SqlExpressDownloader.DoWork += new DoWorkEventHandler(this.SqlExpressDownloader_DoWork);
SqlExpressDownloader.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.SqlExpressDownloader_RunWorkerCompleted);
The RunWorkerCompleteEventHandler looks like this:
private void SqlExpressDownloader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
Debug.WriteLine("The actions are complete.");
}
else
{
Debug.WriteLine("Error in completed work.");
}
}
But, when I debugged it last, it didn't actually trigger.
Instead of querying SqlExpressDownloader.IsBusy in a loop, try subscribing to the RunWorkerCompleted event of the BackgroundWorker and place your code in there that should only occur after the DoWork event has completed.
You'll also have access to the RunWorkerCompletedEventArgs, which you can check to make sure no error was thrown from the DoWork portion of your BackgroundWorker.
...
...
SqlExpressDownloader.RunWorkerCompleted += SqlExpressDownloader_RunWorkerCompleted;
SqlExpressDownloader.RunWorkerAsync();
}
private void SqlExpressDownloader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
// do something in response to the error
}
// stuff to do after DoWork has completed
}
I found Joe Albahari's tutorial helpful when I was learning how to use these.
You can replace your code with more elegant async/await solution like this
private async Task SqlExpressDownloadAsync()
{
string sSource = string.Format("{0}\\{1}", Paths.Settings_Common, "sqlexpr_x64_enu.exe");
Debug.WriteLine(sSource);
Debug.WriteLine("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe");
if (!System.IO.File.Exists(sSource))
{
WebClient oWebClient = new WebClient();
oWebClient.DownloadProgressChanged += DownloadProgressChanged;
oWebClient.DownloadDataCompleted += DownloadComplete;
await oWebClient.DownloadFileTaskAsync(new System.Uri("http://www.elexioamp.com/Install/redistributables/sql2008r2express/sqlexpr_x64_enu.exe"), sSource);
}
}
I had a similar issue. DownloadASync would fire but .IsBusy would always stay on true.
This probably won't be a common problem, just thought I share my resolution.
I used
MessageBox.Show(new Form() { TopMost = true }, "", "")
This was the cause. I also tried:
var t = new Form() { TopMost = true };
MessageBox.Show(t, "", "");
t.Dispose();
This caused the same issue.
My code had multiple threads, I assume one of them must have gotten stuck, or perhaps the MessageBox(the new Form() { TopMost = true; } ) call created a stuck thread.
As soon as I removed that part, eg.
MessageBox.Show("", "");
Everything worked as expected again.
So maybe you are creating another thread somewhere that is causing your issue.
I have a refresh button to update news in my WP7 application. When I double or triple click on the refresh button I am getting an error
"WebClient does not support concurrent I/O operations" .
I think thats because It is sending the request triple times and making it crash. Here is my Click code.
private void NewsRefresh_Click(object sender, RoutedEventArgs e)
{
var vm = this.DataContext as MainPageViewModel;
if (vm != null)
{
vm.UpdateNews();
}
}
How can I turn it as "if It is busy cancel the process".
WebClient isn't very flexible but if you really want to use it you can make use of the IsBusy property and then cancel ongoing operation. Then, once it's cancelled you can restart it. There is important problem with synchronization. The operation which consists of checking IsBusy and invoking CancelAsync isn't atomic. Luckily DownloadStringCompleted is dispatched to the UI thread so you don't need to bother about synchronization. The snippet below shows how can you achieve it. For simplicity it's Windows Forms.
public partial class Form1 : Form
{
WebClient _WebClient;
bool _UpdateNews;
public Form1()
{
InitializeComponent();
_WebClient = new WebClient();
_WebClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(_WebClient_DownloadStringCompleted);
_UpdateNews = false;
}
void _WebClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (_UpdateNews)
{
_UpdateNews = false;
UpdateNews();
}
else if (e.Error != null)
{
// Report error
}
else
{
MessageBox.Show(e.Result);
}
}
private void button1_Click(object sender, EventArgs e)
{
if (_WebClient.IsBusy)
{
_WebClient.CancelAsync();
_UpdateNews = true;
}
else
{
UpdateNews();
}
}
private void UpdateNews()
{
_WebClient.DownloadStringAsync(new Uri("http://stackoverflow.com/questions/7084948/c-concurrent-i-o-operations-exception"));
}
}
The 'easy' way (though not bullet proof):
private void NewsRefresh_Click(object sender, RoutedEventArgs e)
{
try
{
NewsRefresh.Enabled = false;
var vm = this.DataContext as MainPageViewModel;
if (vm != null)
{
vm.UpdateNews();
}
}
finally
{
NewsRefresh.Enabled = true;
}
}
The more difficult approach would require more details on what exactly a MainPageViewModel is, and what UpdateNews() does. Basically you need to store a state value wherever you are storing the WebClient instance. Before using the WebClient you need check to see if you are already using it. The issue comes when multiple threads may operate on a single instance, or if you multiple operations (other than UpdateNews). When multiple threads are involved the easiest thing is to surround the usage of the WebClient with a Mutex.
Of course the other option is to not reuse the WebClient instance, rather create a new one for each new request.
UPDATE
Well, well, using DownloadStringAsync is certainly going to make things fun. The above code Disabling the UI will not work unless you move the re-enabling code. It would be easiest to go with my last suggestion and just create a new instance of WebClient. I'm not real fond of WebClient myself and prefer using WebRequest.Create.
I am having fun with WPF and got a problem. I have googled and found this website that has the same problem of me but without any working solution.
The problem is that I have a button that do some processing of data (around 30 sec). I want to have the button to disable and to have log writing in a text box... the problem is that it doesn't disable and it doesn't wrote any thing on the textbox until the processing is completely done.
Any idea?
private void button1_Click(object sender, RoutedEventArgs e)
{
this.button1.IsEnabled = false;
//Long stuff here
txtLog.AppendText(Environment.NewLine + "Blabla");
//End long stuff here
this.button1.IsEnabled = true;
}
As others have said, use the BackgroundWorker or some other method of doing work asychronously.
You can declare it under your Window, initialize it somewhere like the Loaded event, and use it in the Click event. Here's your method, modified to use BackgroundWorker, assuming you've declared it under the Window as _bw:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_bw = new BackgroundWorker();
_bw.DoWork += new DoWorkEventHandler((o, args) =>
{
//Long stuff here
this.Dispatcher.Invoke((Action)(() => txtLog.AppendText(Environment.NewLine + "Blabla")));
});
_bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler((o, args) =>
{
//End long stuff here
this.Dispatcher.Invoke((Action)(() => this.button1.IsEnabled = true));
});
}
private void button1_Click(object sender, RoutedEventArgs e)
{
this.button1.IsEnabled = false;
_bw.RunWorkerAsync();
}
Note that anything that modifies your UI from another thread must be done within a Dispatcher.Invoke or Dispatcher.BeginInvoke call, WPF does not allow you to get or set DependencyProperty values from any thread but the one where the object was created (more about this here).
If you wanted to read from txtLog instead of modifying it, the code would be the same:
//Long stuff here
this.Dispatcher.Invoke((Action)(() =>
{
string myLogText = txtLog.Text;
myLogText = myLogText + Environment.NewLine + "Blabla";
txtLog.Text = myLogText;
}));
That operation is being performed on the UI thread. This means that it will block the Windows message pump from processing until it has completed. no pump = no UI updates. You should launch the job on another thread. I don't know WPF, but in C# I would use either the Thread or BackgroundWorker classes.
do it async. create a backgroundworker process to handle the data and the application will continue to respond. MSDN Resources on the Class. Since WPF is using C# (or VB.net) you can still use the same types of threading objects. I've used the background worker successfully in a WPF app myself.