Cross thread problem? - c#

My error
Cross-thread operation not
valid: Control 'MailTree' accessed
from a thread other than the thread it
was created on.
with my code
My idea is when SaveMail method has finish store 1 mes then add this mes to listview.
private delegate int SaveMailDelegate(ImapX.Message mes);
public int SaveMail(ImapX.Message mess)
{
if (!File.Exists("D:\\" + Username + "\\" + MailTree.SelectedNode.Text + "\\" + mes.MessageUid.ToString() + ".eml"))
{
mess.Process();
mess.SaveAsEmlToFile("D:\\" + Username + "\\" + MailTree.SelectedNode.Text + "\\", mes.MessageUid.ToString()); //Store messages to a Location
}
// mes.MessageUid=mess.MessageUid;
return 1;
}
Mime EncodingMail(string NodeName,string focusitem)
{
Mime m = new Mime();
m=Mime.Parse("D:\\" + Username+ "\\"+NodeName+"\\"+focusitem+".eml");
return m;
}
private void AddMesToMailList()
{
ListViewItem item = new ListViewItem();
Mime m = EncodingMail(MailTree.SelectedNode.Text, mes);
item.Text = mes.MessageUid.ToString();
item.SubItems.Add(m.MainEntity.Subject);
ReturnMime(m);
if (mailfromname != null)
item.SubItems.Add(mailfromname);
else item.SubItems.Add(mailfrom);
item.SubItems.Add(m.MainEntity.Date.ToString());
item.SubItems.Add(mailfrom);
MailList.Items.Add(item);
}
private void SaveMailDone(IAsyncResult iar)
{
SaveMailDelegate del = iar.AsyncState as SaveMailDelegate;
if (del != null)
{
int result = del.EndInvoke(iar);
AddMesToMailList();
}
}
private void MailTree_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
{
MailList.Items.Clear();
for (int i = 0; i < client.Folders.Count; i++)
{
(ContextMenuListView.Items[1] as ToolStripMenuItem).DropDownItems[i].Click += new EventHandler(MainForm_Click);
}
if (MailTree.SelectedNode.Text == Username)
{
webBrowser1.Visible = false;//webBrowser1.DocumentText = "Hello Baby";
AttachmentList.Visible = false;
groupBox1.Visible = false;
}
else
{
webBrowser1.Visible = true;
groupBox1.Visible = true;
try
{
messages = client.Folders[MailTree.SelectedNode.Text].Search("ALL", false); // Search mail in your choossen Folder
AmoutOfMail = messages.Count(); //Amout of Mail in this Folder
for (int i = 0; i < AmoutOfMail; i++)
{
mes=messages[i];
SaveMailDelegate del = new SaveMailDelegate(this.SaveMail);
del.BeginInvoke(mes, new AsyncCallback(this.SaveMailDone), del);
}
}
catch (Exception)
{ }
}
}

You cannot directly access a control from another thread, you will have to invoke it.
private delegate void ControlCallback(string s);
public void CallControlMethod(string text)
{
if (control.InvokeRequired)
{
ControlCallback call = new ControlCallback((s) =>
{
// do control stuff
});
control.Invoke(call, new object[] { text });
}
else
{
// do control stuff
}
}

you can't access the UI on a different thread than what it was created on. From inside your secondary thread (the one that runs your callback handler) you will need to call Form.BeginInvoke to register a method that will be run on the UI thread. From that method you can update your UI controls

