WPF application crashes when using System.Threading.Thread - c#

I have a button named submit_Button which has the following code in the OnClicked event:
Thread thread = new Thread(new ThreadStart(heavyWork));
thread.Start();
heavyWork function code :
private void heavyWork()
{
DisableUI();
string Name = Name_textBox.Text;
celebrityName = Name.Replace(" ", "+");
string queryURL = "http://stackoverflow.com";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(queryURL);
request.Method = "GET";
// make request for web page
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader htmlSource = new StreamReader(response.GetResponseStream());
string htmlStringSource = string.Empty;
htmlStringSource = htmlSource.ReadToEnd();
response.Close();
//var regex = new Regex(#"<FONT class=""result"">(.*?)</FONT>");
var regex = new Regex(#"<span class=""kno-a-v"">(.*?)</span>");
var match = regex.Match(htmlStringSource);
var result = match.Groups[1].Value;
result = HttpUtility.HtmlDecode(result);
MessageBox.Show(result);
EnableUI();
}
// Functions
private void DisableUI()
{
celebrityName_textBox.IsEnabled = false;
submit_Button.IsEnabled = false;
infoType_listBox.IsEnabled = false;
preloader_Image.Visibility = Visibility.Visible;
}
private void EnableUI()
{
celebrityName_textBox.IsEnabled = true;
submit_Button.IsEnabled = true;
infoType_listBox.IsEnabled = true;
preloader_Image.Visibility = Visibility.Hidden;
}
When I run the application, then press the button, the application crashes immediately!
What's happening ? I tried to use BackgroundWorker Instead, but when I can worker.RunWorkerAsync() nothing happens ( the worker doesn't start ).

DisableUI() is changing the state of UI controls on a thread which is not the UI thread. This is disallowed in WPF, because it is a single threaded UI framework, and only allows you to change controls on something called the UI thread. Dispatcher.Invoke()/BeginInvoke() is your friend.
Good MSDN article on using the Dispatcher

You are going to want to do any UI related stuff on the UI thread, you can do this with the dispatcher, like so:
private void heavyWork()
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(DisableUI));
//rest of method
Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(EnableUI));
}

When using Background Worker your code should look like something like this:
Notice that when you start worker.RunWorkerAsync() method BackgroundWorkerDoWork is called
BackgroundWorker _backgroundWorker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
_backgroundWorker.DoWork += BackgroundWorkerDoWork;
_backgroundWorker.RunWorkerCompleted += BackgroundWorkerRunWorkerCompleted;
void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
//DU STUFF HERE
}
void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
/DO STUFF HERE LIKE HIDE / SHOW / ENABLE/ DISABLE buttons
}

Related

DispatchTimer blocks UI

Hi All: I want to run a function to check internet connection and update the UI content, so i'm using a Dispatchtimer in the WPF loaded, during the intenet check if the ping is blocked by the local server or for some x reasons the UI is blocking.
How can i call the function continuosly without blocking the UI & update the User interface? thanks.
private DispatcherTimer BackgroundAsyncTasksTimer;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
BackgroundAsyncTasksTimer = new DispatcherTimer();
BackgroundAsyncTasksTimer.Interval = TimeSpan.FromMilliseconds(2000);
BackgroundAsyncTasksTimer.Tick += BackgroundAsyncTasksTimer_Tick;
BackgroundAsyncTasksTimer.Start();
}
private async void BackgroundAsyncTasksTimer_Tick(object sender, object e)
{
if(CanConnectToTheInternet())
{
Dispatcher.Invoke((Action)delegate () {
einternetcoxn.Fill = (SolidColorBrush)new BrushConverter().ConvertFromString("#00ff00"); //Eclipse
checkNewversion();
bUpdatesoftware.IsEnabled = true;//button
});
}
else
{
Dispatcher.Invoke((Action)delegate () {
einternetcoxn.Fill = (SolidColorBrush)new BrushConverter().ConvertFromString("#841c34");
clearfields();
});
}
}
private static bool CanConnectToTheInternet()
{
try
{
string[] strArray = new string[5]
{
"8.8.8.8",
"https://www.google.com",
"https://www.microsoft.com",
"https://www.facebook.com",
};
if (((IEnumerable<string>)strArray).AsParallel<string>().Any<string>((Func<string, bool>)(url =>
{
try
{
Ping ping = new Ping();
byte[] buffer = new byte[32];
PingOptions options = new PingOptions();
if (ping.Send(url, 500, buffer, options).Status == IPStatus.Success)
return true;
}
catch
{
}
return false;
})))
return true;
if (((IEnumerable<string>)strArray).AsParallel<string>().Any<string>((Func<string, bool>)(url =>
{
try
{
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.KeepAlive = false;
httpWebRequest.Timeout = 5000;
using ((HttpWebResponse)httpWebRequest.GetResponse())
return true;
}
catch
{
}
return false;
})))
return true;
}
catch
{
return false;
}
return false;
}
A DispatcherTimeris not running the tick event on a background thread, at least not by default in a UI application.
But this should be fine if you change your CanConnectToTheInternetmethod to use Ping.SendAsync and WebRequest.GetResponseAsync. That will require you to follow the async await pattern, but this is an good example of the kind of task this pattern is meant for. In this case you should get rid of all the Dispatcher.Invoke-stuff, since all of your code would run on the UI thread.
The alternative would be to use a timer that runs the tick-event on a threadpool thread, like Timers.Timer. See also timer comparison

