Can someone point me in the right direction to find out how to correctly monitor when files change in the app iCloud container? I've based my code on Apple and other iCloud tutorials I've reviewed, but none of them deal with updates to the iCloud container, just using initial queries. I've been working on this for three weeks now with no success. I use UIDocument in an app saving to the app iCloud container. Since UIDocument sends no notice when a document is added, I can't update the app on another iOS device when the app is running on multiple devices. Changing and deleting a document works fine by monitoring the UIDocument UIDocumentStateChangedNotification.
I use a query to initially check the iCloud container when the app starts or resumes from the background which works fine to get all files in the iCloud container on the device, including any documents added while the app was not active. I disable updates to process the query results when NSMetadataQueryDidFinishGatheringNotification is posted, then enable updates on the query. Sometimes I get one or two update notices shortly after enabling updates from NSMetadataQueryDidUpdateNotification being posted, but that is all. Never any further update notices and never from a document being added to the iCloud container.
I understand the code for iCloud use is somewhat complex, I don't expect anyone to examine my code (I've provided an excerpt for reference) to correct it. I'd appreciate it if someone can point me to more information on the specifics of tracking iCloud container changes during app execution.
Thanks,
Fred
Code excerpt for starting query:
-(void)loadDocument {
// set iCloud URL to nil for local storage to start
NSURL *ubiq = nil;
// if iCloud is selected get the iCloud container URL
if ([_useiCloud isEqualToString:#"YES"]) {
// get the app iCloud container URL
ubiq = DefaultMemoDataController.iCloudContainerURL;
}
// if iCloud URL is available and user chooses to use iCloud, set the query for app memo file names
if (ubiq) {
// adding to see if not creating another query prevents crash resuming from background
if (!self.query) {
self.query = [[NSMetadataQuery alloc] init];
}
// set the scope of the query to look in iCloud documents
[self.query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
// set search to look for a group of file names by setting up a predicate
// use the note file name format for the app
NSPredicate *pred = [NSPredicate predicateWithFormat:#"%K like 'FOLMemo_*'", NSMetadataItemFSNameKey];
// set the query to search with the predicate.
[self.query setPredicate:pred];
// set up a notification when the query is complete because the query is an asynchronous call (off the main queue)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(queryDidFinishGathering:)
name:NSMetadataQueryDidFinishGatheringNotification
object:self.query];
// start the query.
[self.query startQuery];
// not sure this is needed, but want to make sure same query is started again for updates.
DefaultMemoDataController.query = self.query;
}
}
code when query completes
-(void)queryDidFinishGathering:(NSNotification *)notification {
// stop the query while processing the query results to prevent changes while processing
NSMetadataQuery *query = [notification object];
[query disableUpdates];
// not sure is needed but want to make sure resume updates on same query
DefaultMemoDataController.query = query;
// stop looking for query did finish notifications since the query was completed.
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSMetadataQueryDidFinishGatheringNotification
object:query];
// start looking for query updates
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(processQueryUpdate:)
name:NSMetadataQueryDidUpdateNotification
object:query];
// load the data from the query
[self loadData:query];
}
code to process query:
-(void)loadData:(NSMetadataQuery *)query {
// add all the memos from the query results to the app memos dictionary
for (NSMetadataItem *item in [query results]) {
// get the URL for the memo
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
// load the memo text from the url
FOLMemoDoc *doc = [[FOLMemoDoc alloc] initWithFileURL:url];
// open the note
[doc openWithCompletionHandler:^(BOOL success) {
if (success) {
// add the memo UIDocument object to the memo dictionary
// need temp dictionary since can't change a property dictionary for some reason
NSMutableDictionary * tempDict = [NSMutableDictionary dictionaryWithDictionary:DefaultMemoDataController.masterMemoDictionary];
[tempDict setObject:doc forKey:doc.memoDictionaryKey];
DefaultMemoDataController.masterMemoDictionary = [NSMutableDictionary dictionaryWithDictionary:tempDict];
NSNotification *notice = [NSNotification notificationWithName:kFlashofLightUpdateMemoNotice
object:doc];
[[NSNotificationCenter defaultCenter] postNotification:notice];
} else {
// failed to open document, should probably alert the user
}
}];
}
// enable query updates
[query enableUpdates];
}
After another week's experimentation I got query updates for the iCloud container working by adding a property to my persistent dataController object for the query object. By replacing each query reference in my previous code with the persistent dataController property, keeping the observer for the finished query (NSMetadataQueryDidFinishGatheringNotification) and never stopping the query, query updates now works (NSMetadataQueryDidUpdateNotification). The app receives a NSMetadataQueryDidUpdateNotification notification for every change to the app iCloud container. Multiple notices are received at times, but I have not come across a time when a notice is not posted, so I can now catch all real time updates on all devices running the app.
Here are the revised code extracts from above. This code requires other methods and set-up that is not included, so it will not run stand alone, but shows the changes I had to make to get NSMetadataQueryDidUpdateNotification notifications working in my app.
Code excerpt for starting query:
-(void)loadDocument {
// set iCloud URL to nil for local storage to start
NSURL *ubiq = nil;
// if iCloud is selected get the iCloud container URL
if ([_useiCloud isEqualToString:#"YES"]) {
// get the app iCloud container URL
ubiq = DefaultMemoDataController.iCloudContainerURL;
}
// if iCloud URL is available and user chooses to use iCloud, set the query for app memo file names
if (ubiq) {
// adding to see if not creating another query prevents crash resuming from background
if (!DefaultMemoDataController.query) {
DefaultMemoDataController.query = [[NSMetadataQuery alloc] init];
}
// set the scope of the query to look in iCloud documents
[DefaultMemoDataController.query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
// set search to look for a group of file names by setting up a predicate
// use the note file name format for the app
NSPredicate *pred = [NSPredicate predicateWithFormat:#"%K like 'FOLMemo_*'", NSMetadataItemFSNameKey];
// set the query to search with the predicate.
[DefaultMemoDataController.query setPredicate:pred];
//remove observer to make sure no duplicate observers
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSMetadataQueryDidFinishGatheringNotification
object:DefaultMemoDataController.query];
// set up a notification when the query is complete because the query is an asynchronous call (off the main queue)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(queryDidFinishGathering:)
name:NSMetadataQueryDidFinishGatheringNotification
object:DefaultMemoDataController.query];
// remove observer to make sure no duplicate observers
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSMetadataQueryDidUpdateNotification
object:DefaultMemoDataController.query];
// set observer for query update
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(processQueryUpdate:)
name:NSMetadataQueryDidUpdateNotification
object:DefaultMemoDataController.query];
// start the query.
[DefaultMemoDataController.query startQuery];
}
code when query initially completes:
-(void)queryDidFinishGathering:(NSNotification *)notification {
// disable the query while processing the query results to prevent changes while processing
DefaultMemoDataController.query
NSMetadataQuery *query = [notification object];
[DefaultMemoDataController.query disableUpdates];
// call loadData with the query results
[self loadData:DefaultMemoDataController.query];
}
code to process query
-(void)loadData:(NSMetadataQuery *)query {
// add all the memos from the query results to the app memos dictionary
for (NSMetadataItem *item in [query results]) {
// get the URL for the memo
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
// load the memo text from the url
FOLMemoDoc *doc = [[FOLMemoDoc alloc] initWithFileURL:url];
// open the memo
[doc openWithCompletionHandler:^(BOOL success) {
if (success) {
// add the memo UIDocument object to the memo dictionary
// need temp dictionary since can't change a property dictionary for some reason
NSMutableDictionary * tempDict = [NSMutableDictionary dictionaryWithDictionary:DefaultMemoDataController.masterMemoDictionary];
[tempDict setObject:doc forKey:doc.memoDictionaryKey];
DefaultMemoDataController.masterMemoDictionary = [NSMutableDictionary dictionaryWithDictionary:tempDict];
// save the memo dictionary
[DefaultMemoDataController saveMemoDictionary];
NSNotification *notice = [NSNotification notificationWithName:kFlashofLightUpdateMemoNotice
object:doc];
[[NSNotificationCenter defaultCenter] postNotification:notice];
} else {
// failed to open document
// if there is a memo dictionary key available, delete the memo from master memo dictionary
if (doc.memoDictionaryKey) {
// delete memo from master memo dictionary
[DefaultMemoDataController.masterMemoDictionary removeObjectForKey:doc.memoDictionaryKey];
}
// get the dictionary key from the file name and try to delete it that way
else {
NSString * filename = [doc.fileURL lastPathComponent];
if (filename) {
[DefaultMemoDataController.masterMemoDictionary removeObjectForKey:filename];
}
}
}
}];
}
// enable query updates
[DefaultMemoDataController.query enableUpdates];
}
I hope this helps someone else.
Fred
Related
i am trying to track my icloud upload progress using NSMetadataQueryDidUpdateNotification..but it can't work... i don't know what the problem is..
here is my code for upload to icloud
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fileCoordinator coordinateReadingItemAtURL:backupUrl options:NSFileCoordinatorReadingWithoutChanges error:nil byAccessor:^(NSURL *newURL) {
NSFileManager* fm = [NSFileManager defaultManager];
NSError *theError = nil;
BOOL success =[fm setUbiquitous:YES itemAtURL:backupUrl destinationURL:[[ubiq URLByAppendingPathComponent:#"Documents" isDirectory:true] URLByAppendingPathComponent:bName] error:&theError];
if (!(success)) {
[progView dismiss];
UIAlertView* alertFail=[[UIAlertView alloc]initWithTitle:#"Backup Error" message:#"Could not backup to iCloud." delegate:Nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertFail show];
NSLog(#"iCloud error: %#", [theError localizedDescription]);
}
else{
[self loadNotes:bName];
}
}];
});
and this code for tracing my upload progress
- (void)loadNotes:(NSString *)bname {
self.alertQuery = [[NSMetadataQuery alloc] init];
[self.alertQuery setPredicate:[NSPredicate predicateWithFormat:#"%K LIKE %#", NSMetadataItemFSNameKey, bname]];
[self.alertQuery setSearchScopes:#[NSMetadataQueryUbiquitousDataScope]];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(liveupdate:) name:NSMetadataQueryDidUpdateNotification object:self.alertQuery];
[self.alertQuery startQuery];
}
-(void)liveupdate:(NSNotification *)note {
NSMetadataQuery* query=[note object];
if ([query resultCount]==0){
return;
}
NSMetadataItem* item=[query resultAtIndex:0];
float progress=[[item valueForAttribute:NSMetadataUbiquitousItemPercentUploadedKey]floatValue];
[progView.progBar setProgress:progress animated:NO];
if ([[item valueForAttribute:NSMetadataUbiquitousItemIsUploadedKey] boolValue]){
[query stopQuery];
[query disableUpdates];
_alertQuery=nil;
[progView dismiss];
}
}
what is the wrong with code...
can somebody tell me what is the best way to track icloud upload progress in NSFileManager setUbiquitous....
thank you...
You will probably want to observe the NSMetadataQueryDidFinishGatheringNotification notification, which fires first, with the initial set of results.
But even then, you may not get what you want, because the update notification will only fire if the set of results changes. You are searching for a particular file, and since that file is not being deleted or anything like that, your set of results will remain the same, even if the file uploads or downloads.
In my experience, NSMetadataQuery is not very effective for monitoring upload and download progress. You can hack it to almost work, but it is never exactly what you want.
Probably the best you can do is fire the metadata query, observe the finished-gathering notification, stop the query, and start the query again. Do this at regular intervals of a second or so, and you should be able to track the progress.
You should also consider whether you really want to track progress of an individual file. It will depend how large your files are. In many cases, you may be better to track the number of files to upload/download, or the total bytes remaining.
If this is the case, you can try to setup a metadata that includes a predicate with the uploaded/downloaded status included. This will continually fire notifications when a file finishes uploading/downloading. You can find an example of this here. Look for the method startMonitoringMetadata.
I'm trying to pull a list of connected users in Firebase to simply populate a select dropdown. My problem is that I can't seem to access the child objects properly.
Using connectedUsers.userName (see below code) works but only for my own user data, it doesn't pull anything else.
It seemed to me like changing "myUserRef.on" to "userListRef.on" and using something like "snapshot.child('userName').val()" should work but it just throws undefined. The same goes for "connectedUsers.child.userName", I'm sure I'm missing something simple here.
In the below code by changing to "userListRef.on('child_added', function(snapshot)" I can successfully add and remove user data from Firebase, and log all of the objects to the console and all data looks fine when I drill down the objects. I just need a way to access that data so I can put all connected users into a select dropdown or remove them from it when they disconnect.
var userListRef = new Firebase('https://myaccount.firebaseIO.com/users/');
var myUserRef = userListRef.push();
// ADD USER DATA TO FIREBASE
var userId = $('#myIdInput').val();
var userName = $('#nameInput').val();
myUserRef.push({userId: userId, userName: userName});
// READ USER OBJECTS AND FIRE ADDUSER FUNCTION
myUserRef.on('child_added', function(snapshot) {
var connectedUsers = snapshot.val();
console.log(addUser);
//addUser(connectedUsers.userId, connectedUsers.userName);
});
// ADD USER TO SELECT DROPDOWN
function addUser(userId, userName) {
var modSelect = $('#tsmmodsendto');
modSelect.append($('<option></option>').attr("value", userId).text(userName));
}
// READ USER OBJECTS AND FIRE REMOVEUSER FUNCTION
myUserRef.on('child_removed', function(snapshot) {
var connectedUsers = snapshot.val();
console.log(removeUser);
//removeUser(connectedUsers.userId, connectedUsers.userName);
});
// REMOVE USER TO SELECT DROPDOWN
function removeUser(userId, userName) {
var modSelect = $('#tsmmodsendto');
modSelect.append($('<option></option>').removeAttr("value", userId).text(userName));
}
// ON DISCONNECT REMOVE USER DATA FROM FIREBASE
myUserRef.onDisconnect().remove();
The code you've written won't work properly because each user is writing to:
/users/PUSH_ID/PUSH_ID
And is then listening at:
/users/PUSH_ID
So every client is going to be listening only to its own data and will never see anyone else's data. In order to view other people's data, you need to all be listening / writing to the same path.
In your question you mention you see "undefined" if you change to listening at /users. Could you simplify your code, and use that approach, and perhaps then I can provide a more helpful answer?
Or if I'm not understanding correctly, please simplify and clarify your question.
I am using JPA 3, with annotation (no mapping file) and with provider org.hibernate.ejb.HibernatePersistence
I need to have optimistic concurrency.
1)I tried to rely on the tag called , it did not work.
2)
So I decided to do it with java code. I have a mergeServiceRequest method and an object with type Request as follows: I start a transaction, lock the request object,
then try to get a Request object newRequest from database, compare its timestamp with the current one request. If they do not match, I throw an exception; if they match, then I update the current request enter code herewith current time and save it to database.
I need to lock the object manually, because by starting a transaction from session, it does not put a lock on the row in database. I wrote some java code which shows that a transaction does not lock the record in database automatically.
Problem with this approach is the query
Request newRequest=entityManager.createQuery("select r from Request r where serviceRequestId = " + request.getServiceRequestId());
always return same object as request. "request" is in the session entityManger, and the query always return what is cached in the session. I tried all the five query.setHint lines and I still get same result: no database query is performed, the result is from session cache directly.
#Transactional
public void mergeServiceRequest(Request request) {
System.out.println("ServiceRequestDao.java line 209");
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.lock(request, LockModeType.WRITE); // use to lock the database row
Query query = entityManager.createQuery("select r from Request r where serviceRequestId = " + request.getServiceRequestId());
//query.setHint("javax.persistence.cache.retrieveMode", "BYPASS");
//query.setHint("org.hibernate.cacheMode", CacheMode.REFRESH);
//query.setHint("javax.persistence.cache.retrieveMode", CacheMode.REFRESH);
//query.setHint("javax.persistence.retrieveMode", CacheMode.REFRESH);
//query.setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache);
Request newRequest=(Request)query.getSingleResult();
if (! newRequest.getLastUpdatedOn().equals(request.getLastUpdatedOn())) {
throw new StaleObjectStateException(request.getClass().toString(), request.getServiceRequestId());
}
request.setLastUpdatedOn(new Date(System.currentTimeMillis()));
entityManager.persist(request);
entityManager.flush();
transaction.commit();
}
3)So I also tried to use another session get query the newRequest, if I do that, the newRequest will be different from request. But for some reason, if I do that, then the lock on request object is never released, even after the transaction commit. Code looks like below
#Transactional
public void mergeServiceRequest(Request request) {
System.out.println("ServiceRequestDao.java line 209");
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.lock(request, LockModeType.WRITE); // use to lock the database row
Request newRequest=findRequest(request.getServiceRequestId()); // get it from another session
if (! newRequest.getLastUpdatedOn().equals(request.getLastUpdatedOn())) {
throw new StaleObjectStateException(request.getClass().toString(), request.getServiceRequestId());
}
request.setLastUpdatedOn(new Date(System.currentTimeMillis()));
entityManager.persist(request);
entityManager.flush();
transaction.commit();
//lock on the database record is not released after this, and even after entityManager is closed
}
Could anyone help me on this?
Thanks.
Daniel
I have a DS.Store which uses the DS.RESTAdapter and a ChatMessage object defined as such:
App.ChatMessage = DS.Model.extend({
contents: DS.attr('string'),
roomId: DS.attr('string')
});
Note that a chat message exists in a room (not shown for simplicity), so in my chat messages controller (which extends Ember.ArrayController) I only want to load messages for the room the user is currently in:
loadMessages: function(){
var room_id = App.getPath("current_room.id");
this.set("content", App.store.find(App.ChatMessage, {room_id: room_id});
}
This sets the content to a DS.AdapterPopulatedModelArray and my view happily displays all the returned chat messages in an {{#each}} block.
Now it comes to adding a new message, I have the following in the same controller:
postMessage: function(contents) {
var room_id = App.getPath("current_room.id");
App.store.createRecord(App.ChatMessage, {
contents: contents,
room_id: room_id
});
App.store.commit();
}
This initiates an ajax request to save the message on the server, all good so far, but it doesn't update the view. This pretty much makes sense as it's a filtered result and if I remove the room_id filter on App.store.find then it updates as expected.
Trying this.pushObject(message) with the message record returned from App.store.createRecord raises an error.
How do I manually add the item to the results? There doesn't seem to be a way as far as I can tell as both DS.AdapterPopulatedModelArray and DS.FilteredModelArray are immutable.
so couple of thoughts:
(reference: https://github.com/emberjs/data/issues/190)
how to listen for new records in the datastore
a normal Model.find()/findQuery() will return you an AdapterPopulatedModelArray, but that array will stand on its own... it wont know that anything new has been loaded into the database
a Model.find() with no params (or store.findAll()) will return you ALL records a FilteredModelArray, and ember-data will "register" it into a list, and any new records loaded into the database will be added to this array.
calling Model.filter(func) will give you back a FilteredModelArray, which is also registered with the store... and any new records in the store will cause ember-data to "updateModelArrays", meaning it will call your filter function with the new record, and if you return true, then it will stick it into your existing array.
SO WHAT I ENDED UP DOING: was immediately after creating the store, I call store.findAll(), which gives me back an array of all models for a type... and I attach that to the store... then anywhere else in the code, I can addArrayObservers to those lists.. something like:
App.MyModel = DS.Model.extend()
App.store = DS.Store.create()
App.store.allMyModels = App.store.findAll(App.MyModel)
//some other place in the app... a list controller perhaps
App.store.allMyModels.addArrayObserver({
arrayWillChange: function(arr, start, removeCount, addCount) {}
arrayDidChange: function(arr, start, removeCount, addCount) {}
})
how to push a model into one of those "immutable" arrays:
First to note: all Ember-Data Model instances (records) have a clientId property... which is a unique integer that identifies the model in the datastore cache whether or not it has a real server-id yet (example: right after doing a Model.createRecord).
so the AdapterPopulatedModelArray itself has a "content" property... which is an array of these clientId's... and when you iterate over the AdapterPopulatedModelArray, the iterator loops over these clientId's and hands you back the full model instances (records) that map to each clientId.
SO WHAT I HAVE DONE
(this doesn't mean it's "right"!) is to watch those findAll arrays, and push new clientId's into the content property of the AdapterPopulatedModelArray... SOMETHING LIKE:
arrayDidChange:function(arr, start, removeCount, addCount){
if (addCount == 0) {return;} //only care about adds right now... not removes...
arr.slice(start, start+addCount).forEach(function(item) {
//push clientId of this item into AdapterPopulatedModelArray content list
self.getPath('list.content').pushObject(item.get('clientId'));
});
}
what I can say is: "its working for me" :) will it break on the next ember-data update? totally possible
For those still struggling with this, you can get yourself a dynamic DS.FilteredArray instead of a static DS.AdapterPopulatedRecordArray by using the store.filter method. It takes 3 parameters: type, query and finally a filter callback.
loadMessages: function() {
var self = this,
room_id = App.getPath('current_room.id');
this.store.filter(App.ChatMessage, {room_id: room_id}, function (msg) {
return msg.get('roomId') === room_id;
})
// set content only after promise has resolved
.then(function (messages) {
self.set('content', messages);
});
}
You could also do this in the model hook without the extra clutter, because the model hook will accept a promise directly:
model: function() {
var self = this,
room_id = App.getPath("current_room.id");
return this.store.filter(App.ChatMessage, {room_id: room_id}, function (msg) {
return msg.get('roomId') === room_id;
});
}
My reading of the source (DS.Store.find) shows that what you'd actually be receiving in this instance is an AdapterPopulatedModelArray. A FilteredModelArray would auto-update as you create records. There are passing tests for this behaviour.
As of ember.data 1.13 store.filter was marked for removal, see the following ember blog post.
The feature was made available as a mixin. The GitHub page contains the following note
We recommend that you refactor away from using this addon. Below is a short guide for the three filter use scenarios and how to best refactor each.
Why? Simply put, it's far more performant (and not a memory leak) for you to manage filtering yourself via a specialized computed property tailored specifically for your needs
I'm working on an app that requires extracting data from an xml web service, then I want to store that data (images+titles+datetime ...) to display it on my app then select an item and navigate to another page that displays more info about this item.
Is there a detailed tutorial that explains the parsing and storing process clearly (with the threads) because I'm gonna need it a lot for my app.Thanks!
I usually use this method, but didn't always get me what i want:
var doc = XDocument.Load(new StringReader(e.Result));
var items = from c in doc.Descendants("item")
select new RSSitem()
{
Title = c.Element("title").Value,
Photo = c.Element("img").Attribute("src").Value,
Description = c.Element("description").Value,
Link = c.Element("link").Value,
};
ListBoxNews.ItemsSource = items;
Sounds like you are in over your head (based on the vague nature of your question). So I'm offering my advise to get up to speed, so you can get started and ask a question that we can help give a definitive answer to.
With WP7 and .NET you shouldn't really have to do much manual parsing of Web Services. You should be able to add a Service Reference and generate a proxy which will handle this for you. This will also generate business objects for the data returned by your service.
Once you have that done, you can look into Windows Phone Navigation which should help you transition between pages in your application.
To consume web services:
String baseUri = “your service URI";
WebClient wc = new WebClient();
public MainPage()
{
InitializeComponent();
wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_downloadstringcompleted);
// event handler that will handle the ‘downloadstringsompleted’ event
wc.DownloadStringAsync(new Uri(baseUri));
// this method will download your string URI asynchronously
}
void wc_downloadstringcompleted(Object sender, DownloadStringCompletedEventArgs e)
{
// method will get fired after URI download completes
// writes your every code here
}
To parse the data:
using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
{
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
break;
case XmlNodeType.Text:
break;
case XmlNodeType.EndElement:
break;
}
}
}
}
To store in isolated storage: http://msdn.microsoft.com/en-us/library/system.io.isolatedstorage.isolatedstoragesettings%28v=vs.95%29.aspx
For navigation:
NavigationService.Navigate(new Uri("/SecondPage.xaml?msg=" + navigationstring, UriKind.Relative));