I think AddMesToMailList() is trying to modify the view elements but it is on a wrong thread.
Try something like this
void AddMesToMailList()
{
if (this.InvokeRequired)
{
this.BeginInvoke(new Action(AddMesToMailList));
return;
}
// do stuff that original AddMesToMailList() did.
}
EDIT:
SaveMail is a little complicated as it has a return value but you can try this
public int SaveMail(ImapX.Message mess)
{
if(this.InvokeRequired)
{
return (int) this.Invoke(
new Func<ImapX.Message, int>( m => SaveMail(mess)) );
}
else
{
if (!File.Exists(#"D:\" + Username + "\\" + MailTree.SelectedNode.Text + "\\" + mes.MessageUid.ToString() + ".eml"))
{
mess.Process();
mess.SaveAsEmlToFile(#"D:\" + Username + "\\" + MailTree.SelectedNode.Text + "\\", mes.MessageUid.ToString()); //Store messages to a Location
}
// mes.MessageUid=mess.MessageUid;
return 1;
}
}

Related

C# Monitoring desktop screen from a Windows service

I have just written the C# Code that is recording the screenshot of the desktop.It works on Winforms but not works in windows service.
My code as below:
public partial class ScreenCapture : ServiceBase
{
bool rec = false;
Rectangle screenSize = Screen.PrimaryScreen.Bounds;
UInt32 frameCount = 0;
VideoFileWriter writer;
int width = SystemInformation.VirtualScreen.Width;
int height = SystemInformation.VirtualScreen.Height;
AForge.Video.ScreenCaptureStream streamVideo;
Stopwatch stopWatch = new Stopwatch();
public ScreenCapture()
{
InitializeComponent();
writer = new VideoFileWriter();
if (!System.Diagnostics.EventLog.SourceExists("MySource"))
{
System.Diagnostics.EventLog.CreateEventSource("MySource", "MyLog");
}
eventLog1.Source = "MySource";
this.CanHandleSessionChangeEvent = true;
}
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
string folderName = #"C:\LoginLog";
if (changeDescription.Reason == SessionChangeReason.SessionLogon)
{
eventLog1.WriteEntry(changeDescription.SessionId + " User Logon");
if (!Directory.Exists(folderName))
{
Directory.CreateDirectory(folderName);
}
StartRec(folderName);
}
else if (changeDescription.Reason == SessionChangeReason.SessionLogoff)
{
eventLog1.WriteEntry(changeDescription.SessionId + " User Logoff");
rec = false;
}
else if (changeDescription.Reason == SessionChangeReason.SessionLock)
{
eventLog1.WriteEntry(changeDescription.SessionId + " User Lock");
rec = false;
}
else if (changeDescription.Reason == SessionChangeReason.SessionUnlock)
{
eventLog1.WriteEntry(changeDescription.SessionId + " User Unlock");
if (!Directory.Exists(folderName))
{
Directory.CreateDirectory(folderName);
}
StartRec(folderName);
}
base.OnSessionChange(changeDescription);
}
private void StartRec(string path)
{
if (rec == false)
{
rec = true;
frameCount = 0;
string time = DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ssff");
string compName = Environment.UserName;
string fullName = path + "\\" + compName.ToUpper() + "_" + time;
try
{
writer.Open(
fullName + ".mp4",
width,
height,
10,
VideoCodec.MPEG4, 1000000);
}
catch (Exception ex)
{
eventLog1.WriteEntry("Exception StartRec: " + ex.Message);
}
DoJob();
}
}
private void DoJob()
{
try
{
Rectangle screenArea = Rectangle.Empty;
foreach (System.Windows.Forms.Screen screen in
System.Windows.Forms.Screen.AllScreens)
{
screenArea = Rectangle.Union(screenArea, screen.Bounds);
}
streamVideo = new ScreenCaptureStream(screenArea);
streamVideo.NewFrame += new NewFrameEventHandler(video_NewFrame);
streamVideo.Start();
stopWatch.Start();
}
catch (Exception ex)
{
eventLog1.WriteEntry("Exception DoJob: " + ex.Message);
}
}
private void video_NewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
{
try
{
if (rec)
{
frameCount++;
writer.WriteVideoFrame(eventArgs.Frame);
}
else
{
stopWatch.Reset();
Thread.Sleep(500);
streamVideo.SignalToStop();
Thread.Sleep(500);
writer.Close();
}
}
catch (Exception ex)
{
eventLog1.WriteEntry("Exception Video New Frame: " + ex.Message);
}
}
}
And the service can save a .mp4 file, but it cannot open it.I think windows service can not capture desktop screen.
Can anybody help me how to solve this problem?
thanks in advance.
You need to set windows service run under interactive account,
To do so you need to go to properties of service got to logon tab and login by
your windows account.

Multithread using backgroundworker and event handler

I'm developing a sample program to connect multiple device using backgroundworker. Each device connected will be add to the list as new object. After finished connecting all the devices, i wanted to add an event handler for each connected devices. The problem that i'm facing now is the event handler doesn't firing at all. Below are the sample codes.
The Connect click button event :
private void btnConnect_Click(object sender, EventArgs e)
{
using (BackgroundWorker m_oWorker = new BackgroundWorker())
{
m_oWorker.DoWork += delegate (object s, DoWorkEventArgs args)
{
int iIpStart = 0;
int iIpEnd = 0;
string strIp1 = string.Empty;
string strIp2 = string.Empty;
list.Clear();
string[] sIP1 = txtIpStart.Text.Trim().ToString().Split('.');
string[] sIP2 = txtIpEnd.Text.Trim().ToString().Split('.');
iIpStart = Convert.ToInt32(sIP1[3]);
iIpEnd = Convert.ToInt32(sIP2[3]);
strIp1 = sIP1[0] + "." + sIP1[1] + "." + sIP1[2] + ".";
strIp2 = sIP2[0] + "." + sIP2[1] + "." + sIP2[2] + ".";
Ping ping = new Ping();
PingReply reply = null;
int iIncre = 0;
int iVal = (100 / (iIpEnd - iIpStart));
for (int i = iIpStart; i <= iIpEnd; i++)
{
Thread.Sleep(100);
string strIpconnect = strIp1 + i.ToString();
Console.Write("ip address : " + strIpconnect + ", status: ");
reply = ping.Send(strIpconnect);
if (reply.Status.ToString() == "Success")
{
if (ConnectDevice(strIpconnect))
{
strLastDevice = strIpconnect + " Connected";
isconnected = true;
}
else
{
isconnected = false;
}
}
else
{
isconnected = false;
}
m_oWorker.ReportProgress(iIncre);
iIncre = iIncre + iVal;
}
m_oWorker.ReportProgress(100);
};
m_oWorker.ProgressChanged += new ProgressChangedEventHandler(m_oWorker_ProgressChanged);
m_oWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_oWorker_RunWorkerCompleted);
m_oWorker.WorkerReportsProgress = true;
m_oWorker.WorkerSupportsCancellation = true;
m_oWorker.RunWorkerAsync();
}
}
ConnectDevice function method. Connected device will be added to the list :
protected bool ConnectDevice(string sIP)
{
try
{
NewSDK sdk = new NewSDK();
if (sdk.Connect() == true)
{
list.Add(new objSDK { sdk = sdk, ipaddress = sIP });
return true;
}
else
{
}
}
catch() {}
return false;
}
the Backgroundworker :
void m_oWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//If it was cancelled midway
if (e.Cancelled)
{
lblStatus.Text = "Task Cancelled.";
}
else if (e.Error != null)
{
lblStatus.Text = "Error while performing background operation.";
}
else
{
lblStatus.Text = "Task Completed...";
btnListen.Enabled = true;
}
}
void m_oWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//Here you play with the main UI thread
progressBar1.Value = e.ProgressPercentage;
lblStatus.Text = "Processing......" + progressBar1.Value.ToString() + "%";
if (isconnected)
{
listBox2.Items.Add(strLastDevice);
string[] ssplit = sDeviceInfo.Split(';');
foreach (string sword in ssplit)
{
listBox1.Items.Add(sword);
}
}
}
The function to attached event :
private void RegisterEvent()
{
foreach (objSDK obj in list)
{
obj.sdk.OnTransaction += () =>
{
listBox1.Items.Add("ip : " + obj.IP + " transaction");
};
}
}
You have declared m_oWorker as a local variable. I'm guessing this was a mistake ( the m_ prefix should only be used for class member variables)?
Also, you declared it within a using statement, meaning that it that the framework will call Dispose() on it at the end of the using block. Even if you held on to a reference to it (and I don't think you do) it still means its resources will be deallocated, which is probably why it isn't handling any events.
I try another workaround by using thread and task and work perfectly. Thanks for all response

Different behaviors when instantiated from button or timer in c#

I have a function called getMessages that can be called by a Button click (using the RelayCommand trigger) or that is called in a timer every 15s.
The desired behavior is:
webservice > deserialize answer > system notification > updatelistview > insert localDB
But when the function is called by the timer the updatelistview is not done. Why does this happen if the function is the same and works perfectly in the button command?
CODE:
// Get messages for the logged in user
public async void getMessages()
{
try
{
List<FriendGetMessage> msg = new List<FriendGetMessage>();
var response = await CommunicationWebServices.GetCHAT("users/" + au.idUser + "/get", au.token);
if (response.StatusCode == HttpStatusCode.OK) // If there are messages for me.
{
var aux = await response.Content.ReadAsStringAsync();
IEnumerable<FriendGetMessage> result = JsonConvert.DeserializeObject<IEnumerable<FriendGetMessage>>(aux);
if (result != null)
{
foreach (var m in result)
{
msg.Add(m);
}
//MsgList=msg;
foreach (var f in Friends)
{
if (f.msg == null || f.msg.Count() == 0)
{
f.msg = new ObservableCollection<Messages>();
}
foreach (var mess in msg)
{
if (mess.idUser == f.idUser)
{
Messages mm = new Messages();
mm.received = mess.message;
mm.timestamp = "Received " + mess.serverTimestamp;
mm.align = "Right";
// Add to the friend list.
f.msg.Add(mm);
// Add to Local DB
InsertMessage(null, au.idUser.ToString(), f.idUser, mess.message, mess.serverTimestamp);
var notification = new System.Windows.Forms.NotifyIcon()
{
Visible = true,
Icon = System.Drawing.SystemIcons.Information,
BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info,
BalloonTipTitle = "New Message from " + f.name,
BalloonTipText = "Message: " + mess.message,
};
// Display for 5 seconds.
notification.ShowBalloonTip(5);
// The notification should be disposed when you don't need it anymore,
// but doing so will immediately close the balloon if it's visible.
notification.Dispose();
}
}
}
counterChat = 1; // resets the counter
}
}
else {
counterChat = counterChat * 2;
}
//var sql = "select * from chat";
//var respo = GetFromDatabase(sql);
OnPropertyChanged("Friends");
}
catch (Exception e)
{
MessageBox.Show("GetMessages: " + e);
Debug.WriteLine("{0} Exception caught.", e);
}
}
CODE TIMER:
public void chatUpdate()
{
_timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
}
public void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
getMessages();
OnPropertyChanged("Friends");
incChat = 0;
}
}
ADDED - I've also tried this and didn't worked (it seems that is some kind of concurrency problem to the ObservableCollection called Friends (is a friendslist) each friend has an ObservableCollection of messages (is a chat))
public void chatUpdate()
{
_timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
}
public async void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
Application.Current.Dispatcher.Invoke((Action)async delegate { await getMessages(); });
incChat = 0;
}
}
Best regards,
I think you need to make the timer handler be an async method as follows:
public async void timerchat_Tick(object sender, EventArgs e)
{
if (counterChat != incChat)
{
incChat++;
}
else
{
await getMessages();
OnPropertyChanged("Friends");
incChat = 0;
}
}
This way OnPropertyChanged("Friends") is guaranteed to fire after the work in getMessages is done.
The methods need to change to:
DispatcherTimer _timerChat = new DispatcherTimer(DispatcherPriority.Render);
_timerChat.Interval = TimeSpan.FromSeconds(15);
_timerChat.Tick += new EventHandler(timerchat_Tick);
_timerChat.Start();
public async void timerchat_Tick(object sender, EventArgs e)
{
//...
await getMessages();
//...
}
public async Task getMessages()
{
try
{
// ... your code here
string result = await response.Content.ReadAsStringAsync();
// .... rest of your code
}
catch (Exception e)
{
MessageBox.Show("GetMessages: " + e);
}
}
It is solved. The problem was in my ViewModels I was opening multiple threads and sometimes the right one would update the UI and sometimes no.
Thanks for all the answers.