Threading concept to improve the webbrowsers URL navigation process in C#

I have developed a simple Id checking windows forms with C# application to check a set of given Ids valid or not by passing to a webpage using webbrowser control and getting the reply and everything is working fine,its taking 40 - 60 seconds for 20 Ids.one by one.Now i want to speed up the same process using advance threading concept in C# .
Code is working fine i want to improve the performance using threading. any simple suggestion would be great help today
private void button2_Click(object sender, EventArgs e)
{
string url = "https://idscheckingsite.com";
WebBrowser wb = new WebBrowser();
wb.ScriptErrorsSuppressed = true;
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(Final_DocumentCompleted);
wb.Navigate(url);
}
private void Final_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wbs = sender as WebBrowser;
wbs.Document.GetElementById("pannumber").InnerText = ListsofIds[ids];
wbs.Document.GetElementById("frmType1").SetAttribute("value", "24Q");
HtmlElement btnlink = wbs.Document.GetElementById("clickGo1");
btnlink.InvokeMember("Click");
//string response = wbs.DocumentText;
wbs.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(Final_DocumentCompleted);
wbs.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(Final_result);
}
private void Final_result(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wbResult = sender as WebBrowser;
string status = wbResult.Document.GetElementById("status").InnerText;
string name = wbResult.Document.GetElementById("name").InnerText;
wbResult.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(Final_result);
wbResult.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(Final_DocumentCompleted);
DataRow dr = dt.NewRow();
dr[0] = PANNumber[ids];
dr[1] = status;
dr[2] = name;
dt.Rows.Add(dr);
++ids;
if (ids < 20)
wbResult.Navigate(vurl);
else
{
dataGridView1.DataSource = dt;
}
}
Working fine but need to improve the performance to the max using advance C# threading concepts if any .
Here is my suggestion. When the button2 is clicked, a number of worker tasks are started. A reasonable number is 4, but you can try different numbers until you get the best performance. Each worker task will use its own WebBrowser control, and will invoke a subset of the ids. For example the worker task #0 will invoke the ids 4, 8, 12, 16, and 20, the worker task #1 will invoke 1, 5, 9, 13, and 17 etc. Then all worker tasks will be waited to complete, and then the DataGridView can be updated. There is no multithreading involved. Everything happens in the UI thread. No locking or other thread synchronization is required.
private async void button2_Click(object sender, EventArgs e)
{
string url = "https://idscheckingsite.com";
const int WORKER_TASKS_COUNT = 4;
var workerTasks = new Task[WORKER_TASKS_COUNT];
for (int i = 0; i < WORKER_TASKS_COUNT; i++)
{
workerTasks[i] = DoWorkAsync(i);
}
await Task.WhenAll(workerTasks);
dataGridView1.DataSource = dt;
async Task DoWorkAsync(int workerIndex)
{
using (var wb = new WebBrowser())
{
wb.ScriptErrorsSuppressed = true;
for (int i = 0; i < ListsofIds.Length; i++)
{
if (i % WORKER_TASKS_COUNT != workerIndex) continue;
wb.Navigate(url);
await wb; // await for the next DocumentCompleted
wb.Document.GetElementById("pannumber").InnerText = ListsofIds[i];
wb.Document.GetElementById("frmType1").SetAttribute("value", "24Q");
HtmlElement btnlink = wb.Document.GetElementById("clickGo1");
btnlink.InvokeMember("Click");
await wb; // await for the next DocumentCompleted
string status = wb.Document.GetElementById("status").InnerText;
string name = wb.Document.GetElementById("name").InnerText;
DataRow dr = dt.NewRow();
dr[0] = PANNumber[i];
dr[1] = status;
dr[2] = name;
dt.Rows.Add(dr);
}
}
}
}
The code above uses an interesting technique to simplify the navigation of the WebBrowser control. Instead of subscribing and unsubscribing manually to the DocumentCompleted event, it is doing it automatically by awaiting the WebBrowser control. Normally this is not possible, but we can make it possible by creating an extension method that returns a TaskAwaiter:
public static class WebBrowserExtensions
{
public static TaskAwaiter<Uri> GetAwaiter(this WebBrowser wb)
{
var tcs = new TaskCompletionSource<Uri>();
WebBrowserDocumentCompletedEventHandler handler = null;
handler = (_, e) =>
{
wb.DocumentCompleted -= handler;
tcs.TrySetResult(e.Url);
};
wb.DocumentCompleted += handler;
return tcs.Task.GetAwaiter();
}
}
Update: After using my code myself I found await wb to be a bit confusing, because the WebBrowser control has many events that could be awaited. So I made it more explicit and extensible be creating an async version of the event (instead of an awaiter):
public static class WebBrowserExtensions
{
public static Task<Uri> DocumentCompletedAsync(this WebBrowser wb)
{
var tcs = new TaskCompletionSource<Uri>();
WebBrowserDocumentCompletedEventHandler handler = null;
handler = (_, e) =>
{
wb.DocumentCompleted -= handler;
tcs.TrySetResult(e.Url);
};
wb.DocumentCompleted += handler;
return tcs.Task;
}
}
It can be used like this:
await wb.DocumentCompletedAsync();
Then it becomes trivial to create more extension methods like NavigatedAsync or DocumentTitleChangedAsync for example.
Update: Waiting endlessly is not very nice, so a timeout (expressed in milliseconds) could be added as an argument in the awaited extension method. Since the whole code is intended to run exclusively in the UI thread I used a System.Windows.Forms.Timer, although a CancellationToken would be propably more convenient in general. The code is a bit involved to avoid memory leaks, that could be an issue for an application intended to run for many hours, and do thousands web requests.
public static class WebBrowserExtensions
{
public static Task<Uri> DocumentCompletedAsync(this WebBrowser wb, int timeout)
{
var tcs = new TaskCompletionSource<Uri>();
WebBrowserDocumentCompletedEventHandler handler = null;
var timeoutRegistration = WithTimeout(tcs, timeout,
() => wb.DocumentCompleted -= handler);
handler = (_, e) =>
{
wb.DocumentCompleted -= handler;
timeoutRegistration.Unregister();
tcs.TrySetResult(e.Url);
};
wb.DocumentCompleted += handler;
return tcs.Task;
}
public static Task<Uri> DocumentCompletedAsync(this WebBrowser wb)
{
return wb.DocumentCompletedAsync(30000); // Default timeout 30 sec
}
private static TimeoutRegistration WithTimeout<T>(
TaskCompletionSource<T> tcs, int timeout, Action eventRemove)
{
if (timeout == Timeout.Infinite) return default;
var timer = new System.Windows.Forms.Timer();
timer.Tick += (s, e) =>
{
timer.Enabled = false;
timer = null;
eventRemove();
eventRemove = null;
tcs.SetException(new TimeoutException());
tcs = null;
};
timer.Interval = timeout;
timer.Enabled = true;
return new TimeoutRegistration(() =>
{
if (timer == null) return;
timer.Enabled = false;
// Make everything null to avoid memory leaks
timer = null;
eventRemove = null;
tcs = null;
});
}
private struct TimeoutRegistration
{
private Action _unregister;
public TimeoutRegistration(Action unregister)
{
_unregister = unregister;
}
public void Unregister()
{
if (_unregister == null) return;
_unregister();
_unregister = null;
}
}
}
Update: As a side note, I see that you are suppressing script errors by using wb.ScriptErrorsSuppressed = true. Are you aware that you can configure the Internet Explorer version emulated by the WebBrowser control? To make the control emulate the latest (and final) version of Internet Explorer, the version 11, add this code at the start of your program:
Registry.SetValue(#"HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION",
AppDomain.CurrentDomain.FriendlyName, 11000); // IE11

