Xamarin app shows blank page while looping - c#

I'm making an Android application on Xamarin and I want this code to be looped over and over.
But when it's looping it shows literally nothing
public MainPage()
{
InitializeComponent();
for (int i = 0; i < 100; i++)
{
Thread.Sleep(2000);
string app = "notepad";
HttpClient httpClient = new HttpClient();
var result = httpClient.GetAsync("LINK/ob/ob.php?text=" + app).Result;
var contents = result.Content.ReadAsStringAsync().Result;
string decider = contents.ToString();
if (decider.Length > 7)
{
van.Text = "The " + app + " is ON";
van.TextColor = Xamarin.Forms.Color.Green;
}
else
{
van.Text = "The " + app + " is off";
}
}
}

first, don't do this in the constructor. Doing so guarantees that your page won't display until the code completes
second, instead of doing this in a loop with Thread.Sleep() use a timer instead
Timer timer;
int counter;
protected override void OnAppearing()
{
timer = new Timer(2000);
timer.Elapsed += OnTimerElapsed;
timer.Enabled = true;
}
private void OnTimerElapsed(object sender, ElapsedEventArgs a)
{
counter++;
if (counter > 100) timer.Stop();
// put your http request code here
// only the UI code updates should run on the main thread
MainThread.BeginInvokeOnMainThread(() =>
{
if (decider.Length > 7)
{
van.Text = "The " + app + " is ON";
van.TextColor = Xamarin.Forms.Color.Green;
}
else
{
van.Text = "The " + app + " is off";
}
});
}

Related

How to more efficiently set properties of multiple Form Controls