C# Received data from SerialPort is wrong after writing

I have a communication device which sends requests every two seconds through COM. Between the requests, the device waits for response. I'm building software in C# with SerialPort. I call an event handler for data receiving and I run a method in new thread with while loop which checks that the request is as expected and calls method responsible for response. The thing is, after response next received data is wrong. Here is the code:
The SerialPortManager:
class SerialPortManager : IDisposable
{
...
public void connect()
{
if (mSerialPort.IsOpen)
return;
mSerialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
try
{
mSerialPort.Open();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
mStatus = Status.DISCONNECTED;
return;
}
if (mSerialPort.IsOpen)
{
mStatus = Status.CONNECTED;
Thread tryToResponseThread = new Thread(tryToResponse);
tryToResponseThread.Start();
}
}
private void tryToResponse()
{
while (mStatus == Status.CONNECTED)
{
if (mRequest.Length >= 56)
{
string checksum = "555555555555555580808080";
if (mRequest.Length > 56)
{
mRequest.Remove(55, mRequest.Length - 56);
Debug.Print("cutting");
}
if (mRequest.ToString().StartsWith(checksum))
{
StringBuilder strToCMD = new StringBuilder();
for (int i = 0; i < mRequest.Length; i += 2)
{
strToCMD.Append(mRequest[i]);
strToCMD.Append(mRequest[i + 1]);
strToCMD.Append(" ");
}
StringBuilder address = new StringBuilder();
StringBuilder group = new StringBuilder();
address.Append(mRequest.ToString(24, 8));
group.Append(mRequest.ToString(24 + 8, 2));
mMainForm.appendCMDTextboxText(Environment.NewLine);
mMainForm.appendCMDTextboxText(DateTime.Now.ToLongTimeString() + " [RX] " + address.ToString() + " " + group.ToString() + "\t");
mMainForm.appendCMDTextboxText(strToCMD.ToString());
byte[] request = ByteArrayConverter.fromString16(mRequest.ToString());
mRequest.Clear();
response(request);
Array.Clear(request, 0, request.Length);
Debug.Print("starts with checksum");
}
else if (mRequest.ToString().Contains(checksum))
{
int indexOfChecksum = mRequest.ToString().IndexOf(checksum);
mRequest.Remove(0, indexOfChecksum);
Debug.Print("contains");
}
else
{
int index = 0;
bool found = false;
for (int i = 0; i < checksum.Length; i++)
{
StringBuilder s = new StringBuilder();
int sub = mRequest.Length - checksum.Length + i + 2;
if (sub == mRequest.Length)
break;
s.Append(mRequest.ToString().Substring((Math.Max(0, mRequest.Length - checksum.Length + i + 2))));
s.Append(mRequest.ToString(0, i + 2));
if (s.ToString().Equals(checksum))
{
index = sub;
found = true;
break;
}
}
if (found)
{
mRequest.Remove(0, index);
}
else
{
mRequest.Clear();
}
Debug.Print("on start and end");
}
}
}
}
private void response(byte[] request)
{
Luminaire lumToResponse = mLuminaireManager.getLuminaire(request);
if (lumToResponse == null)
{
return;
}
else
{
if (lumToResponse.isNotResponding())
return;
}
byte[] responseMsg = lumToResponse.getWholeFrame(request);
mMainForm.setCommandLabelForResponsingLuminaire(lumToResponse);
mMainForm.appendCMDTextboxText(Environment.NewLine + DateTime.Now.ToLongTimeString() + " [TX]\t");
string responseMsgAsString = ByteArrayConverter.toString(responseMsg).Replace("-", " ");
mMainForm.appendCMDTextboxText(responseMsgAsString);
write(responseMsg, 0, responseMsg.Length);
mSerialDataEventArgs.clearData();
}
public void write(byte[] buffer, int offset, int count)
{
if (mStatus == Status.DISCONNECTED || mSerialPort.IsOpen == false)
{
mStatus = Status.DISCONNECTED;
return;
}
mSerialPort.Write(buffer, offset, count);
}
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (mStatus == Status.DISCONNECTED)
return;
int dataLength = mSerialPort.BytesToRead;
if (dataLength == 0)
return;
byte[] data = new byte[dataLength];
mSerialPort.Read(data, 0, dataLength);
mSerialDataEventArgs.setData(data);
mDataReceived?.Invoke(this, mSerialDataEventArgs);
}
...
}
The helpser class for passing the received data:
public class SerialDataEventArgs : EventArgs
{
public SerialDataEventArgs()
{
}
public void setData(byte[] data)
{
clearData();
mData = data;
}
public SerialDataEventArgs(byte[] dataInByteArray)
{
mData = dataInByteArray;
}
public void clearData()
{
if (mData == null)
return;
Array.Clear(mData, 0, mData.Length);
}
public byte[] mData;
}
And the main class:
public partial class MainForm : Form
{
...
private void MainForm_Load(object sender, EventArgs e)
{
mSerialPortManager = new SerialPortManager();
mSerialPortManager.setPortBoudRate((int)numUpDown_SerialPortSpeed.Value);
mLuminaireManager = new LuminaireManager();
mSerialPortManager.mMainForm = this;
mSerialPortManager.mLuminaireManager = mLuminaireManager;
fixTableLayoutColumnSize(ref tl_SingleLuminaire);
fillTheRestOfSingleLuminaireGroupBoxes();
fillSerialPortComboBoxWithNamesOfAvailablePorts();
mSerialPortManager.mDataReceived += new EventHandler<SerialDataEventArgs>(serialPortManager_DataReceived);
mIsPaused = false;
}
private void serialPortManager_DataReceived(object sender, SerialDataEventArgs e)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new EventHandler<SerialDataEventArgs>(serialPortManager_DataReceived), new object[] { sender, e });
return;
}
if (mIsPaused)
return;
mSerialPortManager.mRequest.Append(ByteArrayConverter.toString(e.mData).Replace("-", ""));
}
...
}
The communication should be like below:
request: 5555555555555555808080800100000001001A0006070001060031B1
response: 55555555555555558080808001000000010000808076
request: 5555555555555555808080800200000001001A0006070001060034B2
response: 555555555555555580808080020000000100008041BA
request: 5555555555555555808080800300000001001A000607000106003473
response: 55555555555555558080808003000000010000804049
And so on. It is just example, what the request frame should look like. As you can see, the device asks for 1,2,3,4, etc. It always asks in this order. The last four values are just checksum. What I receive after response is like:
request: 5555555555555555808080800200000001001A0006070001060034B2
response: 555555555555555580808080020000000100008041BA
request: 55555555555555558080808002000000000A0100000000000000BCAE
After response for 2, there should be an ask for 3. If I set the software to not responding, every request looks fine.
What I am doing wrong?
Ok, so everything is okay. My COM interface is broken :( Everything is fine with both ways - DataReceived event handler and read() right after write() (no matter which solution is better in programming way). Thank you all for trying help with my case anyway!

APM pattern, Await Async

I need help on how to use APM pattern, i am now reading some articles, but i am afraid i don't have much time. What i really want is to get all the persons(data from db) then get the photos and put it on a autocompletebox
Code:
void listanomesautocomplete(object sender, ServicosLinkedIN.queryCompletedEventArgs e)
{
if (e.Result[0] != "")
{
for (int i = 0; i < e.Result.Count(); i = i + 3)
{
Pessoa pessoa = new Pessoa();
pessoa.Nome = e.Result[i];
pessoa.Id = Convert.ToInt32(e.Result[i + 1]);
if (e.Result[i + 2] == "")
pessoa.Imagem = new BitmapImage(new Uri("Assets/default_perfil.png", UriKind.Relative));
else
{
ServicosLinkedIN.ServicosClient buscaimg = new ServicosLinkedIN.ServicosClient();
buscaimg.dlFotoAsync(e.Result[i + 2]);
buscaimg.dlFotoCompleted += buscaimg_dlFotoCompleted;//when this completes it saves into a public bitmapimage and then i save it into pessoa.Imagem
//basicly, what happends, the listadlfotosasync only happends after this function
//what i want is to wait until it completes and have into the class novamsg
pessoa.Imagem = img;//saving the photo from dlFotoAsync
}
listaPessoas.Add(pessoa);
}
tbA_destinatario.ItemsSource = null;
tbA_destinatario.ItemsSource = listaPessoas;
BackgroundWorker listapessoas = new BackgroundWorker();
listapessoas.DoWork += listapessoas_DoWork;
listapessoas.RunWorkerAsync();
tb_lerdestmsg.Text = "";
}
else
{
tbA_destinatario.ItemsSource = null;
tb_lerdestmsg.Text = "Não encontrado";
}
}
There are a few things to address here:
The listanomesautocomplete event handler should be async. Handle and report all exceptions possibly thrown inside it (generally, this rule applies to any event handler, but it's even more important for async event handlers, because the asynchronous operation inside your handler continues outside the scope of the code which has fired the event).
Register the dlFotoCompleted event handler first, then call dlFotoAsync. Do not assume that dlFotoAsync will be always executed asynchronously.
Think about the case when another listanomesautocomplete is fired while the previous operation is still pending. This well may happen as a result of the user's action. You may want to cancel and restart the pending operation (like this), or just queue a new one to be executed as soon as the pending one has completed (like this).
Back to the question, it's the EAP pattern that you need to wrap as Task, not APM. Use TaskCompletionSource for that. The relevant part of your code may look like this:
async void listanomesautocomplete(object sender, ServicosLinkedIN.queryCompletedEventArgs e)
{
if (e.Result[0] != "")
{
for (int i = 0; i < e.Result.Count(); i = i + 3)
{
Pessoa pessoa = new Pessoa();
pessoa.Nome = e.Result[i];
pessoa.Id = Convert.ToInt32(e.Result[i + 1]);
if (e.Result[i + 2] == "")
pessoa.Imagem = new BitmapImage(new Uri("Assets/default_perfil.png", UriKind.Relative));
else
{
// you probably want to create the service proxy
// outside the for loop
using (ServicosLinkedIN.ServicosClient buscaimg = new ServicosLinkedIN.ServicosClient())
{
FotoCompletedEventHandler handler = null;
var tcs = new TaskCompletionSource<Image>();
handler = (sHandler, eHandler) =>
{
try
{
// you can move the code from buscaimg_dlFotoCompleted here,
// rather than calling buscaimg_dlFotoCompleted
buscaimg_dlFotoCompleted(sHandler, eHandler);
tcs.TrySetResult(eHandler.Result);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
};
try
{
buscaimg.dlFotoCompleted += handler;
buscaimg.dlFotoAsync(e.Result[i + 2]);
// saving the photo from dlFotoAsync
pessoa.Imagem = await tcs.Task;
}
finally
{
buscaimg.dlFotoCompleted -= handler;
}
}
}
listaPessoas.Add(pessoa);
}
tbA_destinatario.ItemsSource = null;
tbA_destinatario.ItemsSource = listaPessoas;
BackgroundWorker listapessoas = new BackgroundWorker();
listapessoas.DoWork += listapessoas_DoWork;
listapessoas.RunWorkerAsync();
tb_lerdestmsg.Text = "";
}
else
{
tbA_destinatario.ItemsSource = null;
tb_lerdestmsg.Text = "Não encontrado";
}
}
void listanomesautocomplete(object sender, ServicosLinkedIN.queryCompletedEventArgs e)
{
if (e.Result[0] != "")
{
List<Pessoa> listaPessoas = new List<Pessoa>();
for (int i = 0; i < e.Result.Count(); i = i + 3)
{
Pessoa pessoa = new Pessoa();
pessoa.Nome = e.Result[i];
pessoa.Id = Convert.ToInt32(e.Result[i + 1]);
if (e.Result[i + 2] == "")
pessoa.Imagem = new BitmapImage(new Uri("Assets/default_perfil.png", UriKind.Relative));
else
{
ServicosLinkedIN.ServicosClient buscaimg = new ServicosLinkedIN.ServicosClient();
buscaimg.dlFotoAsync(e.Result[i + 2]);
//THIS ACTUALLY WORKS!!!
//THE THREAD WAITS FOR IT!
buscaimg.dlFotoCompleted += (s, a) =>
{
pessoa.Imagem = ConvertToBitmapImage(a.Result);
};
}
listaPessoas.Add(pessoa);
}
if (tbA_destinatario.ItemsSource == null)
{
tbA_destinatario.ItemsSource = listaPessoas;
}
tb_lerdestmsg.Text = "";
}
else
{
tbA_destinatario.ItemsSource = null;
tb_lerdestmsg.Text = "Não encontrado";
}
}
Man, i am not even mad, i am amazed.
Noseratio, you answer gave me an idea and it actually worked!!
Thanks a lot man, i can't thank you enough ;)

Categories

Resources