Using a loop to create variables in c# - c#

I am creating an app that measures the time a person has gazed at around 300 objects. For all of the objects, it needs to output the time into a text file. I've succesfully coded this for just one object, but I am trying to do it for 300 objects. This is the code I have created for one object:
Stopwatch Timer = new Stopwatch();
gazeButtonControl1 = GazeInput.GetGazeElement(GazeBlock1);
gazeButtonControl1 = new GazeElement();
GazeInput.SetGazeElement(GazeBlock1, gazeButtonControl1);
TimeSpan Word1 = TimeSpan.Zero;
gazeButtonControl1.StateChanged += GazeBlockControl1_StateChanged;
void GazeBlockControl1_StateChanged(object sender, StateChangedEventArgs ea)
{
if (ea.PointerState == PointerState.Enter)
{
Timer.Start();
}
if (ea.PointerState == PointerState.Exit)
{
Timer.Stop();
Word1 += Timer.Elapsed;
File.WriteAllText(#"*insert path here", Word1.ToString());
Timer.Reset();
}
}
Everytime there is a "1" inserted in the variable or name of an element, I want to have that for all of the 300 objects. This is what I am looking for:
Stopwatch Timer = new Stopwatch();
for (int i = 0; i < 300; i++) {
gazeButtonControl[i] = GazeInput.GetGazeElement(GazeBlock[i]);
gazeButtonControl[i] = new GazeElement();
GazeInput.SetGazeElement(GazeBlock[i], gazeButtonControl[i]);
TimeSpan Word[i] = TimeSpan.Zero;
gazeButtonControl[i].StateChanged += GazeBlockControl[i]_StateChanged;
void GazeBlockControl[i]_StateChanged(object sender, StateChangedEventArgs ea)
{
if (ea.PointerState == PointerState.Enter)
{
Timer.Start();
}
if (ea.PointerState == PointerState.Exit)
{
Timer.Stop();
Woord[i] += Timer.Elapsed;
File.WriteAllText(#"*insert path here", Word[i].ToString());
Timer.Reset();
}
}
}
This code doesn't work. I've tried using lists and that didn't work either. Does anyone know how to make this solution work? Thanks in advance!
Vincent

You can't use placeholders or array indices in names of variables, methods, and so on.
For UWP there seems to be a helper method FindChildByName which allows you to find a control by its name, via (TypeOfChildControl)insertParentControlHere.FindChildByName("<Name of child control>").
I find the following code of yours perplexing:
gazeButtonControl1 = GazeInput.GetGazeElement(GazeBlock1);
gazeButtonControl1 = new GazeElement();
GazeInput.SetGazeElement(GazeBlock1, gazeButtonControl1);
Basically, first you get your gazeButtonControl1 from GazeBlock1 and then ignore it to create a new GazeElement. I guess what is meant is something like in this UWP Gaze sample where it's first checked if the UI control has a gaze element and if not one is created. So I think it should be:
gazeButtonControl1 = GazeInput.GetGazeElement(GazeBlock1);
if (gazeButtonControl1 == null)
{
gazeButtonControl1 = new GazeElement();
GazeInput.SetGazeElement(GazeBlock1, gazeButtonControl1);
}
Also like i wrote in my initial comment you probably need a separate timer for each gaze element.
So in total it should be something like this (albeit untested):
public class YourClass
{
private TimeSpan[] Word = new TimeSpan[300];
private Stopwatch[] Timer = new Stopwatch[300];
private GazeElement[] gazeButtonControl = new GazeElement[300];
public YourMethod(...)
{
for (int i = 0; i < 300; i++)
{
// first find gaze block where parentControl is the control containing your gaze blocks.
var gazeBlock = (UIElement)parentControl.FindChildByName("GazeBlock" + (i + 1));
gazeButtonControl[i] = GazeInput.GetGazeElement(gazeBlock);
if (gazeButtonControl[i] == null)
{
gazeButtonControl[i] = new GazeElement();
GazeInput.SetGazeElement(gazeBlock, gazeButtonControl[i]);
}
Word[i] = TimeSpan.Zero;
Timer[i] = new Stopwatch();
gazeButtonControl[i].StateChanged += GazeBlockControl_StateChanged;
}
}
private void GazeBlockControl_StateChanged(object sender, StateChangedEventArgs ea)
{
// get the GazeElement for which this event was raised
var changedControl = (GazeElement)sender;
// find its index in your list of GazeElements.
var i = Array.IndexOf(gazeButtonControl, changedControl);
if (ea.PointerState == PointerState.Enter)
{
Timer[i].Start();
}
if (ea.PointerState == PointerState.Exit)
{
Timer[i].Stop();
Word[i] += Timer.Elapsed;
File.WriteAllText(#"*insert path here", Word[i].ToString());
Timer[i].Reset();
}
}
}
Please not that I use Array.IndexOf instead of gazeButtonControl.IndexOf because I declared gazeButtonControl as an array. If it would be a list (e.g. List<GazeElement> gazeButtonControl) you would use gazeButtonControl.IndexOf.

Related

Entity Framework and copying 100 rows at the time

I'm writing my first Service Worker to handle copying all records from one table to another every 60 seconds. At the moment everything works like a charm, but after deploying I wan't to make sure that all future data will be copied 100 records at one time, until no more records left to copy - and than 60 seconds break.
Fallowing code will copy every record from given date at once, and than wait 60 seconds.
public void CopyLatestData(DateTime from)
{
using (var context = new EdDbContext())
{
var dataToCopy = context.ELMAH_Errors.Where(x => x.TimeUtc > from).ToList();
var result = dataToCopy.Select(x => new parsed_errors(x)).ToList();
context.parsed_errors.AddRange(result);
context.SaveChanges();
}
}
This is how I handle timer
private static void startTimer()
{
if (timer == null)
{
timer = new Timer();
timer.Interval = 60 * 1000;
timer.Elapsed += timer_ElapsedActions;
timer.Start();
}
}
private static void timer_ElapsedActions(object sender, ElapsedEventArgs e)
{
if (isTaskAlreadyRunning)
{
return;
}
lock (locker)
{
if (!isTaskAlreadyRunning)
{
isTaskAlreadyRunning = true;
try
{
copyDataFromRemoteDatabaseToLocalDatabase();
parseCopiedData();
}
finally
{
isTaskAlreadyRunning = false;
}
}
}
what is the easiest way to achieve what I need?
my suggestion would be add a boolean in your Entity like AlreadyCopied or IsCopied. Then use that as a marker.
public bool CopyLatestData()
{
using (var context = new EdDbContext())
{
var query = context.ELMAH_Errors.Where(x => !x.IsCopied).AsQueryable();
//if (query.Any())
if (query.Count() != 0) //this will check if some are left not copied
{
var dataToCopy = query.Take(100).ToList(); //this will only take the first 100
var result = dataToCopy.Select(x => new parsed_errors(x)).ToList();
context.parsed_errors.AddRange(result);
dataToCopy.ForEach(x => x.IsCopied = true); //this will update the records to IsCopied = true
context.SaveChanges();
if (query.Any())
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
}
then in your timer stop timer if the bool value of the if (Copylatestdata() == false)
private static void timer_ElapsedActions(object sender, ElapsedEventArgs e)
{
var stillHasRecords = CopyLatestData();
if (!stillHasRecords)
{
Timer timer = (Timer)sender; //get the sender object
timer.Stop(); // stop the sender
}
}
You could try using .Take() to limit the number of rows returned by the query, that way every 60 seconds it will return a maximum of 100 records. If fewer than 100 records are present it will only return what is there.
var dataToCopy = context.ELMAH_Errors.Where(x => x.TimeUtc > from).Take(100).ToList();
An alternative to 'IsProcessed' would be to keep 'latestProcessed' and then retrieve records that have timestamps after that, in batches of 100.
(Something like the code below, sorry for bad formatting, I'm typing on a phone)
while( keepGoing) {
var dataToCopy = context.ELMAH_Errors
.Where(x => x.TimeUtc > from)
.Where(x => x.TimeUTc > lastProcessedUtc)
.Take(100)
.OrderBy( x => x.TimeUtc)
.ToList();
(...)
if( dataToCopy.Any() ) lastProcessedUtc = data.Last().TimeUtc;
keepGoing = dataToCopy.Any(); //Or .Count() == 100

how to stop looping in file in c#?

I'm Trying to save a customer in file but when i'm saving it, it keeps looping the person i entered i do not know where i'm doing it wrong .The problem is i'm thinking my logic is good but i know i'm doing something wrong somewhere which i can not find it .If you could help me i really appreciate it.
public partial class admin : Window
{
accounts acclist = new accounts();
customers cuslist = new customers();
public admin(string pin, accounts myacc, customers mycus)
{
InitializeComponent();
acclist = myacc;
cuslist = mycus;
}
public void saveaccount()
{
using (StreamWriter writer = new StreamWriter("account.txt"))
{
for (int i = 0; i < acclist.Count; i++)
{
var info = new List<string>
{
acclist[i].accounttype.ToString(),
acclist[i].PIN,
acclist[i].accountnumber,
acclist[i].accountbalance.ToString()
};
var account = String.Join(";", info);
writer.WriteLine(account);
}
}
}
//save to customer file
public void savefile()
{
using (StreamWriter writer = new StreamWriter("customer.txt"))
{
for (int i = 0; i < cuslist.Count; i++)
{
var info = new List<string>
{
cuslist[i].NAME.ToString(),
cuslist[i].pin,
};
var customer = String.Join(";", info);
writer.WriteLine(customer);
}
}
}
// add user
private void Sub_Click(object sender, RoutedEventArgs e)
{
customer newCus = new customer();
account newAcc= new account();
try
{
newCus.NAME = Nameadd.Text;
newCus.pin = pinadd.Text;
newAcc.PIN = pinadd.Text;
newAcc.accountnumber = Accountnumadd.Text;
newAcc.accounttype = 'C';
for (int i = 0; i < acclist.Count; i++)
{
{
if(newAcc.accounttype == 'C')
{
newAcc.PIN = pinadd.Text;
newAcc.accountnumber = Accountnumadd.Text;
newAcc.accounttype = 'S';
}
}
cuslist.add(newCus);
acclist.add(newAcc);
savefile();
saveaccount();
}
}
catch(Exception error)
{
MessageBox.Show(error.Message);
}
}
}
In your "save" event, your doing a for loop over the "count" of elements in your account list. That account list variable is global in scope to your class. The problem is that in your loop, you're adding to that list... so really the list you're iterating over is mutating right under-neath you. As you add that customer, the loop starts next iteration, checks the "count", and ends only when "i" is equal in value to the count. However each pass you're adding to the count... so technically you'll never reach the end as the accList.Count is constantly increasing by 1 each pass.
private void Sub_Click(object sender, RoutedEventArgs e)
{
customer newCus = new customer();
account newAcc= new account();
try
{
newCus.NAME = Nameadd.Text;
newCus.pin = pinadd.Text;
newAcc.PIN = pinadd.Text;
newAcc.accountnumber = Accountnumadd.Text;
newAcc.accounttype = 'C';
for (int i = 0; i < acclist.Count; i++) // here you are checking acclist.Count... each iteration this increases by 1, thus i will never technically ever be equivalent to acclist.Count
{
{
if(newAcc.accounttype == 'C')
{
newAcc.PIN = pinadd.Text;
newAcc.accountnumber = Accountnumadd.Text;
newAcc.accounttype = 'S';
}
}
cuslist.add(newCus);
acclist.add(newAcc); // <-- this is where you're adding to acclist each time. However inside this loop you're constantly increasing its size... thus your infinite loop you're hitting.
savefile();
saveaccount();
}
}
catch(Exception error)
{
MessageBox.Show(error.Message);
}
}
I suggest for one, you use a ForEach statement as it's been suggested. Also, use a separate list to hold your "new" accounts. If you need to add to acclist for whatever reason, then after you've added to your new list, iterate over that and add each one of those back to your acclist. This way you avoid mutating the very object you're looping over.
Another way is to first store the "count" into a variable and check against that so it never changes.
var myCounter = acclist.Count
for (int i = 0; i < myCounter ; i++)
{
...
But, I don't know which option is best for you as I obviously don't know the larger context of what it is you need to ultimately do. :) Either solution should stop your infinite loop though.
Consider the use of a foreach loop. This loop is best used for applications like the one in your savefile() method. It's great for applications where you want to perform an action for every item in a list or collection.
See here: https://msdn.microsoft.com/en-us/library/ttw7t8t6.aspx?f=255&MSPPError=-2147217396
EDIT: The requested example:
List<string> FruitBasket = new List<string>();
FruitBasket.Add("apple");
FruitBasket.Add("banana");
FruitBasket.Add("orange");
foreach (string fruit in FruitBasket)
{
Console.WriteLine(fruit);
}
and this results in an output of:
apple, banana, orange.
In the foreach loop you need to declare a variable of the same type as your collection (so in this example I had a List of strings so I made my variable a string, and then they keyword in assigns this variable to each item in that collection, one at a time, starting from the beginning.

Change TextBlock.Inlines from Backgroundworker

Is there any way to change the inlines from a BackgroundWorker?
I tried the following:
private void test()
{
var rows = GetDataGridRows(dgVarConfig);
foreach (DataGridRow r in rows)
{
TextBlock tb = cMatchEx.GetCellContent(r) as TextBlock;
if (!syntaxWorker.IsBusy)
syntaxWorker.RunWorkerAsync(new KeyValuePair<TextBlock, String>(tb, tb.Text));
}
}
private void syntaxWorker_DoWork(object sender, DoWorkEventArgs e)
{
if (e.Argument == null)
Thread.Sleep(100);
else
{
KeyValuePair<TextBlock, String> kvp = (KeyValuePair<TextBlock, String>)e.Argument;
e.Result = new KeyValuePair<TextBlock, List<Run>>(kvp.Key, Syntax.Highlight(kvp.Value));
}
}
private void syntaxWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Result != null)
{
KeyValuePair<TextBlock, List<Run>> kvp = (KeyValuePair<TextBlock, List<Run>>)e.Result;
TextBlock tb = kvp.Key;
tb.Text = "";
kvp.Value.ForEach(x => tb.Inlines.Add(x));
}
}
And the syntax class:
public static class Syntax
{
static Regex subFormula = new Regex(#"\w+\(\)");
static Regex sapFormula = new Regex(#"\w+\(([^)]+)\)");
static Regex strings = new Regex(#"\'[^']+\'");
static Regex numerals = new Regex(#"\b[0-9\.]+\b");
static Regex characteristic = new Regex(#"(?:)?\w+(?:)?");
static Regex andOr = new Regex(#"( and )|( AND )|( or )|( OR )");
static Regex not = new Regex(#"(not )|(NOT )");
private static Brush[] colorArray;
public static List<Run> Highlight(String input)
{
colorArray = new Brush[input.Length];
for (int i = 0; i < input.Length; i++)
colorArray[i] = Brushes.Black;
//Reihenfolge beibehalten!!
assignColor(Brushes.Blue, characteristic.Matches(input));
assignColor(Brushes.Black, andOr.Matches(input));
assignColor(Brushes.Black, numerals.Matches(input));
assignColor(Brushes.Orange, strings.Matches(input));
assignColor(Brushes.DeepPink, subFormula.Matches(input));
assignColor(Brushes.Green, sapFormula.Matches(input));
assignColor(Brushes.Green, not.Matches(input));
int index = 0;
List<Run> runList = new List<Run>();
foreach (Char character in input)
{
runList.Add(new Run(character.ToString()) { Foreground = colorArray[index] });
index++;
}
colorArray = null;
return runList;
}
public static void Check(TextBlock textBlock)
{
}
private static void assignColor(Brush brush, MatchCollection matchCollection)
{
foreach (Match match in matchCollection)
{
int start = match.Index;
int end = start + match.Length;
for (int i = start; i < end; i++)
{
colorArray[i] = brush;
}
}
}
}
I alway get this error: The calling thread cannot access this object because a different thread owns it.
I tried many different things: return the runList with progress changed, changed the static syntax class to a normal class.. but nothing worked, its always the same error.
I also tried to invoke it from the Backgroundworker.. that means call
List<Run> runList = Syntax.Highlight(kvp.Value);
this.Dispatcher.Invoke((Action)(() =>
{
runList.ForEach(x => publicRunList.Add(x));
}));
Anybody knows the problem?
Use
tb.Dispatcher.Invoke(() => {
tb.Text = "";
kvp.Value.ForEach(x => tb.Inlines.Add(x));
});
instead of
tb.Text = "";
kvp.Value.ForEach(x => tb.Inlines.Add(x));
Gui elements can only be accessed from the Gui thread. Using Dispatcher.Invoke ensures that the invoked action runs on it.
You are also creating Run objects in Syntax.Highlight. You also have to create Gui elements on the Gui thread. So you should also wrap this call in a dispatcher invoke:
e.Result = new KeyValuePair<TextBlock, List<Run>>(kvp.Key, Syntax.Highlight(kvp.Value));
This should work:
//this runs synchronously
kvp.Key.Dispatcher.Invoke(() => {
e.Result = new KeyValuePair<TextBlock, List<Run>>(kvp.Key, Syntax.Highlight(kvp.Value));
});
//this runs asynchronously
kvp.Key.Dispatcher.BeginInvoke((Action)(() => {
e.Result = new KeyValuePair<TextBlock, List<Run>>(kvp.Key, Syntax.Highlight(kvp.Value));
}));
This probably defeats the purpose of why you wanted to use a BackgroundWorker in the first place. I'd suggest to change the interface of Syntax.Highlight to return a list of tuples with the string and the highlight color instead, and then create the Run objects on the Gui thread.
Edit:
As Gopichandar noted, using BeginInvoke executes the given Action asynchronously, so that would solve the freezing of the application. It would still take a couple of seconds until all elements are added to the Gui though.
In WPF, only the thread that the UI element belongs to (i.e. the UI thread) can communicate with it. The DoWork part of the BackgroundWorker is executed in a different thread and thus cannot do anything UI-related. The same thing goes for Timers instead of BackgroundWorkers.
But if you create the BackgroundWorker with var worker = new BackgroundWorker {WorkerReportsProgress = true}; then you can set an event handler for ProgressChanged. Inside your _DoWork(), you can then say: (sender as BackgroundWorker).ReportProgress, which will call your ProgressChanged event handler in the original thread, where you can manipulate the UI elements.
Full example:
http://www.wpf-tutorial.com/misc/multi-threading-with-the-backgroundworker/

Waiting for a parse.com async task to finish in Unity3D

As part of my school project I'm trying to link two tables to decrease the amount of data stored in one table so I wanted to link my "Scores" class with my "CorrectAnswers" class via the ObjectID. However since the tasks are asynchronous, by the time one task is done saving, the other task has already begun or also finished saving and so the ObjectID returns as null.
Here's the code I'm using:
public void SaveScore()
{
ParseObject SendScore = new ParseObject("Scores");
SendScore["Score"] = CheckAnswer.score;
SendScore["user"] = ParseObject.CreateWithoutData("_User", ParseUser.CurrentUser.ObjectId);
SendScore["TestMode"] = MainMenu.testmode;
SendScore["TotalQuestions"] = QuestionCreation.TotalQuestions;
SendScore["CorrectQuestions"] = CheckAnswer.CorrectQuestions;
SendScore.SaveAsync().ContinueWith(t =>
{
ScoreObjectId = SendScore.ObjectId;
});
ParseObject SendCorrectTopics = new ParseObject("CorrectAnswers");
SendCorrectTopics["Score"] = SendScore.ObjectId;
for (int i = 0; i <= 9; i++)
{
string Topic = "Topic" + (i + 1).ToString();
SendCorrectTopics[Topic] = CheckAnswer.CorrectTopics[i];
}
SendCorrectTopics.SaveAsync();
SceneManager.LoadScene(0);
}
How would I be able to make the second save hold until the first save has finished? I'm somewhat new to C# and so don't quite know all it's features yet. I've looked into "await" but unity doesn't seem to like that. Any help would be greatly appreciated!
Thanks in advance,
EDIT: Okay, after a bit more reading on Unity's coroutines, I found a much better way of checking that only relies on checking when needed:
IEnumerator CheckSave()
{
while(ScoreObjectId == null & !DoneSave))
{
print("Running");
yield return new WaitForSeconds(0.5f);
}
DoneSave = false;
SaveTotalTopics();
}
This seems like a much better way of doing it.
Well, it seems the answer was something I've already done before, even if it is a little ugly.
Using Unity's update function I created a check to make sure the ObjectID is not null and the previous save had completed, as so:
void Update () {
if (ScoreObjectId != null & DoneSave)
{
DoneSave = false;
SaveTotalTopics();
}
Thus splitting it into two saves and creating:
public void SaveScore()
{
ParseObject SendScore = new ParseObject("Scores");
SendScore["Score"] = CheckAnswer.score;
SendScore["user"] = ParseObject.CreateWithoutData("_User", ParseUser.CurrentUser.ObjectId);
SendScore["TestMode"] = MainMenu.testmode;
SendScore["TotalQuestions"] = QuestionCreation.TotalQuestions;
SendScore["CorrectQuestions"] = CheckAnswer.CorrectQuestions;
Task SendingScores = SendScore.SaveAsync().ContinueWith(t =>
{
if (t.IsFaulted || t.IsCanceled)
{
DoneSave = false;
print(t.Exception);
}
else
{
DoneSave = true;
print("Setting object ID!");
ScoreObjectId = SendScore.ObjectId;
print(ScoreObjectId);
}
});
}
void SaveTotalTopics()
{
for (int i = 0; i <= 9; i++)
{
string Topic = "Topic" + (i + 1).ToString();
SendCorrectTopics[Topic] = CheckAnswer.CorrectTopics[i];
}
SendCorrectTopics["UserScore"] = ParseObject.CreateWithoutData("Scores", ScoreObjectId);
SendCorrectTopics.SaveAsync().ContinueWith(t =>
{
if(t.IsFaulted || t.IsCanceled)
{
print(t.Exception);
}
else
{
print("Saved!");
}
});
}
I'd also forgotten to use ParseObject.CreateWithoutData() so my first code snippet wouldn't have worked even if I'd found a better method...
So, although I'm not happy with the final result, at least it works and I don't think running an if statement every frame should significantly impact on my game's performance.
Why not use a bool and a while loop?
public IEnumerator SaveScore()
{
bool canContinue = false;
ParseObject SendScore = new ParseObject("Scores");
SendScore["Score"] = CheckAnswer.score;
SendScore["user"] = ParseObject.CreateWithoutData("_User", ParseUser.CurrentUser.ObjectId);
SendScore["TestMode"] = MainMenu.testmode;
SendScore["TotalQuestions"] = QuestionCreation.TotalQuestions;
SendScore["CorrectQuestions"] = CheckAnswer.CorrectQuestions;
SendScore.SaveAsync().ContinueWith(t =>
{
ScoreObjectId = SendScore.ObjectId;
//set the bool canContinue to true because the first portion of code has finished running
canContinue = true;
});
//wait while the canContinue bool is false
while(!canContinue){
yield return null;
}
//continue your parse code
ParseObject SendCorrectTopics = new ParseObject("CorrectAnswers");
SendCorrectTopics["Score"] = SendScore.ObjectId;
for (int i = 0; i <= 9; i++)
{
string Topic = "Topic" + (i + 1).ToString();
SendCorrectTopics[Topic] = CheckAnswer.CorrectTopics[i];
}
SendCorrectTopics.SaveAsync();
SceneManager.LoadScene(0);
return null;
}

Making an method execute on interval in Winforms in C#

I’m making an RSS reader, I want it to be able to update at a given interval of time.
I’m not interested in using the Winforms Timer component.
I was more thinking about using the System.Threading.Timer.
The method I want to execute on an interval looks like this:
public void getNews()
{
for (int i2 = 0; i2 < urlList.Count; i2++)
{
//Creates a XmlTextReader which reads from the url entered in input field
rssReader = new XmlTextReader(urlList[i2]);
//Creates an xml doc to save the content of the entered path
rssDoc = new XmlDocument();
//Loads the xml content from the reader into a XmlDocument
rssDoc.Load(rssReader);
//Make a loop to search for the <rss> tag
for (int i = 0; i < rssDoc.ChildNodes.Count; i++)
{
//If the childenode is the rss tag
if (rssDoc.ChildNodes[i].Name == "rss")
{
//the <rss> tag is found, and we know where it is
nodeRss = rssDoc.ChildNodes[i];
}
}
//Make a loop to search for the <channel> tag
for (int i = 0; i < nodeRss.ChildNodes.Count; i++)
{
//If the childnode is the channel tag
if (nodeRss.ChildNodes[i].Name == "channel")
{
//The channel tag is found and we know where it is
nodeChannel = nodeRss.ChildNodes[i];
}
}
//Make a loop to search for the <item> tag
for (int i = 0; i < nodeChannel.ChildNodes.Count; i++)
{
//If the childnode is the item tag
if (nodeChannel.ChildNodes[i].Name == "item")
{
//the item tag is found, and we know where it is
nodeItem = nodeChannel.ChildNodes[i];
//Creates a new row in the LstView which contains information from inside the nodes
rowNews = new ListViewItem();
rowNews.Text = nodeItem["title"].InnerText;
rowNews.SubItems.Add(nodeItem["link"].InnerText);
if (this.lstView.InvokeRequired)
{
AddItemCallback d = new AddItemCallback(getNews);
this.Invoke(d);
return;
}
lstView.Items.Add(rowNews);
}
}
}
}
This is the button, that executes the method:
private void btnRead_Click(object sender, EventArgs e)
{
lstView.Items.Clear();
Thread myThread = new Thread(getNews);
myThread.Start();
}
How do I execute my getNews() method on a specific interval? Examples with my code are very appreciated.
User Timer Control and write code in Tick event...
http://www.c-sharpcorner.com/UploadFile/mahesh/WorkingwithTimerControlinCSharp11302005054911AM/WorkingwithTimerControlinCSharp.aspx
I would start a new thread and sleep for the specified interval at the end of it.
for example
you would have a member variable for whether the process is running and the interval
private bool _isRunning = false;
private int _interval = 1000;
then in your start method create a new thread
public void Start()
{
ThreadStart oThreadStart = new ThreadStart(DoWork);
Thread t = new Thread(oThreadStart);
_isRunning = true;
t.Start();
}
public void Stop()
{
_isRunning = false;
}
private void DoWork()
{
while(_isRunning)
{
// do work
Thread.Sleep(_interval);
}
Thread.CurrentThread.Join();
}
You then have all processing on one thread and it sleeps while not in use (eg waiting for the next 'tick')
also, using this method prevents the possibility of a second tick event being fired until the first one has finished processing
I like the Reactive Extensions for these things.
var observable = Observable.Interval(TimeSpan.FromSeconds(2)); // Interval in seconds
var subscription = observable.Subscribe(_ => getNews());
// Or if it does not work then try this:
var subscription = observable.ObserveOnWindowsForms().Subscribe(_ => getNews());
using (subscription)
{
Console.WriteLine("Press any key to stop...");
Console.ReadKey();
}
Instead of stopping with a console key press, you can call .Dispose() on subscription and delete the whole using block.
For testing this approach, try replacing _ => getNews() with Console.WriteLine and then you will see how it works :) (it is a example from http://rxwiki.wikidot.com/101samples)

Categories