I am creating my first windows store app and i have several web service calls during startup and also periodically through the app. However I have noticed that my app will ot start/crashes or just closes down when I don't have internet access because of the web serivice calls. I want my app to start up in normal way with some initial data and seem normal even when there is no internet access. The data I get from webservice are mostly weather data that I show in various textboxes and graphs.
The code below shows the webservice calls in my extended splash screen.
public sealed partial class ExtendedSplashScreen : Page
{
//parameterItem max1DayAgo = new parameterItem();
//parameterItem min1DayAgo = new parameterItem();
public ExtendedSplashScreen()
{
this.InitializeComponent();
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached. The Parameter
/// property is typically used to configure the page.</param>
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
string[] periodSelector = { "1DayAgo", "1WeekAgo", "1MonthAgo" };
string[] modeSelector = { "max", "min" };
string[] parameterSelector = { "umtTemp1", "umtWindSpeed", "umtAdjBaromPress", "umtRainRate" };
//Create a webservice object
ServiceReference.WebServiceSoapClient webServiceObj = new ServiceReference.WebServiceSoapClient();
//First we create an object that holds max data for yesterday
var getMax1DayAgoObj = await webServiceObj.GetSelectedMaxMinDataAsync(parameterSelector, periodSelector[0], modeSelector[0]);
//create an object that holds min data for yesterday
var getMin1DayAgoObj = await webServiceObj.GetSelectedMaxMinDataAsync(parameterSelector, periodSelector[0], modeSelector[1]);
//Save arrayOfValue and arrayOfUnit to a parameterItem object. these objects are created during startup
// and the can be accessed and updated by all methods in this page later we will see that maxMinButton_Click method
//for the maxMinButton will use these data
//create an object that holds max data for last week
var getMax1WekAgoObj = await webServiceObj.GetSelectedMaxMinDataAsync(parameterSelector, periodSelector[1], modeSelector[0]);
//create an object that holds min data for last week
var getMin1WekAgoObj = await webServiceObj.GetSelectedMaxMinDataAsync(parameterSelector, periodSelector[1], modeSelector[1]);
//create an object that holds max data for last month
var getMax1MonthAgoObj = await webServiceObj.GetSelectedMaxMinDataAsync(parameterSelector, periodSelector[2], modeSelector[0]);
//create an object that holds min data for last month
var getMin1MonthAgoObj = await webServiceObj.GetSelectedMaxMinDataAsync(parameterSelector, periodSelector[2], modeSelector[1]);
(App.Current as App).max1DayAgo.arrayOfValue = getMax1DayAgoObj.arrayOfValue;
(App.Current as App).max1DayAgo.arrayOfUnit = getMax1DayAgoObj.arrayOfUnit;
(App.Current as App).min1DayAgo.arrayOfValue = getMin1DayAgoObj.arrayOfValue;
(App.Current as App).min1DayAgo.arrayOfUnit = getMin1DayAgoObj.arrayOfUnit;
(App.Current as App).max1WeekAgo.arrayOfValue = getMax1WekAgoObj.arrayOfValue;
(App.Current as App).max1WeekAgo.arrayOfUnit = getMax1WekAgoObj.arrayOfUnit;
(App.Current as App).min1WeekAgo.arrayOfValue = getMin1WekAgoObj.arrayOfValue;
(App.Current as App).min1WeekAgo.arrayOfUnit = getMin1WekAgoObj.arrayOfUnit;
(App.Current as App).max1MonthAgo.arrayOfValue = getMax1MonthAgoObj.arrayOfValue;
(App.Current as App).max1MonthAgo.arrayOfUnit = getMax1MonthAgoObj.arrayOfUnit;
(App.Current as App).min1MonthAgo.arrayOfValue = getMin1MonthAgoObj.arrayOfValue;
(App.Current as App).min1MonthAgo.arrayOfUnit = getMin1MonthAgoObj.arrayOfUnit;
string[] startupData = new string[13];
startupData[0] = " " + (App.Current as App).max1DayAgo.arrayOfValue[0] + " " + (App.Current as App).max1DayAgo.arrayOfUnit[0]; // maxTemp
startupData[1] = " " + (App.Current as App).max1DayAgo.arrayOfValue[1] + " " + (App.Current as App).max1DayAgo.arrayOfUnit[1]; // maxWindSped
startupData[2] = " " + (App.Current as App).max1DayAgo.arrayOfValue[2] + " " + (App.Current as App).max1DayAgo.arrayOfUnit[2]; // maxAirPressure
startupData[3] = " " + (App.Current as App).max1DayAgo.arrayOfValue[3] + " " + (App.Current as App).max1DayAgo.arrayOfUnit[3];// maxRainfall
startupData[4] = " " + (App.Current as App).min1DayAgo.arrayOfValue[0] + " " + (App.Current as App).min1DayAgo.arrayOfUnit[0]; // minTemp
startupData[5] = " " + (App.Current as App).min1DayAgo.arrayOfValue[1] + " " + (App.Current as App).min1DayAgo.arrayOfUnit[1];// minWindSped
startupData[6] = " " + (App.Current as App).min1DayAgo.arrayOfValue[2] + " " + (App.Current as App).min1DayAgo.arrayOfUnit[2];// minAirPressure
startupData[7] = " " + (App.Current as App).min1DayAgo.arrayOfValue[3] + " " + (App.Current as App).min1DayAgo.arrayOfUnit[3];// minRainfall
// Main fields
// ServiceReference.WebServiceSoapClient webServiceObj = new ServiceReference.WebServiceSoapClient();
var getLatestTempObj = await webServiceObj.GetLatestDataAsync("umtTemp1");
var getLatestWindObj = await webServiceObj.GetLatestDataAsync("umtWindSpeed");
var getLatestwindDirObj = await webServiceObj.GetLatestDataAsync("umtAdjWinDir");
var getLatestairPressureObj = await webServiceObj.GetLatestDataAsync("umtAdjBaromPress");
startupData[8] = " " + getLatestTempObj.Value + " " + getLatestTempObj.Unit;//temperatureMainTxtBlock.Text
startupData[9] = " " + getLatestWindObj.Value + " " + getLatestWindObj.Unit;//temperatureMainTxtBlock.Text
startupData[10] = "" + getLatestwindDirObj.Value; //temperatureMainTxtBlock.Text
startupData[11] = " " + getLatestairPressureObj.Value + " " + getLatestairPressureObj.Unit;//temperatureMainTxtBlock.Text
startupData[12] = "Last update: " + getLatestwindDirObj.Timestamp;//temperatureMainTxtBlock.Text
//save the startup data to the global variables
(App.Current as App).NavigateData = startupData;
this.Frame.SetNavigationState(e.Parameter as string);
this.Frame.Navigate(typeof(MainPage));
}
}
An approach we have in some of our team based apps is prior to any call to return data of the net, the network status is checked. Example:
async Task RefreshFromWeb(...)
{
if (!App.HasInternetAccess)
{
await new Windows.UI.Popups.MessageDialog(Strings.NoInternetWarning).ShowAsync();
return;
}
//attempt access here
}
public static bool HasInternetAccess
{
get
{
var profile = Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile();
if (profile == null)
return false;
return profile.GetNetworkConnectivityLevel() ==
Windows.Networking.Connectivity.NetworkConnectivityLevel.InternetAccess;
}
}
We also took another approach at times which was very similar but uses await and returns true or false (the same could easily be done above, that approach above just gives the dialog)
public static async System.Threading.Tasks.Task HasInternet()
{
var profile = Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile();
var hasNetAccess = profile != null;
if (!hasNetAccess)
await new Windows.UI.Popups.MessageDialog(
content: InfoHub.AppHubViewModel.Strings.NoInternetWarning,
title: InfoHub.AppHubViewModel.Strings.NoInternetWarning).ShowAsync();
return hasNetAccess;
}
async void YourControlEvent_Click(object sender, ItemClickEventArgs e)
{
//if net access, do your stuff, otherwise ignore for now
if (await IsInternet())
{
//do net calls here
}
}
You need to implement some exception handling around this line:
ServiceReference.WebServiceSoapClient webServiceObj = new ServiceReference.WebServiceSoapClient();
and implement a fallback that will work in off-line mode, i.e. retrieve data from a cache.
You can use NetworkStatusChanged event in App.xaml.cs and then you can declare one static variable and use it to check whether Internet is available or not. If Internet is available do your desired operation otherwise show error message.
public static bool IsInternetAvailable;
void NetworkInformation_NetworkStatusChanged(object sender)
{
if (NetworkInformation.GetInternetConnectionProfile() != null)
App.IsInternetAvailable = true;
else
App.IsInternetAvailable = false;
}
Always use try catch blocks, when you have probability of exception.
Related
I have a piece of code which requires me to use a process, but i want that to run in background and not open console window.
public uint LaunchProcess(string sIPAddress, string sPort)
{
uint iPid = 0;
try
{
logger.AddLog("LaunchProcess : " + sIPAddress + " " + sPort);
object[] PlugInRunnerInfo = { StaticUtils.GetLocation(AgilentPluginCommonConstants.PlugInRunnerPath) + "\\" + "PlugInRunner.exe" + " " + sIPAddress + " " + sPort, null, null, 0 };
//ManagementClass is a part of Windows Management Intrumentation,namespaces. One of its use is to provides access to manage applications.
//Here this class is used to launch PlugInRunner as detached process.By setting the ManagementClass object's property 'CreateFlags' to value 0x00000008
//we can start the PlugInRunner as detached one.
using (var mgmtObject = new ManagementClass("Win32_Process"))
{
var processStartupInfo = new ManagementClass("Win32_ProcessStartup");
processStartupInfo.Properties["CreateFlags"].Value = 0x00000008;//DETACHED_PROCESS.
var result = mgmtObject.InvokeMethod("Create", PlugInRunnerInfo);
if (result != null)
{
logger.AddLog("Process id " + Convert.ToUInt32(PlugInRunnerInfo[3]));
iPid = Convert.ToUInt32(PlugInRunnerInfo[3]);
}
}
}
catch (Exception ex)
{
logger.AddLog("Exception " + ex.Message);
}
return iPid;
}
Above is my code, can anyone help me run the process in background?
I have the code below:
if (jumlahiddb < jumlahbuku)
{
DownloadBukuKomik(url);
string KomikUpdate = #"INSERT INTO books (id,title,folder_id,identifier) SELECT " + intID + ",'" + namaFile + ".pdf',67,'" + namaFile +
".pdf' WHERE not exists (select id AND title AND folder_id AND identifier FROM books WHERE id=" + intID + " and title='" + namaFile +
".pdf' AND folder_id=67 and identifier='" + namaFile + ".pdf')";
Debug.WriteLine(KomikUpdate.ToString());
var komikQuery = objConnUpdate.Prepare(KomikUpdate);
komikQuery.Step();
}
else
{
bool shown = false;
if (!shown)
{
MessageDialog messageDialog1 = new MessageDialog("Jumlah komik bertambah sebanyak " + jumlahbuku + " komik pada menu Komik Pendidikan", "Update Berhasil");
messageDialog1.Commands.Add(new UICommand("OK", (command) =>
{
DownloadBukuVideo.IsOpen = false;
Downloading.IsOpen = false;
ukomikBtn.Visibility = Visibility.Visible;
downloadKomikBtn.Visibility = Visibility.Collapsed;
ukomikText.Visibility = Visibility.Collapsed;
ukomikText.Text = "";
shown = true;
}));
await messageDialog1.ShowAsync();
}
I have a problem, that is when I click the OK button, it will display message dialog again. I want message dialog shown only 1 time. How to solve it?
The problem is that you are declaring the shown variable in a local scope, so it is being initialised and set every time your show message box code is run.
To avoid this, declare it at a higher level - for instance, at class level. For example, based on the code you shared in the comments:
class myClass {
private bool _shown;
public async void KomikMsgDialog()
{
if (!_shown) // If we haven't shown the dialog yet
{
MessageDialog messageDialog1 = new MessageDialog("Jumlah komik bertambah sebanyak " + jumlahbuku + " komik pada menu Komik Pendidikan", "Update Berhasil");
messageDialog1.Commands.Add(new UICommand("OK", (command) =>
{
DownloadBukuVideo.IsOpen = false;
Downloading.IsOpen = false;
ukomikBtn.Visibility = Visibility.Visible;
downloadKomikBtn.Visibility = Visibility.Collapsed;
ukomikText.Visibility = Visibility.Collapsed;
ukomikText.Text = "";
}));
await messageDialog1.ShowAsync();
_shown = true; // Flag the dialog as having been shown
}
}
}
This way, the first time you call the method it will check whether the the dialog has been shown, which it won't have been, so it will show the dialog and flag it as having been shown. The next time it will check the flag and not show the dialog.
I have managed to store data, but I can't retrieve it and i would be so grateful if someone could just help me get at least 1 example working.
First I am storing data when the user signs up:
public void SetupNewParseMember(ParseUser user)
{
ParseObject gameScore = new ParseObject("GameScore");
gameScore["cash"] = 500;
gameScore["playerName"] = user.Username;
gameScore["HighestCash"] = 500;
gameScore["GamesPlayed"] = 0;
Task saveTask = gameScore.SaveAsync();
}
This works fine, I can see the data in parse and all seems ok..
The problem is when i try to retrieve the objects.
public void SetupMainScreen(ParseUser user)
{
var query = ParseObject.GetQuery("GameScore").WhereEqualTo("playerName", user.Username);
query.FindAsync().ContinueWith(t =>
{
IEnumerable<ParseObject> results = t.Result;
List<ParseObject> resultsList = results.ToList();
DealWithResults(resultsList, user);
});
}
public void DealWithResults(List<ParseObject> resultsList, ParseUser me)
{
userGamesPlayed = resultsList[1].Get<int>("GamesPlayed");
userHighestCash = resultsList[2].Get<int>("HighestCash");
userCash = resultsList[3].Get<int>("Cash");
WelcomeText.text = "Welcome, " + me.Username + "\n" +
"Cash: $" + userCash + "\n" +
"Highest Cash: $" + userHighestCash + "\n" +
"Games Played: " + userGamesPlayed;
}
First I tried just making changes to the unity ui from inside the Query but that did not work, So i made an outside function and passed the results to it that way, and that still does not work?
I tried to debug what i was getting in the list with this:
foreach (var res in resultsList)
{
Debug.Log("Class Name = " + res.ClassName + "| Keys are: " + res.Keys);
}
But all it returned was:
Class Name = GameScore| Keys are: System.Collections.Generic.Dictionary`2+KeyCollection[System.String,System.Object]
Can anyone offer any insights?
EDIT2:
ok so first i found results list and its contents
http://i.imgur.com/IKcBbey.png
Then if i open it, it seems to be null ref?
http://i.imgur.com/VmSpi9c.png
But if i go digging, i found the info i need all the way down here
http://i.imgur.com/1Wwu5uc.png
Now just need to work out how to get it?
As there is only one set of data it is always accessible through resultsList[0]. What you want is:
double cash = (double)resultsList[0]["cash"];
string playerName = (string)resultsList[0]["playerName"];
double highestCash = (double)resultsList[0]["HighestCash"];
int gamesPlayed = (int)resultsList[0]["GamesPlayed"];
Though you probably want to check that resultsList is not null and contains one element before you try to dereference it.
Also as your ParseObject appears to be a Dictionary you might find this MSDN page useful.
Ended up solving it.. Much different to the examples...
I had to make a coroutine that called a function on callback to access the variables outside of the query.
I called it with
StartCoroutine(SetupMainScreen(me, DealWithResults));
then called this.
public IEnumerator SetupMainScreen(ParseUser user, Action<GameScore> callback)
{
var query = ParseObject.GetQuery("GameScore").WhereEqualTo("playerName", user.Username).FirstOrDefaultAsync();
while (!query.IsCompleted)
{
yield return null;
}
if (query.IsFaulted || query.IsCanceled)
{
Debug.Log("Getting of GameScores faulted or cancelled...");
}
else
{
var obj = query.Result;
if (obj != null)
callback(new GameScore(obj.Get<int>("cash"),obj.Get<string>("playerName"),obj.Get<int>("HighestCash"),obj.Get<int>("GamesPlayed")));
}
}
public void DealWithResults(GameScore gs)
{
WelcomeText.text = "Welcome, " + gs.Username + "\n" +
"Cash: $" + gs.Cash + "\n" +
"Highest Cash: $" + gs.HighestCash + "\n" +
"Games Played: " + gs.GamesPlayed;
}
And i just made a class to hold the objects.. Hopefully this helps someone else.
I have the following code
async void getLocation1()
{
try {
var geolocator = new Geolocator();
Geoposition position = await geolocator.GetGeopositionAsync();
// reverse geocoding
BasicGeoposition myLocation = new BasicGeoposition
{
Longitude = position.Coordinate.Longitude,
Latitude = position.Coordinate.Latitude
};
Geopoint pointToReverseGeocode = new Geopoint(myLocation);
MapLocationFinderResult result = await MapLocationFinder.FindLocationsAtAsync(pointToReverseGeocode);
// here also it should be checked if there result isn't null and what to do in such a case
PostalCode1 = result.Locations[0].Address.PostCode;
Country1 = result.Locations[0].Address.Country;
City1 = result.Locations[0].Address.Town;
State1 = result.Locations[0].Address.Region;
guardarLatit = myLocation.Latitude.ToString();
guardarLong = myLocation.Longitude.ToString();
await GeolocationWait();
MessageDialog msgbox3 = new MessageDialog("Latitud: " + guardarLatit + "Longitud: " + guardarLong);
MessageDialog msgbox4 = new MessageDialog("PostalCode: " + PostalCode1 + " Country: " + Country1 + "City: " + City1 + "State: " + State1);
geolocation.Add("Latitud: " + guardarLatit);
geolocation.Add("Longitud: " + guardarLong);
geolocation.Add("PostalCode: " + PostalCode1);
geolocation.Add("Country: " + Country1);
geolocation.Add("City: " + City1);
geolocation.Add("State: " + State1);
await msgbox3.ShowAsync();
await msgbox4.ShowAsync();
} catch (Exception ex)
{
MessageDialog msgboxE = new MessageDialog("Error");
await msgboxE.ShowAsync();
geolocation.Add("Latitud: null");
geolocation.Add("Longitud: null");
geolocation.Add("PostalCode: null");
geolocation.Add("Country: null");
geolocation.Add("City: null");
geolocation.Add("State: null");
}
}
but I need to do it in the same method without the asynchronous method return values I certainly would be some way to tell me all my asynchronous it stops to get that values.
My problem is that when I print the longitude and latitude zero throws me because of what the asynchronous method sends the values certainly not on time.
Thank you
Ok, so first of all you need to know that you shouldn't use async void.
It is a construction that allows you to use await inside it, but if you await getLocation1() your program will not wait for it.
Instead, you should always use async Task when it's possible. So please try to change getLocation1 to async Task and then, when you await it, after that you will be sure of completed tasks inside of it.
I am fairly new to C# and I have written several functioning programs, but all of them have been single thread applications. This is my first multi-threaded application and I am struggling to resolve this "Cross-thread operation not valid: Control 'cbLogType' accessed from a thread other than the one it was created on" error. My application searches Windows Event viewer for a user defined Event ID in a user defined Event Log Source(cbLogType). I am using a backgroundworker process to do all the work and I am using the worker.reportprogress to update a label, however, I receive the above error when debugging. I have tried several Invoke methods, but none seem to resolve my error. I have also tried removing the combobox and setting the Log Source directly in the code, which works to an extent, but still fails. I have included my code and any help would be greatly appreciated. I suspect that I might not be using the Invoke method correctly. Thanks in advance!
CODE:
private void bgWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
{
if (File.Exists(#"C:\Events.log"))
MessageBox.Show("File 'Events.log' already exists. All new data will be appended to the log file!", "Warning!");
string message = string.Empty;
string eventID = (tbEventID.Text);
string text;
EventLog eLog = new EventLog();
Invoke((MethodInvoker)delegate() { text = cbLogType.Text; });
eLog.Source = (this.cbLogType.Text); // I am receiving the error here
eLog.MachineName = ".";
int EventID = 0;
string strValue = string.Empty;
strValue = tbEventID.Text.Trim();
//string message = string.Empty;
EventID = Convert.ToInt32(strValue); // Convert string to integer
foreach (EventLogEntry entry in eLog.Entries)
{
int entryCount = 1;
if (cbDateFilter.Checked == true)
{
if (entry.TimeWritten > dtPicker1.Value && entry.TimeWritten < dtPicker2.Value)
if (entry.InstanceId == EventID)
message = "Event entry matching " + (tbEventID.Text) + " was found in " + (cbLogType.Text);
using (StreamWriter writer = new StreamWriter(#"C:\Events.log", true))
writer.WriteLine("EventID: " + entry.InstanceId +
"\r\nDate Created: " + entry.TimeWritten +
"\r\nEntry Type: " + entry.EntryType +
"\r\nMachinename: " + entry.MachineName +
"\r\n" +
"\r\nMessage: " + entry.Message +
"\r\n");
if (entry.InstanceId != EventID)
message = "No event ids matching " + (tbEventID.Text) + " was found in " + (cbLogType.Text);
}
else
{
if (cbDateFilter.Checked == false)
{
if (entry.InstanceId == EventID)
using (StreamWriter writer = new StreamWriter(#"C:\Events.log", true))
writer.WriteLine("EventID: " + entry.InstanceId +
"\r\nDate Created: " + entry.TimeWritten +
"\r\nEntry Type: " + entry.EntryType +
"\r\nMachinename: " + entry.MachineName +
"\r\n" +
"\r\nMessage: " + entry.Message +
"\r\n");
else if (entry.InstanceId != EventID)
message = "No event ids matching " + (tbEventID.Text) + " was found in " + (cbLogType.Text);
}
bgWorker1.ReportProgress((entryCount) * 10, message);
entryCount++;
}
}
}
}
private void bgWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
lblStat.Text = e.UserState.ToString();
}
You're accessing cbLogType in a non-UI thread.
Change to
eLog.Source = text;