Resolved How do I update a property every 5 seconds following mvvm pattern using c# and .Net 4.x?

BoomBa

Member
Joined
Dec 24, 2022
Messages
8
Programming Experience
Beginner
I have a property defined in my viewmodel which is supposed to check if todays internet date is same as the system date and store it in the property as some string so that I can bind it to a textblock text or a label content.
But this check must run every 5 second as long as the app is open, that means the value of the property can change and it should reflect on the view accordingly.
How can I do this following mvvm pattern and using .Net 4.x?

I've done

C#:
    public class BaseVM : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
   
    }

    public class VM : BaseVM
    {
        private static System.Timers.Timer chkDate;
       
        public string msg {get;set;}
       
        public VM()
        {
            chkDate = new System.Timers.Timer();
           
            chkDate.Interval = 5000; // every five seconds
           
            chkDate.Elapsed += VerifyDate;
           
            chkDate.AutoReset = true;
           
            chkDate.Enabled = true;
        }
       
       
        public void VerifyDate(Object source, System.Timers.ElapsedEventArgs e)
        {
            if (IsInternetAvailable())
            {
                if (DateTime.Today.ToString("dd-MMM-yyyy") == GetInternetTime().ToString("dd-MMM-yyyy"))
                {
                    msg="Machine date verified!";
                }
               
                else
                    msg="Machine date is not correct!";
            }
           
            else
               
            {
                msg="Machine date cannot be verified! Check internet connectivity !!!";
            }
           
            OnPropertyChanged("msg");
        }
    }

Then in the label : <Label Content="{Binding msg}" Foreground="{Binding msg, Converter={StaticResource TextToColorConverter}}" ... />
I've also added an IValueConverter to convert the color of the text depending of whether msg is equal to a certain text or not:

C#:
    public class TextToColorConverter : IValueConverter
    {
        public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string str = value as string;
            if (value == null || str=="Machine date verified!")
                return new SolidColorBrush(Colors.LightGreen);

            else
                return new SolidColorBrush(Colors.Red);
        }

        public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return null;
        }

    }

But it is not working as intended, initially the value changes like if I change the system date or disconnect internet the property updates but after that I make the system date correct or activate internet the property does not update.

Can someone help?
 
Did you try to set breakpoints to make sure the the correct line of code are being executed?

Not related to your problem, but line 38 can likely be shortened by just comparing the Date property of two DateTime structures.

 
Did you try to set breakpoints to make sure the the correct line of code are being executed?
Where should I ? The problem is updating/refreshing the view. When I start the app it shows the correct data in the view, then when I say disable the internet the view updates properly then too but when say I reconnect to internet it doesn't update it stays on "Machine date cannot be verified! Check internet connectivity !!!" and so initially it updates but then stops updating !?
 
When you turn the internet back on, is your timer still being called? It's why I was asked you to try setting a breakpoint on it.

The easiest way to set a breakpoint is to click on the far left border of edit pane where the white dots appear. For example below, I'm hovering by line 10:
1671897002654.png


If I left click on the mouse button, it would set a breakpoint on that line. If I right click on line, I would be given options for more than just an "always stop" breakpoint.

If you are not a mouse person, put the editting caret on the line where you want the breakpoint and then go to Debug menu, and select "Toggle Breakpoint". If you have the default keymappings, F9 should toggle a breakpoint with having to go to the menu.
 
My personal guess is that you will find that your timer event handler is being called every 5 seconds, but your IsInternetAvailable() keeps returning false even after you have restored your Internet connection.
 
I know how to set a breakpoint, what I was asking is where exactly do I set it ?

Also, if I make my project .Net 6 project it works as expected but for .Net 4.8 it doesn't, evan when I change the system date it doesn't update. So the problem can't be IsInternetAvailable() right ?
 
There were breaking changes in the way things worked in .NET Framework vs .NET (Core). Please show us the code for your IsInternetAvailable().
 
evan when I change the system date it doesn't update
What do the values look like when tracing with the breakpoint? I find it really difficult to imagine DateTime.Today to give you incorrect values. But it doesn't matter it that wrong date is being returned because you reported that the text never changes from "Machine date cannot be verified! Check internet connectivity !!!". That means that either the event handler was not being called, or IsInternetAvailable() was always returning false.
 
Here are my methods IsInternetAvailable() and GetInternetTime()

C#:
public static bool IsInternetAvailable()
         {
                
             try
             {
                 if (Dns.GetHostAddresses("google.com").Any())
                 {
                     return true;
                 }
                 else
                     return false;
                    
             }
             catch (System.Net.Sockets.SocketException x)
             {
                 return false;
             }
         }
            
         public static DateTime GetInternetTime()
         {
             var myHttpWebRequest = (HttpWebRequest)WebRequest.Create("http://www.google.com");
             var response = myHttpWebRequest.GetResponse();
             string todaysDates = response.Headers["date"];
             return DateTime.ParseExact(todaysDates,
                                        "ddd, dd MMM yyyy HH:mm:ss 'GMT'",
                                        CultureInfo.InvariantCulture.DateTimeFormat,
                                        DateTimeStyles.AssumeUniversal);
         }
 
How do you that Dns.GetHostAddress() does not cache results?
 
I ask, because you only try to inspect the date only if you have an internet connection. And if you have an internet connection, you have two strings that are completely different from the string for when there is no internet connection.
 
How do you that Dns.GetHostAddress() does not cache results?
I don't know. What others ways (other than pinging as ping protocol are blocked in many offices/institutions) can I check for an active internet connection ?
 
Actually I found the issue. It's your way of getting to internet time. On the first request Google responds back, but on succeeding calls it doesn't return a response so you are basically left waiting.

I was testing with the following code and set a breakpoint on lines 70 and 73. Would get one or two hits on line 70 and 73, after that lots of hits on line 70, but not on line 73.

C#:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SimpleWpf
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        readonly System.Timers.Timer timer;
        public string Message { get; set; } = String.Empty;

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
            timer = new System.Timers.Timer();

            timer.Interval = 1000;
            timer.Elapsed += Timer_Elapsed;
            timer.AutoReset = true;
            timer.Enabled = true;
        }

        void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (IsInternetAvailable())
            {
                if (DateTime.Today == GetInternetDateTime().Date)
                    Message = $"{DateTime.Now}: Date match.";
                else
                    Message = $"{DateTime.Now}: Date mismatch.";
            }
            else
            {
                Message = $"{DateTime.Now}: Internet not available.";
            }
            OnPropertyChanged("Message");
        }

        static bool IsInternetAvailable()
        {
            try
            {
                return Dns.GetHostAddresses("google.com").Any();
            }
            catch (System.Net.Sockets.SocketException)
            {
                return false;
            }
        }

        static DateTime GetInternetDateTime()
        {
            var myHttpWebRequest = (HttpWebRequest)WebRequest.Create("http://www.google.com");
            var response = myHttpWebRequest.GetResponse();
            string todaysDates = response.Headers["date"];
            return DateTime.ParseExact(todaysDates,
                                       "ddd, dd MMM yyyy HH:mm:ss 'GMT'",
                                       CultureInfo.InvariantCulture.DateTimeFormat,
                                       DateTimeStyles.AssumeUniversal);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

namespace SimpleWpf
{
    public class TextToColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            string str = value as string;
            if (value == null || str.Contains("True"))
                return new SolidColorBrush(Colors.LightGreen);
            else
                return new SolidColorBrush(Colors.Red);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            => throw new NotImplementedException();
    }
}
 
The official way to get time from the Internet is to query a NNTP server.
 
Back
Top Bottom