i have a problem with the info of a JSON in Windows Phone.
I want to show if the app is running for the first time, and if not, don't show anything.
This is my function to show info on the JSON:
async void NavigationService_Navigated(object sender, NavigationEventArgs e)
{
if (e.IsNavigationInitiator
|| !e.IsNavigationInitiator && e.NavigationMode != NavigationMode.Back)
{
var navigationInfo = new
{
Mode = e.NavigationMode.ToString(),
From = this.BackStack.Any() ? this.BackStack.Last().Source.ToString() : string.Empty,
Current = e.Uri.ToString(),
};
var jsonData = Newtonsoft.Json.JsonConvert.SerializeObject(navigationInfo);
await this.currentApplication.Client.PageView(jsonData);
}
}
I want to add one more thing where is Mode, From and Current. I want to add IsFirstRun that give as True if it's the first time i open the app.
I've seen this for firstRun function, but i don't know how to put it in my code.
public static bool IsFirstRun()
{
if (!settings.Contains(FIRST_RUN_FLAG)) //First time running
{
settings.Add(FIRST_RUN_FLAG, false);
return true;
}
return false;
}
I need help... thanks!
It is pretty simple if you want to create a flag for First Run,
In App.xaml.cs
Look for a function named
// Code to execute when the application is launching (eg, from Start)
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
}
What we want to do is create a flag inside this function and only set it to true if it doesn't exist. Like so.
using System.IO.IsolatedStorage; // include this namespace in App.xaml.cs
// Code to execute when the application is launching (eg, from Start)
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
if (!IsolatedStorageSettings.ApplicationSettings.Contains("first_run"))
{
IsolatedStorageSettings.ApplicationSettings.Add("first_run", true);
}
else
{
// set the flag to flase
IsolatedStorageSettings.ApplicationSettings["first_run"] = false;
}
// save
IsolatedStorageSettings.ApplicationSettings.Save();
}
Now if you want to do something on first run all you have to do is check the settings again like so:
bool first_run = (bool) IsolatedStorageSettings.ApplicationSettings["first_run"];
For debugging cases you will probably want to remove the flag so it will hit first_run again by doing this
// remove the flag and save
IsolatedStorageSettings.ApplicationSettings.Remove("first_run");
IsolatedStorageSettings.ApplicationSettings.Save();
Related
If i run this code on console application:
static async Task Main(string[] _)
{
using var client = new WTelegram.Client();
var user = await client.LoginUserIfNeeded();
Console.WriteLine($"We are logged-in as {user.username ?? user.first_name + " " + user.last_name} (id {user.id})");
}
It will prompt interactively for App api_id and api_hash.
How can i Authorize user on winforms application?. So that i can input the api_id and api_hash through textbox
Edit: (Oct 2022) Latest version of the library has a simplified config system that makes it more easy to use in WinForms apps.
Please take a look at the example WinForms app provided in the repository that demonstrate how to proceed.
The original answer below is still valid but maybe more complex
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
First, you should read WTelegramClient FAQ #3:
3. How to use the library in a WinForms or WPF application
The library should work without a problem in a GUI application.
The difficulty might be in your Config callback when the user must enter the verification code or password, as you can't use Console.ReadLine here.
An easy solution is to call Interaction.InputBox("Enter verification code") instead.
This might require adding a reference (and using) to the Microsoft.VisualBasic assembly.
A more complex solution requires the use of a ManualResetEventSlim that you will wait for in Config callback,
and when the user has provided the verification_code through your GUI, you "set" the event to release your Config callback so it can return the code.
Here is an example solution for your Form class with a ManualResetEventSlim and textboxes:
using Microsoft.VisualBasic;
using TL;
private readonly ManualResetEventSlim _codeReady = new ManualResetEventSlim();
private WTelegram.Client _client;
private User _user;
string Config(string what)
{
switch (what)
{
case "api_id": return textBoxApiID.Text;
case "api_hash": return textBoxApiHash.Text;
case "phone_number": return textBoxPhone.Text;
case "verification_code":
_codeReady.Reset();
_codeReady.Wait();
return textBoxCode.Text;
case "password": return Interaction.InputBox("Enter 2FA password");
default: return null;
};
}
private void textBoxCode_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == '\r') // pressing Return in the textboxCode
{
_codeReady.Set();
e.Handled = true;
}
}
private async void buttonLogin_Click(object sender, EventArgs e)
{
buttonLogin.Enabled = false;
_client = new WTelegram.Client(Config);
_user = await _client.LoginUserIfNeeded();
MessageBox.Show("We are now connected as " + _user);
}
private async void buttonGetChats_Click(object sender, EventArgs e)
{
if (_user == null) { MessageBox.Show("You must complete the login first."); return; }
var chats = await _client.Messages_GetAllChats(null);
MessageBox.Show(string.Join("\n", chats.chats.Values.Where(c => c.IsActive)));
}
I am trying to parse some pois from a xml download from a server and I saw that it is done after the program continues in the main thread. I haven't found a way to solve it because I need it.
using System.Threading;
namespace XML_Parser
{
class XMLParserPOI_Wiki
{
private static XMLParserPOI_Wiki objSingle = new XMLParserPOI_Wiki();
public static XMLParserPOI_Wiki ObjSingle
{
get { return objSingle; }
set { objSingle = value; }
}
private List<POI> places;
public List<POI> Places
{
get { return places; }
}
private XMLParserPOI_Wiki()
{
}
public void parseWikitude(string url)
{
places = new List<POI>();
WebClient wc = new WebClient();
wc.DownloadStringCompleted += HttpsCompleted;
wc.DownloadStringAsync(new Uri(url));
}
private void HttpsCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
XDocument xdoc = XDocument.Parse(e.Result, LoadOptions.None);
XNamespace ns = "http://www.opengis.net/kml/2.2";
XNamespace ns2 = "http://www.openarml.org/wikitude/1.0";
var placemarkers = xdoc.Root.Descendants(ns + "Placemark");
places =
(from query in xdoc.Root.Descendants(ns + "Placemark")
select new POI
(
...
)).ToList();
System.Diagnostics.Debug.WriteLine("Lista");
System.Diagnostics.Debug.WriteLine(places.Count);
}
}
}
}
In my main class:
XMLParserPOI_Wiki parserXML = XMLParserPOI_Wiki.ObjSingle;
parserXML.parseWikitude("http://myurl.php");
System.Diagnostics.Debug.WriteLine("Lista de pois");
System.Diagnostics.Debug.WriteLine(parserXML.Places.Count);
for (int i = 0; i < parserXML.Places.Count; i++)
{
System.Diagnostics.Debug.WriteLine(parserXML.Places[i].getName());
}
It prints Lista de POis and 0, before Lista and X (number of pois)
I guess I should freeze main thread but I tried a couple of times with some examples and they didn't work.
Can you point me to any tutorial about this? More than get an answer I want to understand how to deal with this kind of operations
First of all, you don't want to block (freeze) the UI thread EVER!
This is called asynchronous programming. There are two things you can do to solve your problem (I recommend option 2!):
Use the classic callback model. You basically call some long operation on a background thread and give a function to it, to execute when the long operation is done. Here's how to do it in your case.
At the end of the HttpsCompleted method, invoke what you need on the UI Thread using:
Deployment.Current.Dispatcher.BeginInvoke(delegate() {
//The code here will be invoked on the UI thread
});
If you want to make the parseWikitude method reusable, you should pass an Action to it. This way you can call it from multiple places and tell it what to do on the UI thread when the parsing is done. Something like this:
public void parseWikitude(string url, Action callback) {
places = new List<POI>();
WebClient wc = new WebClient();
wc.DownloadStringCompleted += HttpsCompleted;
wc.DownloadStringAsync(new Uri(url), callback);
}
private void HttpsCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
...
var callback = (Action)e.UserState;
Deployment.Current.Dispatcher.BeginInvoke(callback);
}
}
//And then when you use it, you do it like that
parserXML.parseWikitude("http://myurl.php", delegate() {
//The code here will be executed on the UI thread, after the parsing is done
});
Use the (rather) new asnyc pattern in .NET. You should read about this, as it is one of the best features of .NET if you ask me. :) It basically does the callback thing automatically and makes the code a lot easier to read/maintain/work-with. Once you get used to it, that is.
Here's an example:
public Task<List<POI>> parseWikitude(string url) {
TaskCompletionSource<List<POI>> resultTaskSource = new TaskCompletionSource<List<POI>>();
WebClient wc = new WebClient();
wc.DownloadStringCompleted += HttpsCompleted;
wc.DownloadStringAsync(new Uri(url), resultTaskSource);
return resultTaskSource.Task;
}
private void HttpsCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
//If needed, run the code here in a background thread
//...
var resultTaskSource = (TaskCompletionSource<List<POI>>)e.UserState;
resultTaskSource.SetResult(places);
}
}
//And when you need to use it, do it like that (note, this must be invoked in an async method!)
var places = await parser.parseWikitude("http://myurl.php");
//The code here will be executed on the same thread when the parsing is done, but the thread will not be blocked while the download is happening.
So, these are the two ways you can handle it. Option one is old-school, classic and easy. Option two is the new and cool way of doing async stuff. It really is a must-know. Simplifies a lot of things once you get used to it.
P.S. Sorry if I got carried away. :D
I have a valid URL for a remote JPEG which I'm trying to load in the background. But I find I never get control back after invoking the BitmapImage() constructor. My question is, should this approach work, or should I pitch it all, load up BcpAsync project from NuGet and start working with WebClient asynch methods?
A sample URL for which it fails is
http://image.weather.com/images/maps/current/garden_june_720x486.jpg
It is valid. .UpdateAsync() references it from AppViewModel.Instance, it's not explicitly referenced here.
Here's the background agent:
protected override async void OnInvoke(ScheduledTask task)
{
AppViewModel.LoadData();
await AppViewModel.Instance.RemoteImageProxy.UpdateAsync();
AppViewModel.Instance.ImageUrl = AppViewModel.Instance.RemoteImageProxy.LocalFileUri;
AppViewModel.Instance.UpdateCount++;
PinnedTile.Update();
}
AppViewModel.SaveData();
#if DEBUG
ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(AppViewModel.Instance.BgAgentInterval));
#endif
NotifyComplete();
}
Here's the invoked method:
public Task<double> UpdateAsync() {
LastCheckedTime = DateTime.UtcNow;
CompletionTask = new TaskCompletionSource<double>();
// Not usually called on UI thread, not worth optimizing for that case here.
Deployment.Current.Dispatcher.BeginInvoke(() => { //todo determine whether System.Windows.Deployment.Dispatcher can be called from main app, or just bgAgent.
HelperImageControl = new Image();
HelperImageControl.Loaded += im_Loaded;
HelperImageControl.ImageFailed += im_ImageFailed;
HelperImageControl.ImageOpened += im_ImageOpened;
// breakpoint here
HelperImageControl.Source = new BitmapImage(SourceUri);
// stepping over the function, control does not return here. Nor are any of the above events fired.
});
return CompletionTask.Task; // this will be completed in one of the subsequent control events...
}
You need to call CompletionTask.SetResult(); to return control back to the caller method.
This works (I'm returning 100 in case of successful download because you set the task to return double).
TaskCompletionSource<double> CompletionTask;
public Task<double> UpdateAsync()
{
CompletionTask = new TaskCompletionSource<double>();
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
var HelperImageControl = new Image();
var bmp = new BitmapImage();
bmp.ImageOpened += bmp_ImageOpened;
bmp.ImageFailed += bmp_ImageFailed;
bmp.CreateOptions = BitmapCreateOptions.None;
bmp.UriSource = new Uri("http://image.weather.com/images/maps/current/garden_june_720x486.jpg", UriKind.Absolute);
HelperImageControl.Source = bmp;
});
return CompletionTask.Task;
}
void bmp_ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
CompletionTask.SetException(e.ErrorException);
}
void bmp_ImageOpened(object sender, RoutedEventArgs e)
{
CompletionTask.SetResult(100);
}
I have a list of theaters and I created a secondary tile from my application to navigate directly to specific theater. I pass the id of the theater in query string :
I load the theaters from a WCF service in the file "MainViewModel.cs"
In my home page, I have a list of theaters and I can navigate to a details page.
But when I want to navigate from the tile, I have an error...
The Tile :
ShellTile.Create(new Uri("/TheaterDetails.xaml?selectedItem=" + theater.idTheater, UriKind.Relative), tile, false);
My TheaterDetails page :
public partial class TheaterDetails : PhoneApplicationPage
{
theater theater = new theater();
public TheaterDetails()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
}
if (DataContext == null)
{
string selectedIndex = "";
if (NavigationContext.QueryString.TryGetValue("selectedItem", out selectedIndex))
{
int index = int.Parse(selectedIndex);
theater = (from t in App.ViewModel.Theaters
where t.idTheater == index
select t).SingleOrDefault();
DataContext = theater;
....
....
....
The error :
https://dl.dropboxusercontent.com/u/9197067/error.png
Like if the data were not loaded...
Do you have an idea where the problem come from ?
The solution could be easy but I am a beginner... Maybe it's because I load the data asynchronously and the application doesn't wait until it's done...
Thanks
EDIT :
My LoadData() method :
public void LoadData()
{
client.GetTheatersCompleted += new EventHandler<ServiceReference1.GetTheatersCompletedEventArgs>(client_GetTheatersCompleted);
client.GetTheatersAsync();
// Other get methods...
this.IsDataLoaded = true;
}
private void client_GetTheatersCompleted(object sender, ServiceReference1.GetTheatersCompletedEventArgs e)
{
Theaters = e.Result;
}
You should check to see which variable is actually null. In this case it looks to be Theaters (otherwise the error would have thrown earlier).
Since Theaters is populated from a web call it is most likely being called asynchronously, in other words when you return from LoadData() the data is not yet there (it's still waiting for the web call to come back), and is waiting for the web service to return its values.
Possible solutions:
Make LoadData() an async function and then use await LoadData(). This might require a bit of rewriting / refactoring to fit into the async pattern (general introduction to async here, and specific to web calls on Windows Phone here)
A neat way of doing this that doesn't involve hacks (like looping until the data is there) is to raise a custom event when the data is actually populated and then do your Tile navigation processing in that event. There's a basic example here.
So the solution that I found, thanks to Servy in this post : Using async/await with void method
I managed to use async/await to load the data.
I replaced my LoadData() method by :
public static Task<ObservableCollection<theater>> WhenGetTheaters(ServiceClient client)
{
var tcs = new TaskCompletionSource<ObservableCollection<theater>>();
EventHandler<ServiceReference1.GetTheatersCompletedEventArgs> handler = null;
handler = (obj, args) =>
{
tcs.SetResult(args.Result);
client.GetTheatersCompleted -= handler;
};
client.GetTheatersCompleted += handler;
client.GetTheatersAsync();
return tcs.Task;
}
public async Task LoadData()
{
var theatersTask = WhenGetTheaters(client);
Theaters = await theatersTask;
IsDataLoaded = true;
}
And in my page :
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
await App.ViewModel.LoadData();
}
I am trying to implement the MVVM patter for my WP7 Silverlight app and I am running into a problem with the async JSON Rest call. I moved into my ViewModel class the following two methods that were on my WP7 app Page.
public void FetchGames()
{
ObservableCollection<Game> G = new ObservableCollection<Game>();
//REST call in here
var webClient = new WebClient();
Uri uri = new Uri("http://www.somewebsite.com/get/games/league/" + league);
webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(OpenReadCompletedGames);
webClient.OpenReadAsync(uri);
}
private void OpenReadCompletedGames(object sender, OpenReadCompletedEventArgs e)
{
DataContractJsonSerializer ser = null;
ser = new DataContractJsonSerializer(typeof(ObservableCollection<Game>));
Games = ser.ReadObject(e.Result) as ObservableCollection<Game>;
this.IsDataLoaded = true;
}
Now the problem is that because it is an async call the following code does not work. The following code is on my app Page.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (NavigationContext.QueryString.TryGetValue("league", out league))
{
try
{
App.gViewModel.league = league;
App.gViewModel.FetchGames();
if(App.gViewModel.IsDataLoaded)
{
lbTeams.ItemsSource = App.gViewModel.Games;
}
}
catch ()
{
//error logging in here
}
}
}
Stepping thru the code shows that FetchGames is called then hits the next line ( if(App.gViewModel.IsDataLoaded)
) before the async call is finished. So IsDataLoaded is always false and I cant bind the listbox on the page.
Doing a lot of googleing I have some possible solutions but I am unable convert them to my particular problem. One is like this and it has to do with continuation passing style'. I couldn't get it to work tho and would greatly appreciate some help.
Thanks!
void DoSomethingAsync( Action<string> callback ) {
HttpWebRequest req; // TODO: build your request
req.BeginGetResponse( result => {
// This anonymous function is a closure and has access
// to the containing (or enclosing) function.
var response = req.EndGetResponse( result );
// Get the result string and call the callback
string resultString = null; // TODO: read from the stream
callback(resultString);
}, null );
}
This can be resolved by moving
lbTeams.ItemsSource = App.gViewModel.Games;
to the end of the OpenReadCompletedGames method. You'll need to use the Dispatcher to update the UI from here.
Dispatcher.BeginInvoke( () => { lbTeams.ItemsSource = App.gViewModel.Games; } );