From: gu.martinm@gmail.com Date: Sun, 3 Aug 2014 13:23:35 +0000 (+0200) Subject: WindowsPhone 8: WeatherInformation X-Git-Url: https://git.gumartinm.name/?a=commitdiff_plain;h=c3d4d842e80da95b23fc6d31296d77ad007ce6e1;p=CSharpForFun%2F.git WindowsPhone 8: WeatherInformation Improvements --- diff --git a/WindowsPhone/WeatherInformation/WeatherInformation/App.xaml.cs b/WindowsPhone/WeatherInformation/WeatherInformation/App.xaml.cs index 62697af..31d00b4 100644 --- a/WindowsPhone/WeatherInformation/WeatherInformation/App.xaml.cs +++ b/WindowsPhone/WeatherInformation/WeatherInformation/App.xaml.cs @@ -27,7 +27,6 @@ namespace WeatherInformation // Use "" to let user Phone Language selection determine locale. // public static String appForceCulture = "qps-PLOC"; private const String appForceCulture = "en"; - private static MainViewModel viewModel = null; // Declare a private variable to store application state. private WeatherData _remoteWeatherData; @@ -35,22 +34,6 @@ namespace WeatherInformation // Declare an event for when the application data changes. public event EventHandler ApplicationDataObjectChanged; - /// - /// MainViewModel estático que usan las vistas con el que se van a enlazar. - /// - /// Objeto MainViewModel. - public static MainViewModel MainViewModel - { - get - { - // Retrasar la creación del modelo de vista hasta que sea necesario - if (viewModel == null) - viewModel = new MainViewModel(); - - return viewModel; - } - } - // Declare a public property to access the application data variable. public WeatherData ApplicationDataObject { @@ -122,73 +105,68 @@ namespace WeatherInformation public void GetDataAsync() { // Call the GetData method on a new thread. + // TODO: Are there too many threads? HttpClient is going to create more... (threadpools and stuff like that...) Thread t = new Thread(new ThreadStart(GetData)); t.Start(); } - private void GetData() + async private void GetData() { - // Check the time elapsed since data was last saved to isolated storage. - TimeSpan TimeSinceLastSave = TimeSpan.FromSeconds(0); - if (IsolatedStorageSettings.ApplicationSettings.Contains("DataLastSavedTime")) - { - DateTime dataLastSaveTime = (DateTime)IsolatedStorageSettings.ApplicationSettings["DataLastSavedTime"]; - TimeSinceLastSave = DateTime.Now - dataLastSaveTime; - } + // Check to see if data exists in isolated storage and see if the data is fresh. + WeatherData weatherData = GetIsolatedStoredData(); - if (TimeSinceLastSave.TotalSeconds < 30 && !StoredLocation.IsNewLocation) + if ((weatherData != null) && IsStoredDataFresh() && !StoredLocation.IsNewLocation) { - GetStoredData(); + ApplicationDataObject = weatherData; } else { // Otherwise, it gets the data from the web. - var task = LoadDataAsync(); - try - { - // TODO: I guess, I may do this because this code is running in a new thread :/ Better alternative just using async? WIP :( - // Using Task.WhenAll to avoid deadlock :) - Task.WhenAll(task); - } - catch (Exception ex) - { - // If the data request fails, alert the user. - ApplicationDataObject = new WeatherData - { - RemoteForecastWeatherData = null, - RemoteCurrentWeatherData = null, - JSONRemoteForecastWeatherData = null, - JSONRemoteCurrentWeatherData = null, - WasThereRemoteError = true - }; - } + ApplicationDataObject = await LoadDataAsync(); } } - private void GetStoredData() + private bool IsStoredDataFresh() { - // Check to see if data exists in isolated storage and see if the data is fresh. + // Check to see if the data is fresh. // This example uses 30 seconds as the valid time window to make it easy to test. // Real apps will use a larger window. + // Check the time elapsed since data was last saved to isolated storage. + TimeSpan TimeSinceLastSave = TimeSpan.FromSeconds(0); + if (IsolatedStorageSettings.ApplicationSettings.Contains("DataLastSavedTime")) + { + DateTime dataLastSaveTime = (DateTime)IsolatedStorageSettings.ApplicationSettings["DataLastSavedTime"]; + TimeSinceLastSave = DateTime.Now - dataLastSaveTime; + } + + if (TimeSinceLastSave.TotalSeconds < 30) + { + return true; + } + + return false; + } + + private WeatherData GetIsolatedStoredData() + { string JSONRemoteCurrentWeather = null; string JSONRemoteForecastWeather = null; using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication()) { - if (isoStore.FileExists("JSONRemoteCurrentWeatherDataFile.txt")) + if (isoStore.FileExists("JSONRemoteCurrentWeatherFile.txt") && + isoStore.FileExists("JSONRemoteForecastWeatherFile.txt")) { - using (StreamReader sr = new StreamReader(isoStore.OpenFile("JSONRemoteCurrentWeatherDataFile.txt", FileMode.Open))) + using (IsolatedStorageFileStream file = isoStore.OpenFile("JSONRemoteCurrentWeatherFile.txt", FileMode.Open)) + using (StreamReader sr = new StreamReader(file)) { // This method loads the data from isolated storage, if it is available. JSONRemoteCurrentWeather = sr.ReadLine(); } - } - - if (isoStore.FileExists("JSONRemoteForecastWeatherDataFile.txt")) - { - using (StreamReader sr = new StreamReader(isoStore.OpenFile("JSONRemoteForecastWeatherDataFile.txt", FileMode.Open))) + using (IsolatedStorageFileStream file = isoStore.OpenFile("JSONRemoteCurrentWeatherFile.txt", FileMode.Open)) + using (StreamReader sr = new StreamReader(file)) { // This method loads the data from isolated storage, if it is available. JSONRemoteForecastWeather = sr.ReadLine(); @@ -198,14 +176,16 @@ namespace WeatherInformation if (!string.IsNullOrEmpty(JSONRemoteCurrentWeather) && !string.IsNullOrEmpty(JSONRemoteForecastWeather)) { - ApplicationDataObject = WeatherDataParser(JSONRemoteForecastWeather, JSONRemoteCurrentWeather); + return WeatherDataParser(JSONRemoteForecastWeather, JSONRemoteCurrentWeather); } + + return null; } /// /// Retrieve remote weather data. /// - async public Task LoadDataAsync() + async public Task LoadDataAsync() { double latitude = StoredLocation.CurrentLatitude; double longitude = StoredLocation.CurrentLongitude; @@ -223,7 +203,7 @@ namespace WeatherInformation AppResources.APIVersionOpenWeatherMap, latitude, longitude, resultsNumber); string JSONRemoteCurrentWeather = await httpClient.GetWeatherDataAsync(formattedCurrentURL); - ApplicationDataObject = WeatherDataParser(JSONRemoteForecastWeather, JSONRemoteCurrentWeather); + return WeatherDataParser(JSONRemoteForecastWeather, JSONRemoteCurrentWeather); } private ForecastWeather ForecastWeatherParser(string remoteForecastWeatherData) @@ -240,29 +220,28 @@ namespace WeatherInformation private WeatherData WeatherDataParser(string JSONRemoteForecastWeather, string JSONRemoteCurrentWeather) { - ForecastWeather forecastWeather = null; - if (!string.IsNullOrEmpty(JSONRemoteForecastWeather)) + if (string.IsNullOrEmpty(JSONRemoteForecastWeather)) { - forecastWeather = ForecastWeatherParser(JSONRemoteForecastWeather); + throw new ArgumentException("Missing argument", "JSONRemoteForecastWeather"); } - - CurrentWeather currentWeather = null; - if (!string.IsNullOrEmpty(JSONRemoteCurrentWeather)) + if (string.IsNullOrEmpty(JSONRemoteCurrentWeather)) { - currentWeather = CurrentWeatherParser(JSONRemoteCurrentWeather); + throw new ArgumentException("Missing argument", "JSONRemoteCurrentWeather"); } return new WeatherData { - JSONRemoteCurrentWeatherData = JSONRemoteCurrentWeather, - JSONRemoteForecastWeatherData = JSONRemoteForecastWeather, - RemoteCurrentWeatherData = currentWeather, - RemoteForecastWeatherData = forecastWeather, + JSONRemoteCurrent = JSONRemoteCurrentWeather, + JSONRemoteForecast = JSONRemoteForecastWeather, + RemoteCurrent = CurrentWeatherParser(JSONRemoteCurrentWeather), + RemoteForecast = ForecastWeatherParser(JSONRemoteForecastWeather), WasThereRemoteError = false }; } - // TODO: temporary file :/ + // Temporary file? NO RIGHT WAY WITH WINDOWS :O Windows sucks? AFAIK YES. + // rename is not atomic (AFAIK) and destination file must not exist... ROFL + // Microsoft should learn from UNIX: http://thunk.org/tytso/blog/2009/03/15/dont-fear-the-fsync/ private void SaveDataToIsolatedStorage(string isoFileName, string value) { using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication()) @@ -272,8 +251,6 @@ namespace WeatherInformation sw.Write(value); fileStream.Flush(true); } - - IsolatedStorageSettings.ApplicationSettings["DataLastSavedTime"] = DateTime.Now; } @@ -296,21 +273,27 @@ namespace WeatherInformation } // Coming from TOMBSTONED + WeatherData weatherData = null; + // Check to see if the key for the application state data is in the State dictionary. string JSONRemoteForecastWeather = null; - if (PhoneApplicationService.Current.State.ContainsKey("JSONRemoteForecastWeatherData")) + string JSONRemoteCurrentWeather = null; + if (PhoneApplicationService.Current.State.ContainsKey("JSONRemoteForecastWeather") && + PhoneApplicationService.Current.State.ContainsKey("JSONRemoteCurrentWeather")) { // If it exists, assign the data to the application member variable. - JSONRemoteForecastWeather = PhoneApplicationService.Current.State["JSONRemoteForecastWeatherData"] as string; + JSONRemoteForecastWeather = PhoneApplicationService.Current.State["JSONRemoteForecastWeather"] as string; + + // If it exists, assign the data to the application member variable. + JSONRemoteCurrentWeather = PhoneApplicationService.Current.State["JSONRemoteCurrentWeather"] as string; } - string JSONRemoteCurrentWeather = null; - if (PhoneApplicationService.Current.State.ContainsKey("JSONRemoteCurrentWeatherData")) + + if (!string.IsNullOrEmpty(JSONRemoteCurrentWeather) && !string.IsNullOrEmpty(JSONRemoteForecastWeather)) { - // If it exists, assign the data to the application member variable. - JSONRemoteCurrentWeather = PhoneApplicationService.Current.State["JSONRemoteCurrentWeatherData"] as string; + weatherData = WeatherDataParser(JSONRemoteForecastWeather, JSONRemoteCurrentWeather); } - ApplicationDataObject = WeatherDataParser(JSONRemoteForecastWeather, JSONRemoteCurrentWeather); + ApplicationDataObject = weatherData; } // Código para ejecutar cuando la aplicación se desactiva (se envía a segundo plano) @@ -321,21 +304,22 @@ namespace WeatherInformation var weatherData = ApplicationDataObject; if (weatherData != null) { - if (!string.IsNullOrEmpty(weatherData.JSONRemoteForecastWeatherData)) + if (!string.IsNullOrEmpty(weatherData.JSONRemoteCurrent) && + !string.IsNullOrEmpty(weatherData.JSONRemoteForecast)) { // Store it in the State dictionary. - PhoneApplicationService.Current.State["JSONRemoteForecastWeatherData"] = weatherData.JSONRemoteForecastWeatherData; - + PhoneApplicationService.Current.State["JSONRemoteForecastWeather"] = weatherData.JSONRemoteForecast; + // Also store it in isolated storage, in case the application is never reactivated. - SaveDataToIsolatedStorage("JSONRemoteForecastWeatherDataFile.txt", weatherData.JSONRemoteForecastWeatherData); - } - if (!string.IsNullOrEmpty(weatherData.JSONRemoteCurrentWeatherData)) - { + SaveDataToIsolatedStorage("JSONRemoteForecastWeatherFile.txt", weatherData.JSONRemoteForecast); + // Store it in the State dictionary. - PhoneApplicationService.Current.State["JSONRemoteCurrentWeatherData"] = weatherData.JSONRemoteCurrentWeatherData; + PhoneApplicationService.Current.State["JSONRemoteCurrentWeather"] = weatherData.JSONRemoteCurrent; // Also store it in isolated storage, in case the application is never reactivated. - SaveDataToIsolatedStorage("JSONRemoteCurrentWeatherDataFile.txt", weatherData.JSONRemoteCurrentWeatherData); + SaveDataToIsolatedStorage("JSONRemoteCurrentWeatherFile.txt", weatherData.JSONRemoteCurrent); + + IsolatedStorageSettings.ApplicationSettings["DataLastSavedTime"] = DateTime.Now; } } } @@ -349,15 +333,16 @@ namespace WeatherInformation var weatherData = ApplicationDataObject; if (weatherData != null) { - if (!string.IsNullOrEmpty(weatherData.JSONRemoteForecastWeatherData)) + if (!string.IsNullOrEmpty(weatherData.JSONRemoteForecast) && + !string.IsNullOrEmpty(weatherData.JSONRemoteCurrent)) { // Also store it in isolated storage, in case the application is never reactivated. - SaveDataToIsolatedStorage("JSONRemoteForecastWeatherDataFile.txt", weatherData.JSONRemoteForecastWeatherData); - } - if (!string.IsNullOrEmpty(weatherData.JSONRemoteCurrentWeatherData)) - { + SaveDataToIsolatedStorage("JSONRemoteForecastWeatherFile.txt", weatherData.JSONRemoteForecast); + // Also store it in isolated storage, in case the application is never reactivated. - SaveDataToIsolatedStorage("JSONRemoteCurrentWeatherDataFile.txt", weatherData.JSONRemoteCurrentWeatherData); + SaveDataToIsolatedStorage("JSONRemoteCurrentWeatherFile.txt", weatherData.JSONRemoteCurrent); + + IsolatedStorageSettings.ApplicationSettings["DataLastSavedTime"] = DateTime.Now; } } } diff --git a/WindowsPhone/WeatherInformation/WeatherInformation/MainPage.xaml.cs b/WindowsPhone/WeatherInformation/WeatherInformation/MainPage.xaml.cs index f61244f..9f244f5 100644 --- a/WindowsPhone/WeatherInformation/WeatherInformation/MainPage.xaml.cs +++ b/WindowsPhone/WeatherInformation/WeatherInformation/MainPage.xaml.cs @@ -14,14 +14,15 @@ namespace WeatherInformation { public partial class MainPage : PhoneApplicationPage { + private MainViewModel _mainViewModel; + private bool _isNewPageInstance = false; + // Constructor public MainPage() { InitializeComponent(); - - // Establecer el contexto de datos del control ListBox control en los datos de ejemplo - DataContext = App.MainViewModel; + _isNewPageInstance = true; // Set the event handler for when the application data object changes. // TODO: doing this, when is the GC going to release this object? I do not think it is going to be able... This is weird... @@ -40,7 +41,29 @@ namespace WeatherInformation // Cargar datos para los elementos MainViewModel protected override void OnNavigatedTo(NavigationEventArgs e) { - if (App.MainViewModel.IsThereCurrentLocation()) + base.OnNavigatedTo(e); + + // If _isNewPageInstance is true, the page constuctor has been called, so + // state may need to be restored. + if (_isNewPageInstance) + { + if (_mainViewModel == null) + { + _mainViewModel = new MainViewModel(); + } + + DataContext = _mainViewModel; + } + // Set _isNewPageInstance to false. If the user navigates back to this page + // and it has remained in memory, this value will continue to be false. + _isNewPageInstance = false; + + UpdateApplicationDataUI(); + } + + private void UpdateApplicationDataUI() + { + if (StoredLocation.IsThereCurrentLocation) { // If the application member variable is not empty, // set the page's data object from the application member variable. @@ -48,7 +71,7 @@ namespace WeatherInformation WeatherData weatherData = (Application.Current as WeatherInformation.App).ApplicationDataObject; if (weatherData != null && !StoredLocation.IsNewLocation) { - UpdateApplicationDataUI(); + UpdateUI(); } else { @@ -62,26 +85,29 @@ namespace WeatherInformation void MainPage_ApplicationDataObjectChanged(object sender, EventArgs e) { // Call UpdateApplicationData on the UI thread. - Dispatcher.BeginInvoke(() => UpdateApplicationDataUI()); + Dispatcher.BeginInvoke(() => UpdateUI()); } - void UpdateApplicationDataUI() + void UpdateUI() { // Set the ApplicationData and ApplicationDataStatus members of the ViewModel WeatherData weatherData = (Application.Current as WeatherInformation.App).ApplicationDataObject; - if (weatherData.WasThereRemoteError) + if (weatherData != null) { - MessageBox.Show( - AppResources.NoticeThereIsNotCurrentLocation, - AppResources.AskForLocationConsentMessageBoxCaption, - MessageBoxButton.OK); - return; - } - - App.MainViewModel.LoadData(weatherData); + if (weatherData.WasThereRemoteError) + { + MessageBox.Show( + AppResources.NoticeThereIsNotCurrentLocation, + AppResources.AskForLocationConsentMessageBoxCaption, + MessageBoxButton.OK); + return; + } - StoredLocation.IsNewLocation = false; + _mainViewModel.LoadData(weatherData); + + StoredLocation.IsNewLocation = false; + } } private void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e) diff --git a/WindowsPhone/WeatherInformation/WeatherInformation/Model/Services/StoredLocation.cs b/WindowsPhone/WeatherInformation/WeatherInformation/Model/Services/StoredLocation.cs index bec91c0..e2f682e 100644 --- a/WindowsPhone/WeatherInformation/WeatherInformation/Model/Services/StoredLocation.cs +++ b/WindowsPhone/WeatherInformation/WeatherInformation/Model/Services/StoredLocation.cs @@ -91,5 +91,19 @@ namespace WeatherInformation.Model.Services IsolatedStorageSettings.ApplicationSettings["IsNewLocation"] = value; } } + + public static bool IsThereCurrentLocation + { + get + { + if (IsolatedStorageSettings.ApplicationSettings.Contains("CurrentLatitude") && + IsolatedStorageSettings.ApplicationSettings.Contains("CurrentLongitude")) + { + return true; + } + + return false; + } + } } } diff --git a/WindowsPhone/WeatherInformation/WeatherInformation/Model/WeatherData.cs b/WindowsPhone/WeatherInformation/WeatherInformation/Model/WeatherData.cs index 649f212..183482d 100644 --- a/WindowsPhone/WeatherInformation/WeatherInformation/Model/WeatherData.cs +++ b/WindowsPhone/WeatherInformation/WeatherInformation/Model/WeatherData.cs @@ -10,24 +10,24 @@ namespace WeatherInformation.Model { public class WeatherData { - public ForecastWeather RemoteForecastWeatherData + public ForecastWeather RemoteForecast { get; set; } - public string JSONRemoteForecastWeatherData + public string JSONRemoteForecast { get; set; } - public CurrentWeather RemoteCurrentWeatherData + public CurrentWeather RemoteCurrent { get; set; } - public string JSONRemoteCurrentWeatherData + public string JSONRemoteCurrent { get; set; diff --git a/WindowsPhone/WeatherInformation/WeatherInformation/SelectedDatePage.xaml b/WindowsPhone/WeatherInformation/WeatherInformation/SelectedDatePage.xaml index 124fbfb..86271fc 100644 --- a/WindowsPhone/WeatherInformation/WeatherInformation/SelectedDatePage.xaml +++ b/WindowsPhone/WeatherInformation/WeatherInformation/SelectedDatePage.xaml @@ -54,10 +54,10 @@ - - + + - + @@ -96,7 +96,7 @@ - + diff --git a/WindowsPhone/WeatherInformation/WeatherInformation/SelectedDatePage.xaml.cs b/WindowsPhone/WeatherInformation/WeatherInformation/SelectedDatePage.xaml.cs index 132581a..8fd70ae 100644 --- a/WindowsPhone/WeatherInformation/WeatherInformation/SelectedDatePage.xaml.cs +++ b/WindowsPhone/WeatherInformation/WeatherInformation/SelectedDatePage.xaml.cs @@ -11,8 +11,8 @@ namespace WeatherInformation { public partial class SelectedDate : PhoneApplicationPage { - SelectedDateViewModel _selectedDateViewModel; - bool _isNewPageInstance = false; + private SelectedDateViewModel _selectedDateViewModel; + private bool _isNewPageInstance = false; public SelectedDate() { @@ -50,23 +50,26 @@ namespace WeatherInformation { WeatherData weatherData = (Application.Current as WeatherInformation.App).ApplicationDataObject; - if (weatherData.WasThereRemoteError) + if (weatherData != null) { - MessageBox.Show( - AppResources.NoticeThereIsNotCurrentLocation, - AppResources.AskForLocationConsentMessageBoxCaption, - MessageBoxButton.OK); - return; - } + if (weatherData.WasThereRemoteError) + { + MessageBox.Show( + AppResources.NoticeThereIsNotCurrentLocation, + AppResources.AskForLocationConsentMessageBoxCaption, + MessageBoxButton.OK); + return; + } - _selectedDateViewModel.LoadData(weatherData); + _selectedDateViewModel.LoadData(weatherData); - // TODO: Should I try to move this code to MainViewModel. It seems so but how? - // TODO: What if the address is not available? I should show something like "Address not found" by default... - string country = (string)IsolatedStorageSettings.ApplicationSettings["Country"]; - string city = (string)IsolatedStorageSettings.ApplicationSettings["City"]; - string cityCountry = String.Format(CultureInfo.InvariantCulture, "{0}, {1}", city, country); - this.TitleTextCityCountry.Title = cityCountry; + // TODO: Should I try to move this code to MainViewModel. It seems so but how? + // TODO: What if the address is not available? I should show something like "Address not found" by default... + string country = (string)IsolatedStorageSettings.ApplicationSettings["Country"]; + string city = (string)IsolatedStorageSettings.ApplicationSettings["City"]; + string cityCountry = String.Format(CultureInfo.InvariantCulture, "{0}, {1}", city, country); + this.TitleTextCityCountry.Title = cityCountry; + } } } } \ No newline at end of file diff --git a/WindowsPhone/WeatherInformation/WeatherInformation/ViewModels/MainViewModel.cs b/WindowsPhone/WeatherInformation/WeatherInformation/ViewModels/MainViewModel.cs index 8ca2a49..470d397 100644 --- a/WindowsPhone/WeatherInformation/WeatherInformation/ViewModels/MainViewModel.cs +++ b/WindowsPhone/WeatherInformation/WeatherInformation/ViewModels/MainViewModel.cs @@ -121,7 +121,7 @@ namespace WeatherInformation.ViewModels DateTime unixTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - var remoteForecastWeatherData = weatherData.RemoteForecastWeatherData; + var remoteForecastWeatherData = weatherData.RemoteForecast; if (remoteForecastWeatherData != null) { this.ForecastItems.Clear(); @@ -160,7 +160,7 @@ namespace WeatherInformation.ViewModels // TODO: nullables? // TODO: nullables para distinguir cuando hay datos o no. Ahora me llega 0 si no datos (supongo) cuando double/integer - var remoteCurrentWeatherData = weatherData.RemoteCurrentWeatherData; + var remoteCurrentWeatherData = weatherData.RemoteCurrent; if (remoteCurrentWeatherData != null) { var currentMaxTemp = ""; @@ -297,16 +297,6 @@ namespace WeatherInformation.ViewModels } - public bool IsThereCurrentLocation() - { - if (_settings.Contains("CurrentLatitude") && _settings.Contains("CurrentLongitude")) - { - return true; - } - - return false; - } - /// /// Get the current value of the setting, or if it is not found, set the /// setting to the default value. diff --git a/WindowsPhone/WeatherInformation/WeatherInformation/ViewModels/SelectedDateViewModel.cs b/WindowsPhone/WeatherInformation/WeatherInformation/ViewModels/SelectedDateViewModel.cs index 9cb6625..1fa3430 100644 --- a/WindowsPhone/WeatherInformation/WeatherInformation/ViewModels/SelectedDateViewModel.cs +++ b/WindowsPhone/WeatherInformation/WeatherInformation/ViewModels/SelectedDateViewModel.cs @@ -53,7 +53,7 @@ namespace WeatherInformation.ViewModels public void LoadData(WeatherData weatherData) { - var remoteForecastWeatherData = weatherData.RemoteForecastWeatherData; + var remoteForecastWeatherData = weatherData.RemoteForecast; WeatherInformation.Model.ForecastWeatherParser.List forecast = remoteForecastWeatherData.list[this.SelectedDateIndex]; DateTime unixTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);