How to update a view without waiting for another operation to finish

lets say I have a GroupBox with several Labels. In these Labels, various IP-related information are displayed. One info is the external IP address of the machine.
string externalIP = "";
try
{
WebRequest request = WebRequest.Create("http://checkip.dyndns.org/");
request.Timeout = 3000;
System.Threading.Tasks.Task<System.Net.WebResponse> response = request.GetResponseAsync();
using (StreamReader stream = new StreamReader(response.Result.GetResponseStream()))
{
if (response.Result.ContentLength != -1)
{
externalIP = stream.ReadToEnd();
}
}
}
catch (Exception e)
{
externalIP = "Error.";
}
if (externalIP == "")
{
return "No service.";
}
else
{
return externalIP = (new Regex(#"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}")).Matches(externalIP)[0].ToString();
}
This method is called from following code:
private void updateNetworkIP()
{
string ip4e = "External IPv4: " + getExternalIPv4();
lblIP4external.Text = ip4e;
//Get some more info here.
}
How do I execute the code after getExternalIPv4() even when it's not finished yet? It works when setting a TimeOut like I did above but sometimes the request just takes a little longer but still completes successfully. So I want to still be able to display the external IP but continue to execute the other methods for refreshing the GroupBox.
The BackgroundWorker will deliver what you are after. Sample code:
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += new DoWorkEventHandler(getExternalIPv4Back);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(writeLabel);
bg.RunWorkerAsync();
//The code below this point will be executed while the BackgroundWorker does its work
You have to define getExternalIPv4Back as a DoWork Event Method and include inside it the code to be executed in parallel; also writeLabel as a RunWorkerCompleted Event(required to edit the label without provoking muti-threading-related errors). That is:
private void getExternalIPv4Back(object sender, DoWorkEventArgs e)
{
IP = "External IPv4: " + getExternalIPv4(); //IP -> Globally defined variable
}
private void writeLabel(object sender, RunWorkerCompletedEventArgs e)
{
  lblIP4external.Text = IP;
}

C# Thread dataGridView and Loading

Im trying to load a dataGridView which takes some time, so ive come up with an idea of hiding the datagridview and put an image over the top which says Loading... when finished, the image goes away and the datagrid reappears. Ive tried to do this using threading but having no luck.
Can somebody tell me if i am approaching this in the right way?
Label loadingText = new Label();
PictureBox loadingPic = new PictureBox();
private void TelephoneDirectory_Load(object sender, EventArgs e)
{
dataGridView1.Visible = false;
Thread i = new Thread(LoadImage);
i.Start();
Thread t = new Thread(LoadData);
t.Start();
}
void LoadImage()
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(LoadImage));
}
else
{
loadingPic.Image = Properties.Resources.ReportServer;
loadingPic.Location = new Point(0, 0);
loadingPic.Name = "loadingPic";
loadingPic.Dock = DockStyle.Fill;
loadingPic.SizeMode = PictureBoxSizeMode.CenterImage;
loadingText.Text = "Loading, please wait...";
loadingText.Name = "loadingText";
loadingText.TextAlign = ContentAlignment.MiddleCenter;
loadingText.Size = new Size(this.Size.Width, 30);
loadingText.Font = new System.Drawing.Font("Segoe UI", 9);
loadingText.Location = new Point(0, (this.Size.Height / 2 + 10));
this.Controls.AddRange(new Control[] { loadingPic, loadingText });
loadingText.BringToFront();
}
}
private void LoadData()
{
if (dataGridView1.InvokeRequired)
{
dataGridView1.Invoke(new MethodInvoker(this.LoadData));
}
else
{
DirectorySearcher sea = null;
DirectoryEntry dir = null;
DirectoryEntry d = null;
string domainname = System.DirectoryServices.ActiveDirectory.Domain.GetComputerDomain().Name;
domainname = domainname.Replace(".", ",DC=");
try
{
dir = new DirectoryEntry();
dir.Path = "LDAP://DC=" + domainname;
sea = new DirectorySearcher(dir);
sea.Filter = "(&(objectClass=user)(extensionAttribute1=1)(telephoneNumber=*))";
sea.PageSize = 2000;
SearchResultCollection res = sea.FindAll();
foreach (SearchResult result in res)
{
//DO ALL MY STUFF
dataGridView1.Rows.Add(row);
}
}
catch { }
LoadDataComplete();
}
}
void LoadDataComplete()
{
PictureBox loadingGraphic = this.Controls["loadingPic"] as PictureBox;
Label LoadingLabel = this.Controls["loadingText"] as Label;
DataGridView dataGrid = this.Controls["dataGridView1"] as DataGridView;
dataGrid.Visible = true;
LoadingLabel.Visible = false;
LoadingLabel.Dispose();
loadingGraphic.Visible = false;
loadingGraphic.Dispose();
dataGridView1.Sort(dataGridView1.Columns[0], ListSortDirection.Ascending);
dataGridView1.ClearSelection();
}
Spawning threads for this might not be the best idea, you could use ThreadPool or BackgroundWorker
Loading image should be fast enough that you could just do it synchronously, so make sure you actually need to do some operation on the other thread before you actually need it.
Ask yourself questions like: what if actually my image will load later then my dataTable? ("but it loads faster every time I checked" is not an valid argument when talking about threads)
At the beginning of your methods you are using .Invoke which basically means "wait for UI thread and invoke my code on it synchronously" which bombards your whole idea.
Try something like this:
Load image synchronously
Use ThreadPool to load your DataTable in it, but without using .Invoke
When it's loaded and you need to interact with UI -> then put your code in .Invoke()
Pseudocode coud look like this:
private void TelephoneDirectory_Load(object sender, EventArgs e)
{
dataGridView1.Visible = false;
LoadImage();
ThreadPool.QueueUserWorkItem(new WaitCallback(o => LoadData()));
}
void LoadData()
{
//...Do loading
//but don't add rows to dataGridView
if (dataGridView1.InvokeRequired)
{
//Invoke only the ui-interaction code
dataGridView1.Invoke(new MethodInvoker(this.LoadDataComplete));
}
}
void LoadDataComplete()
{
foreach (SearchResult result in res)
{
//DO ALL MY STUFF
//If do all my stuff is compute intensive and doesn't require UI,
//put it before Invoke() (like here)
dataGridView1.Rows.Add(row);
}
//Rest of code
}