My problem is that I have multiple Forms Controls that I need to make visible/invisible/change text, based on the output of my code.
Obviously this is very easy to achieve but the code is ridiculously long due to how I've set it up.
I have 3 image boxes containing a red, green and orange 'light'.
When the ping action is started (button click or a timer) all the controls need to be set like so:
// ping 1
redLight1.Visible = true;
greenLight1.Visible = false;
orangeLight1.Visible = false;
status_Lbl1.Text = "Initiated...";
I need to do this 9 times, and the code looks a bit meh to me having this repeated this many times.
I have a ping object that sends a ping every second for x amount of time. If all of the pings are sent and received successfully then an imagebox containing a green circle becomes visible greenLight1.Visible = true, while all others are set redLight1.Visible = false, orangeLight1.Visible = false, etc.
I have 9 of these sets of 'traffic lights', with a different IP being pinged and a different outcome for each.
I feel there must be a way to iteratively change the values of each of these boxes using the fact they all follow the same naming convention with just a different number on the end corresponding to the ping object they represent.
Here's a more visual idea of what I want to achieve.
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// int counter = 0
if (e.Cancelled == true)
{
status_Lbl1.Text = "Cancelled";
}
else if (e.Error != null)
{
status_Lbl1.Text = "Error: " + e.Error.Message;
}
else
{
foreach (Ping pingObj in pings)
{
if (pingObj.SuccessfulPings == 0)
{
Debug.WriteLine("Ping Object: " + pingObj.Fqdn + " failed to successfully ping");
// greenLight[i].Visible = false;
// orangeLight[i].Visible = false;
// redLight[i].Visible = true;
// counter++
}
else if (pingObj.FailedPings != 0)
{
Debug.WriteLine("Ping Object: " + pingObj.Fqdn + " failed to successfully ping: " + pingObj.FailedPings + " times.");
// greenLight[i].Visible = false;
// orangeLight[i].Visible = true;
// redLight[i].Visible = false;
// counter++
}
else
{
Debug.WriteLine("Ping Object: " + pingObj.Fqdn + " succesfully pinged: " + pingObj.SuccessfulPings + " times.");
// greenLight[i].Visible = false;
// orangeLight[i].Visible = false;
// redLight[i].Visible = false;
// counter++
}
}
}
}
Here's the method that creates/uses the ping objects just in case that is necessary
private async void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
// Create background worker
BackgroundWorker worker = (BackgroundWorker)sender;
// Write to log file
await file.WriteAsync("Starting job...\n");
await file.WriteAsync("Requested amount of pings: " + count + "\n");
// Create date object for logs
DateTime localDate = DateTime.Now;
for (int i = 0; i < count; i++)
{
// Create ping objects
System.Net.NetworkInformation.Ping pinger = new System.Net.NetworkInformation.Ping();
PingReply pingReply;
try
{
foreach (Ping pingObj in pings)
{
try
{
pingReply = pinger.Send(pingObj.IpAddress);
// Write log file
await file.WriteLineAsync(localDate.TimeOfDay + " | Friendly Name " + pingObj.FriendlyName + " | Ping: " + pingReply.Address + " | Status " + pingReply.Status + " | Time: " + pingReply.RoundtripTime);
if (pingReply.Status.ToString().Contains("Success"))
{
pingObj.SuccessfulPings += 1;
}
else // Unsuccessful ping has been sent
{
pingObj.FailedPings += 1;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
wait(1000);
}
catch (Exception b)
{
Debug.WriteLine(b.ToString());
}
}
}
catch (Exception a)
{
Debug.WriteLine(a.ToString());
}
}
You can use Controls.Find() and "search by name" with the recurse option:
Control ctl = this.Controls.Find("greenLight" + counter, true).FirstOrDefault() as Control;
if (ctl != null) {
ctl.Visible = false;
}

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

Report progress using BackgroundWorker report only for the first time

I want my application will show on my form my class properties so I started my class with BackgroundWorker and create ProgressChanged.
my class:
public class DumpFile
{
PacketDevice _device;
public int _packetsCount;
public double _bitsPerSecond;
public double _packetsPerSecond;
public DateTime _lastTimestamp;
public delegate void dlgPackProgress(int progress);
public event dlgPackProgress evePacketProgress;
public DumpFile(PacketDevice device, string pcapPath)
{
_device = device;
_pcapPath = pcapPath;
_packetsCount = 1;
}
public void startCapturing()
{
OnPacketProgress(_packetsCount++);
using (PacketCommunicator communicator = _device.Open(65536, PacketDeviceOpenAttributes.Promiscuous, 1000)) //open the device
{
ThreadStart starter = delegate { openAdapterForStatistics(_device); };
new Thread(starter).Start();
using (PacketDumpFile dumpFile = communicator.OpenDump(_pcapPath)) //open the dump file
{
communicator.ReceivePackets(0, dumpFile.Dump); //start the capture
}
}
}
private void OnPacketProgress(int packet)
{
var handler = evePacketProgress;
if (handler != null)
{
handler(packet);
}
}
public void openAdapterForStatistics(PacketDevice selectedOutputDevice)
{
using (PacketCommunicator statCommunicator = selectedOutputDevice.Open(100, PacketDeviceOpenAttributes.Promiscuous, 1000)) //open the output adapter
{
ThreadStart start = delegate { test(selectedOutputDevice); };
new Thread(start).Start();
statCommunicator.SetFilter("tcp"); //compile and set the filter
statCommunicator.Mode = PacketCommunicatorMode.Statistics; //put the interface in statstics mode
statCommunicator.ReceiveStatistics(0, StatisticsHandler);
}
}
public void test(PacketDevice selectedOutputDevice)
{
using (PacketCommunicator communicator = selectedOutputDevice.Open(65536, PacketDeviceOpenAttributes.Promiscuous, 1000))
{
communicator.ReceivePackets(0, PacketHandler);
}
}
private void PacketHandler(Packet packet)
{
string result = _packetsCount.ToString() + ". " + packet.Timestamp.ToString("yyyy-MM-dd hh:mm:ss.fff") + " length:" + packet.Length;
_packetsCount++;
}
private void StatisticsHandler(PacketSampleStatistics statistics)
{
DateTime currentTimestamp = statistics.Timestamp; //current sample time
DateTime previousTimestamp = _lastTimestamp; //previous sample time
_lastTimestamp = currentTimestamp; //set _lastTimestamp for the next iteration
if (previousTimestamp == DateTime.MinValue) //if there wasn't a previous sample than skip this iteration (it's the first iteration)
{
return;
}
double delayInSeconds = (currentTimestamp - previousTimestamp).TotalSeconds; //calculate the delay from the last sample
_bitsPerSecond = statistics.AcceptedBytes * 8 / delayInSeconds; //calculate bits per second
_packetsPerSecond = statistics.AcceptedPackets / delayInSeconds; //calculate packets per second
}
}
start button who start capturing:
private void btnStartCapture_Click(object sender, EventArgs e)
{
timerSniffer.Start();
btnStartTabSniffer.Enabled = false;
btnStopTabSniffer.Enabled = true;
groupBoxSelectTabSniffer.Enabled = false;
bgWorker = new BackgroundWorker();
bgWorker.WorkerReportsProgress = true;
bgWorker.ProgressChanged += new ProgressChangedEventHandler(bgWSniffer_ProgressChanged);
bgWorker.DoWork += new DoWorkEventHandler(
(s3, e3) =>
{
DumpFile dumpFile = new DumpFile(deviceForCapturing, pcapFilePathSniffer);
tshark.evePacketProgress += new DumpFile.dlgPackProgress(
(packet) =>
{
bgWorker.ReportProgress(packet, dumpFile);
});
dumpFile.startCapturing();
});
bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
(s3, e3) =>
{
groupBoxSelectTabSniffer.Enabled = true;
});
bgWorker.RunWorkerAsync();
}
ProgressChanged:
private void bgWSniffer_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var dumpFile = (DumpFile)e.UserState;
lblNumberOfPacketsTabSniffer2.Text = dumpFile._packetsCount.ToString("#,##0");
lblTrafficRateTabSniffer2.Text = (dumpFile._bitsPerSecond * 0.000001).ToString("0.##") + " Mbit/sec" + " (" + dumpFile._bitsPerSecond.ToString("#,##0") + " Bits/sec" + ")";
lblPacketsRateTabSniffer2.Text = dumpFile._packetsPerSecond.ToString("#,##0") + " Packets/sec";
}
the problem is that my application "get into" ProgressChanged functions but only in one time.
I think I missed something in my class.
I can only find one call to OnPacketProgress(), and it's outside of any loop.
public void startCapturing()
{
OnPacketProgress(_packetsCount++);
....
}
So Yes, that will only be called once.
You need something inside ReceivePackets()

