I have a problem where I have some values that needs to be updated every 5 sec. But in between I have to update my newsfeed too.
How do I run my newsfeed?: My newsfeed will be run while in a loop, moving the text left.
Problem: I will need somehow to run all my other code at the same time as the newsfeed is also running. But I can't figure out a way to do this. I can't place my newsfeed updater inside my main loop, because then it update with the rest too, resulting in the newsfeed bugging.
Code:
public partial class Form1 : Form
{
ServiceReference1.monitorSoapClient ds = new ServiceReference1.monitorSoapClient();
public Form1()
{
InitializeComponent();
}
private void lblTempOut_Click(object sender, EventArgs e)
{
}
private async void btnUpdate_Click(object sender, EventArgs e)
{
int i = 0;
do
{
lblTempOut.Text = ds.OutdoorTemp().ToString("N2") " °C";
lblInsideTemp.Text = ds.StockTemp().ToString("N2") " °C";
lblHumitidyOutside.Text = ds.OutdoorHumidity().ToString("N2") " %";
lblStockHumitidy.Text = ds.StockHumidity().ToString("N2") " %";
{
listBoxMinItem.Items.Clear();
ds.StockItemsUnderMin().ForEach(item =>
{
listBoxMinItem.Items.Add(item);
});
}
{
listBoxMostSold.Items.Clear();
ds.StockItemsMostSold().ForEach(item =>
{
listBoxMostSold.Items.Add(item);
});
}
{
ListBoxOverMax.Items.Clear();
ds.StockItemsUnderMin().ForEach(item =>
{
ListBoxOverMax.Items.Add(item);
});
}
TimeZoneInfo timeZoneCopenhagen = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
DateTime CEST = DateTime.UtcNow;
DateTime ConvertedTimeCEST = TimeZoneInfo.ConvertTimeFromUtc(CEST, timeZoneCopenhagen);
lblTimeCopenhagen.Text = ConvertedTimeCEST.ToString();
TimeZoneInfo timeZoneLondon = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTime GMT = DateTime.UtcNow;
DateTime ConvertedTimeGMT = TimeZoneInfo.ConvertTimeFromUtc(GMT, timeZoneLondon);
lblTimeLondon.Text = ConvertedTimeGMT.ToString();
TimeZoneInfo timeZoneSST = TimeZoneInfo.FindSystemTimeZoneById("Singapore Standard Time");
DateTime SST = DateTime.UtcNow;
DateTime ConvertedTimeSST = TimeZoneInfo.ConvertTimeFromUtc(SST, timeZoneSST);
lblTimeSingapore.Text = ConvertedTimeSST.ToString();
string newsFeedUrl = @"https://nordjyske.dk/rss/nyheder";
XmlReader reader = XmlReader.Create(newsFeedUrl);
SyndicationFeed syndFeed = SyndicationFeed.Load(reader);
reader.Close();
foreach (SyndicationItem item in syndFeed.Items)
{
newsFeed.Text = item.Title.Text " ";
}
await Task.Delay(5000);
} while (i == 0);
Move();
}
private void ResetNewsPosition()
{
newsFeed.Left = newsContainer.Width;
}
private async void Move()
{
while (true)
{
ResetNewsPosition();
while (newsFeed.Location.X newsFeed.Width >= 0)
{
newsFeed.Left -= 1;
await Task.Delay(10);
}
}
}
If anyone have any suggestions, please do let me know :)
CodePudding user response:
You do this by using Timers. When writing UI code you should not write loops that take longer than a few hundred ms to complete. And if your loop contains a Task.Delay or a Thread.Sleep it is a strong indicator that you should use a timer instead. Task.Delay will internally use a timer, and in some cases it can be convenient to use if you want a single short delay, but whenever you make statements like "I want to run X ever Y seconds" it will probably be better to use a timer directly.
This lets you interleave different functions, i.e. you run each function after each other on a single thread, possibly with different frequencies. For example, rewrite your move function to
private void MoveNewsPos(){
newsFeed.Left -= 1;
if(newsFeed.Location.X newsFeed.Width < 0)
ResetNewsPosition();
}
and call this from a timer with a 10ms interval.
The other option is to use multi threading. But this is mostly useful when you are doing things that are computationally expensive. It is not useful at all when most of the task consists of updating the UI.
For completeness there is also asynchronous operations that are mostly useful when doing IO work, to allow the UI thread to do other things while waiting from results from the disk or network.
see also why are there 5 timer classes for different types of timers.
CodePudding user response:
To start a task about every 5 seconds, my advice would be to use class System.Timers.Timer. It is a Component, so it must be disposed when your form is disposed. Best way to do this is to add it to your form's property components.
private Timer CreateUpdateTimer()
{
TimeSpan timerTime = TimeSpan.FromSeconds(5);
Timer timer = new Timer(timerTime.TotalMilliSeconds);
// Hook up the Elapsed event for the timer.
timer.Elapsed = OnTimedEvent;
timer.AutoReset = true;
timer.Enabled = true;
return timer;
}
Consider to create a procedure with the TimeoutTime as TimeSpan parameter
// will be called every 5 seconds:
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
this.UpdateValues(); // the procedure that updates your values
}
In your constructor:
public Form1()
{
InitializeComponent();
this.components.Add(this.CreateUpdateTimer());
}