timer in thread problem

I have my application in which in three datagridview independently in three thread load data from wcf service. I execute in each thread timer which every second load this data.
My problem is that every time my thread go threw each thread but only like I show in method timerNowyYork_Elapsed
Any idea why this happens ? I bad lock thread?
this code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Threading;
namespace Sprawdzanie_warunków_pogodowych
{
public partial class Form1 : Form
{
PogodaEntities entity = new PogodaEntities();
System.Timers.Timer timerKrakow = new System.Timers.Timer();
System.Timers.Timer timerSzczecin = new System.Timers.Timer();
System.Timers.Timer timerNowyYork = new System.Timers.Timer();
KeyValuePair<string, string> krakowInfo;
KeyValuePair<string, string> szczecinInfo;
KeyValuePair<string, string> nowyYorkInfo;
public Form1()
{
System.Net.ServicePointManager.Expect100Continue = false;
InitializeComponent();
List<MiastoContainer> miasta = (from miasto in entity.Miasta
select new MiastoContainer()
{
MiastoName = miasto.Nazwa,
Panstwo = miasto.Państwo
}).ToList();
krakowInfo = new KeyValuePair<string, string>(miasta[0].MiastoName, miasta[0].Panstwo);
szczecinInfo = new KeyValuePair<string, string>(miasta[1].MiastoName, miasta[1].Panstwo);
nowyYorkInfo = new KeyValuePair<string, string>(miasta[2].MiastoName, miasta[2].Panstwo);
ParameterizedThreadStart ptsKrakow = new ParameterizedThreadStart(PobierzKrakow);
Thread tKrakow = new Thread(ptsKrakow);
tKrakow.Start(this.dataGridViewKrakow);
ParameterizedThreadStart ptsSzczecin = new ParameterizedThreadStart(PobierzSzczecin);
Thread tSzczecin = new Thread(ptsSzczecin);
tSzczecin.Start(this.dataGridViewSzczecin);
}
private void oAutorzeToolStripMenuItem_Click(object sender, EventArgs e)
{
new AboutBox1().Show();
}
private void zapiszRaportToolStripMenuItem_Click(object sender, EventArgs e)
{
}
public void PobierzKrakow(object parameters)
{
this.timerKrakow.Elapsed += new System.Timers.ElapsedEventHandler(timerKrakow_Elapsed);
this.timerKrakow.Enabled = true;
this.timerKrakow.Interval = 1000;
this.timerKrakow.Start();
}
public void PobierzSzczecin(object parameters)
{
this.timerSzczecin.Elapsed += new System.Timers.ElapsedEventHandler(timerSzczecin_Elapsed);
this.timerSzczecin.Enabled = true;
this.timerSzczecin.Interval = 1000;
this.timerSzczecin.Start();
}
public void PobierzNowyYork(object parameters)
{
this.timerNowyYork.Elapsed += new System.Timers.ElapsedEventHandler(timerNowyYork_Elapsed);
this.timerNowyYork.Enabled = true;
this.timerNowyYork.Interval = 1000;
this.timerNowyYork.Start();
}
void timerNowyYork_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{ GlobalWeather.Weather weather = new GlobalWeather.Weather();
lock (weather)
{
//thread always start from here
List<object> weatherList = new List<object>();
weatherList.Add(weather.GetTempreature(nowyYorkInfo.Key, nowyYorkInfo.Value));
//and end here , never come any line further
weatherList.Add(weather.GetPressure(nowyYorkInfo.Key, nowyYorkInfo.Value));
weatherList.Add(weather.GetHumidity(nowyYorkInfo.Key, nowyYorkInfo.Value));
weatherList.Add(weather.GetVisibility(nowyYorkInfo.Key, nowyYorkInfo.Value));
entity.SaveChanges();
WarunkiPogodowe warunki = new WarunkiPogodowe()
{
Temperatura = weatherList[0].ToString(),
Ciśnienie = weatherList[1].ToString(),
Wilgotność = weatherList[2].ToString(),
Widoczność = weatherList[3].ToString(),
DataSprawdzenia = DateTime.Now
};
entity.AddToWarunkiPogodowe(warunki);
entity.SaveChanges();
int miastoId = entity.Miasta.First(m => m.Nazwa == nowyYorkInfo.Key).id;
Miasto_has_WarunkiPogodowe m_has_wp = new Miasto_has_WarunkiPogodowe()
{
idMiasto_FK = miastoId,
idWarunkiPogodowe_FK = warunki.id
};
entity.AddToMiasto_has_WarunkiPogodowe(m_has_wp);
entity.SaveChanges();
this.dataGridViewNowyYork.Rows.Add(warunki);
}
}
void timerSzczecin_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
GlobalWeather.Weather weather = new GlobalWeather.Weather();
lock (weather)
{
List<object> weatherList = new List<object>();
weatherList.Add(weather.GetTempreature(szczecinInfo.Key, szczecinInfo.Value));
weatherList.Add(weather.GetPressure(szczecinInfo.Key, szczecinInfo.Value));
weatherList.Add(weather.GetHumidity(szczecinInfo.Key, szczecinInfo.Value));
weatherList.Add(weather.GetVisibility(szczecinInfo.Key, szczecinInfo.Value));
entity.SaveChanges();
WarunkiPogodowe warunki = new WarunkiPogodowe()
{
Temperatura = weatherList[0].ToString(),
Ciśnienie = weatherList[1].ToString(),
Wilgotność = weatherList[2].ToString(),
Widoczność = weatherList[3].ToString(),
DataSprawdzenia = DateTime.Now
};
entity.AddToWarunkiPogodowe(warunki);
entity.SaveChanges();
int miastoId = entity.Miasta.First(m => m.Nazwa == szczecinInfo.Key).id;
Miasto_has_WarunkiPogodowe m_has_wp = new Miasto_has_WarunkiPogodowe()
{
idMiasto_FK = miastoId,
idWarunkiPogodowe_FK = warunki.id
};
entity.AddToMiasto_has_WarunkiPogodowe(m_has_wp);
entity.SaveChanges();
this.dataGridViewSzczecin.Rows.Add(warunki);
}
}
void timerKrakow_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
GlobalWeather.Weather weather = new GlobalWeather.Weather();
lock (weather)
{
List<object> weatherList = new List<object>();
weatherList.Add(weather.GetTempreature(krakowInfo.Key, krakowInfo.Value));
weatherList.Add(weather.GetPressure(krakowInfo.Key, krakowInfo.Value));
weatherList.Add(weather.GetHumidity(krakowInfo.Key, krakowInfo.Value));
weatherList.Add(weather.GetVisibility(krakowInfo.Key, krakowInfo.Value));
entity.SaveChanges();
WarunkiPogodowe warunki = new WarunkiPogodowe()
{
Temperatura = weatherList[0].ToString(),
Ciśnienie = weatherList[1].ToString(),
Wilgotność = weatherList[2].ToString(),
Widoczność = weatherList[3].ToString(),
DataSprawdzenia = DateTime.Now
};
entity.AddToWarunkiPogodowe(warunki);
entity.SaveChanges();
int miastoId = entity.Miasta.First(m => m.Nazwa == krakowInfo.Key).id;
Miasto_has_WarunkiPogodowe m_has_wp = new Miasto_has_WarunkiPogodowe()
{
idMiasto_FK = miastoId,
idWarunkiPogodowe_FK = warunki.id
};
entity.AddToMiasto_has_WarunkiPogodowe(m_has_wp);
entity.SaveChanges();
this.dataGridViewKrakow.Rows.Add(warunki);
}
}
}
class MiastoContainer
{
string miastoName;
public string MiastoName
{
get { return miastoName; }
set { miastoName = value; }
}
string panstwo;
public string Panstwo
{
get { return panstwo; }
set { panstwo = value; }
}
public MiastoContainer()
{ }
public MiastoContainer(string miasto, string panstwo)
{
this.MiastoName = miasto;
this.Panstwo = panstwo;
}
public void Add(MiastoContainer item)
{
((ICollection<MiastoContainer>)this).Add(item);
}
}
}
Your locks are completely useless. As you are locking on an object that you just created, each lock will have it's own identifier and does not affect each other at all.
You need all locks that should exclude each other to use the same object as identifier.
System.Timers.Timer lets you set the SynchronizingObject so that it will invoke the callback on the UI thread. When you create your timers, write:
this.timerKrakow.SynchronizingObject = this;
The timer's elapsed event will then be invoked on the UI thread. That eliminates the need for locks in your event handlers.
You could do the same thing, by the way, with a System.Windows.Forms.Timer, which always invokes the event handler on the UI thread.
The drawback to raising the event on the UI thread is that it might block the user interface. It depends on how much time is spent in the event handler. If your event handler is very quick, then this isn't a problem. If it will take 100 milliseconds to process the event handler, though, you probably don't want to do it on the UI thread.
If you elect not to do it on the UI thread, you need to synchronize access to the UI. The timer event handler can't just modify user interface elements. Instead, you need to call this.Invoke so that any UI modification is done on the UI thread.
I strongly suggest that you NOT use System.Timers.Timer. As the documentation states:
The Timer component catches and
suppresses all exceptions thrown by
event handlers for the Elapsed event.
This behavior is subject to change in
future releases of the .NET Framework.
In other words, if there is a bug in your event handler that throws an exception, you will never know it. I suggest using System.Windows.Forms.Timer or System.Threading.Timer instead.
I don't fully understand your question, but (unless I'm mistaken) the timer callbacks occur in the ThreadPool (or the GUI thread, dependent on usage), so starting them in different threads is pointless.
It seems to me that you are accessing DataGridView directly from another thread. You should not do that. UI controls must always be called from the UI thread. You can use the ISynchronizeInvoke interface to pass the data into correct thread.
this.dataGridViewNowyYork.Invoke(new Action(() => {
this.dataGridViewNowyYork.Rows.Add(warunki);
}), null);

Categories

Resources