Cross thread problem?

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;
}
}

FileSystemWatcher stops catching events

I am writing a c# program to let me know when a file has been added or deleted. I run it on my Windows 7 machine and watch an FTP server on our network.
It works fine but will suddenly stop catching any events. I'm guessing that it might be losing connection to the server or there is a glitch in the network.
How can I handle this situation in the code. Is there some exception I can watch for and try to restart the FileSystemWatcher object.
Any suggestions and code samples would be appreciated.
I needed to add an error handler for the FileSystemWatcher
fileSystemWatcher.Error += new ErrorEventHandler(OnError);
And then add this code:
private void OnError(object source, ErrorEventArgs e)
{
if (e.GetException().GetType() == typeof(InternalBufferOverflowException))
{
txtResults.Text += "Error: File System Watcher internal buffer overflow at " + DateTime.Now + "\r\n";
}
else
{
txtResults.Text += "Error: Watched directory not accessible at " + DateTime.Now + "\r\n";
}
NotAccessibleError(fileSystemWatcher ,e);
}
Here is how I reset the SystemFileWatcher object:
static void NotAccessibleError(FileSystemWatcher source, ErrorEventArgs e)
{
source.EnableRaisingEvents = false;
int iMaxAttempts = 120;
int iTimeOut = 30000;
int i = 0;
while (source.EnableRaisingEvents == false && i < iMaxAttempts)
{
i += 1;
try
{
source.EnableRaisingEvents = true;
}
catch
{
source.EnableRaisingEvents = false;
System.Threading.Thread.Sleep(iTimeOut);
}
}
}
I think this code should do what I want it to do.
The previous answer does not fix it completely, I had to reset the watcher not just turn it on and off.
I use filesystemwatcher on a window service
void NotAccessibleError(FileSystemWatcher source, ErrorEventArgs e)
{
int iMaxAttempts = 120;
int iTimeOut = 30000;
int i = 0;
while ((!Directory.Exists(source.Path) || source.EnableRaisingEvents == false) && i < iMaxAttempts)
{
i += 1;
try
{
source.EnableRaisingEvents = false;
if (!Directory.Exists(source.Path))
{
MyEventLog.WriteEntry("Directory Inaccessible " + source.Path + " at " + DateTime.Now.ToString("HH:mm:ss"));
System.Threading.Thread.Sleep(iTimeOut);
}
else
{
// ReInitialize the Component
source.Dispose();
source = null;
source = new System.IO.FileSystemWatcher();
((System.ComponentModel.ISupportInitialize)(source)).BeginInit();
source.EnableRaisingEvents = true;
source.Filter = "*.tif";
source.Path = #"\\server\dir";
source.NotifyFilter = System.IO.NotifyFilters.FileName;
source.Created += new System.IO.FileSystemEventHandler(fswCatchImages_Changed);
source.Renamed += new System.IO.RenamedEventHandler(fswCatchImages_Renamed);
source.Error += new ErrorEventHandler(OnError);
((System.ComponentModel.ISupportInitialize)(source)).EndInit();
MyEventLog.WriteEntry("Try to Restart RaisingEvents Watcher at " + DateTime.Now.ToString("HH:mm:ss"));
}
}
catch (Exception error)
{
MyEventLog.WriteEntry("Error trying Restart Service " + error.StackTrace + " at " + DateTime.Now.ToString("HH:mm:ss"));
source.EnableRaisingEvents = false;
System.Threading.Thread.Sleep(iTimeOut);
}
}
}
You can create a method that initiates the FileSystemWatcher, and in case of an error, just restart it.
private void WatchFile()
{
try
{
fsw = new FileSystemWatcher(path, filter)
{
EnableRaisingEvents = true
};
fsw.Changed += Fsw_Changed;
fsw.Error += Fsw_Error;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private void Fsw_Error(object sender, ErrorEventArgs e)
{
Thread.Sleep(1000);
fsw.Changed -= Fsw_Changed;
fsw.Error -= Fsw_Error;
WatchFile();
}

Categories

Resources