How to save and retrieve lists in PhoneApplicationService.Current.State? - windows-phone-7

I need to store and retrieve lists in PhoneApplicationService.Current.State[] but this is not a list of strings or integers:
public class searchResults
{
public string title { get; set; }
public string description { get; set; }
}
public List<searchResults> resultData = new List<searchResults>()
{
//
};
The values of the result are fetched from internet and when the application is switched this data needs to be saved in isolated storage for multitasking. How do I save this list and retrieve it again?

If the question really is about how to save the data then you just do
PhoneApplicationService.Current.State["SearchResultList"] = resultData;
and to retrieve again you do
List<searchResults> loadedResultData = (List<searchResults>)PhoneApplicationService.Current.State["SearchResultList"];
Here is a complete working sample:
// your list for results
List<searchResults> resultData = new List<searchResults>();
// add some example data to save
resultData.Add(new searchResults() { description = "A description", title = "A title" });
resultData.Add(new searchResults() { description = "Another description", title = "Another title" });
// save list of search results to app state
PhoneApplicationService.Current.State["SearchResultList"] = resultData;
// --------------------->
// your app could now be tombstoned
// <---------------------
// load from app state
List<searchResults> loadedResultData = (List<searchResults>)PhoneApplicationService.Current.State["SearchResultList"];
// check if loading from app state succeeded
foreach (searchResults result in loadedResultData)
{
System.Diagnostics.Debug.WriteLine(result.title);
}
(This might stop working when your data structure gets more complex or contains certain types.)

Sounds like you just want to employ standard serialisation for your list object, see here in the MSDN docs
http://msdn.microsoft.com/en-us/library/ms973893.aspx
Or also XML serialisation if you want something that can be edited outside of the application (you can also use the Isolated Storage exploter to grab the file off and edit later)
http://msdn.microsoft.com/en-us/library/182eeyhh(v=vs.71).aspx
Alternatively i would also suggest trying out the Tombstone Helper project by Matt Lacey which can simplify this for you greatly
http://tombstonehelper.codeplex.com/

The answer by Heinrich already summarizes the main idea here - you can use the PhoneApplicationService.State with Lists like with any objects. Check out the MSDN docs on preserving application state: How to: Preserve and Restore Application State for Windows Phone. There's one important point to notice there:
Any data that you store in the State dictionary must be serializable,
either directly or by using data contracts.
Directly here means that the classes are marked as [Serializable]. Regarding your List<searchResults>, it is serializable if searchResults is serializable. To do this, either searchResults and all types referenced by it must be marked with the [Serializable] OR it must be a suitable Data Contract, see Using Data Contracts and Serializable Types. In short, make sure the class is declared as public and that it has a public, parameterless constructor.

Related

In MVVMCross 5, how can I navigate backward multiple pages?

In this example, a unique Person is defined by their FirstName and LastName. PageA is a form that selects a unique Person. PageB is a list of unique FirstNames, and PageC is a list of all the LastNames that exist for a given FirstName.
I'm having a hard time solving a particular UX pattern using MvxNavigationService. Here's what I'm attempting to do, (psuedocode):
PageA.SelectedItem = NavigateTo(PageB) [list of Person, grouped
by Person.FirstName];
PageB.SelectedItem = NavigateTo(PageC) [for
Person.FirstName, list of Person.LastName, ];
PageC.Close(SelectedItem);
PageB.Close(SelectedItem);
When I actually try and implement this and run it on Android, the viewmodel logic executes, but the UI doesn't show PageA.
Update: Calling PageB.Close() navigates back to PageC, since PageC was the previous page. Perhaps the problem could be solved by ensuring that PageC is removed from the stack upon closing it. How might this be accomplished?
There's many ways of doing this, using a Custom ViewPresenter on iOS or using an Activity on Android.
One way I achieved this for a small pair (2 view models) was by adding an Instance static variable to the first ViewModel that opens the second ViewModel, like this:
public class FirstViewModel
{
public static FirstViewModel Instance;
public void FirstViewModel()
{
Instance = this;
...
}
}
And then in the second ViewModel's save/close command, I just closed both ViewModels like this and it worked:
public new MvvmCross.Commands.IMvxCommand SaveClickCommand
{
get
{
return new MvvmCross.Commands.MvxAsyncCommand(
async () =>
{
await Navigator.Close(this);
await Navigator.Close(FirstViewModel.Instance);
}
);
}
}

Core Data Problems?

I am trying to use CoreData but I already went through the setup for my project and forgot to check off the box to utilize it.
Is there a way to implement the use of core data when the CoreData box was not checked previously during the setup?
If I start a new project will have to transfer a lot of information and it would be time consuming so I would like to stay on the same project and not create a new one.
To be frank, you did the right think by not checking the Use CoreData box on project creation. I feel that just bloats the project with a bunch of stuff that is easier (and more insightful) to do manually.
To be short, you can implement CoreData the same regardless of what option you selected at project creation.
Here are the steps I usually go through when I want to add CoreData support to my project (manually/programatically):
Define a Data Model
These are just NSManagedObjects which represent your application's data structure. For example, a User, Message, BlogPost, etc. I also make one for my user settings.
Example:
import CoreData
class User : NSManagedObject
{
// #NSManaged is the replacement for #dynamic when using CoreData in Swift
#NSManaged var identifier : String
#NSManaged var firstName : String?
#NSManaged var lastName : String?
// This is called when a new User object is inserted to CoreData
override func awakeFromInsert()
{
super.awakeFromInsert()
self.identifier = NSUUID().UUIDString // generate a random unique ID
}
}
Add Core Data Model
This is another file you add to your project via: File -> New-> iOS-> CoreData -> Data Model. I usually store this same xcmodeldata file in my Models project folder (along with my actual model classes).
Upon selecting this new file, you'll see the CoreData model editor. You will want to see the right-hand side inspector pane is visible (hotkey is ⌥⌘1). For the core data editor, you will also primarily use the third tab (data model inspector) which is switchable with ⌥⌘3.
Now you can add an entity object to this data model (via Add Entity at the bottom). Assuming the example above, add a User entity. With the User entity selected, add the three attributes that are defined in the above class: identifier, firstName, and lastName. They should match the class definition, using String types.
Next step is to tell CoreData that this User entity defined here maps to our actual class file. With the User selected and the data model inspector pane open, set the Name to User and Class to YourAppName.User.
This is the "gotcha" with Swift and CoreData, your classes are prefixed with the module name in order to namespace them (avoiding name collisions). The nice part is that you no longer need to add "XYZ" class prefixes to your objects.
Initialize Core Data Stack
With your data model defined, you need to initialize the CoreData stack itself (database store and context). The most basic example is a global singleton for your NSManagedObjectContext, which will be lazy-loaded when needed.
You can put this in its own Swift file (CoreDataStack.swift):
import CoreData
let managedObjectContext : NSManagedObjectContext =
{
// This is your xcdatamodeld file
let modelURL = NSBundle.mainBundle().URLForResource("MyApp", withExtension: "momd")
let dataModel = NSManagedObjectModel(contentsOfURL: modelURL!)
// This is where you are storing your SQLite database file
let documentsDirectory : NSURL! = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).last as? NSURL
let storeURL = documentsDirectory.URLByAppendingPathComponent("MyApp.sqlite")
let psc = NSPersistentStoreCoordinator(managedObjectModel: dataModel!)
var error : NSError?
let store = psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil, error: &error)
if let error = error
{
println("Uhoh, something happened! \(error), \(error.userInfo)")
}
let context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
context.persistentStoreCoordinator = psc
context.undoManager = nil
return context
}()
Using Core Data
So now that you have a working Core Data stack, some data models defined and mapped... what next?
Let's fetch some objects!
func getUsersByFirstName(firstName: String) -> [User]
{
let fetchRequest = NSFetchRequest(entityName: "User")
// The [c] part indicates case-insensitive, "Bob" == "bob"
fetchRequest.predicate = NSPredicate(format: "firstName ==[c] %#", firstName)
var error : NSError?
let results = context.executeFetchRequest(fetchRequest, error: &error) as [User]
// Handle errors here
return results
}
Oh right, we have nothing to fetch. You can also insert objects...
func insertNewUser() -> User
{
return NSEntityDescription.insertNewObjectForEntityForName("User", inManagedObjectContext: context) as User
}
And of course you can delete objects...
func deleteUser(user: User)
{
context.deleteObject(user)
}
The key is to remember that CoreData contexts (NSManagedObjectContext) keep track of changes in memory. While you can perform these CRUD operations on a context and see the changes instantly (within the same context), they will not persist in the database until you save the changes:
func saveContext() -> Bool
{
var error : NSError?
if context.hasChanges && !context.save(&error)
{
println("Something happened when saving! \(error!), \(error!.userInfo)")
return false
}
return true
}
You can also rollback changes from the last save by using context.rollback().
Feel free to explore CoreData and experiment with the more advanced features like predicates (NSPredicate), sort descriptors (NSSortDescriptor), and setting up object relationships.
Basically all the tick box for Core Data does is add the core data framework (CoreData.framework) to your project and setup your AppDelegate.m with the core data stack, add in a data file and possibly give you a sample view controller (depending on which project type you start with).
If you want your existing project to be setup like the template would set you up, then the quickest way is to just create a new project as an example and select Core Data tick box. Open the new project and review the AppDelegate.m file and grab the code for initializing core data stack. It's about 80 lines and has a comment calling out the Core Data Stack.
Take that over to your existing project and drop it in to your AppDelegate file. Also in your existing project, add the CoreData.framework, then add in a new file (File->New File->CoreData), under Core Data called a "Data Model" file. This file is used to define the equivalent of your data schema. You select it to use the graphical controls.
Then use your sample project to review how you access the core data stack by reviewing the sample ViewController.
Note: some people are not fond of how Apple sets up the Core Data stack in the AppDelegate.m and you'll find many comments about it and how to do it better, if you search for it (I feel compelled to make this disclaimer). There are also some 3rd party libraries on GitHub that can assist you in that regard as well. (MagicalRecord,SLCoreDataStack, etc).
hope that helps!
be well!

protobuf-net concurrent performance issue in TakeLock

We're using protobuf-net for sending log messages between services. When profiling stress testing, under high concurrency, we see very high CPU usage and that TakeLock in RuntimeTypeModel is the culprit. The hot call stack looks something like:
*Our code...*
ProtoBuf.Serializer.SerializeWithLengthPrefix(class System.IO.Stream,!!0,valuetype ProtoBuf.PrefixStyle)
ProtoBuf.Serializer.SerializeWithLengthPrefix(class System.IO.Stream,!!0,valuetype ProtoBuf.PrefixStyle,int32)
ProtoBuf.Meta.TypeModel.SerializeWithLengthPrefix(class System.IO.Stream,object,class System.Type,valuetype ProtoBuf.PrefixStyle,int32)
ProtoBuf.Meta.TypeModel.SerializeWithLengthPrefix(class System.IO.Stream,object,class System.Type,valuetype ProtoBuf.PrefixStyle,int32,class ProtoBuf.SerializationContext)
ProtoBuf.ProtoWriter.WriteObject(object,int32,class ProtoBuf.ProtoWriter,valuetype ProtoBuf.PrefixStyle,int32)
ProtoBuf.BclHelpers.WriteNetObject(object,class ProtoBuf.ProtoWriter,int32,valuetype
ProtoBuf.BclHelpers/NetObjectOptions)
ProtoBuf.Meta.TypeModel.GetKey(class System.Type&)
ProtoBuf.Meta.RuntimeTypeModel.GetKey(class System.Type,bool,bool)
ProtoBuf.Meta.RuntimeTypeModel.FindOrAddAuto(class System.Type,bool,bool,bool)
ProtoBuf.Meta.RuntimeTypeModel.TakeLock(int32&)
[clr.dll]
I see that we can use the new precompiler to get a speed boost, but I'm wondering if that will get rid of the issue (sounds like it doesn't use reflection); it would be a bit of work for me to integrate this, so I haven't tested it yet. I also see the option to call Serializer.PrepareSerializer. My initial (small scale) testing didn't make the prepare seem promising.
A little more info about the type we're serializing:
[ProtoContract]
public class SomeMessage
{
[ProtoMember(1)]
public SomeEnumType SomeEnum { get; set; }
[ProtoMember(2)]
public long SomeId{ get; set; }
[ProtoMember(3)]
public string SomeString{ get; set; }
[ProtoMember(4)]
public DateTime SomeDate { get; set; }
[ProtoMember(5, DynamicType = true, OverwriteList = true)]
public Collection<object> SomeArguments
}
Thanks for your help!
UPDATE 9/17
Thanks for your response! We're going to try the workaround you suggest and see if that fixes things.
This code lives in our logging system so, in the SomeMessage example, SomeString is really a format string (e.g. "Hello {0}") and the SomeArguments collection is a list of objects used to fill in the format string, just like String.Format. Before we serialize, we look at each argument and call DynamicSerializer.IsKnownType(argument.GetType()), if it isn't known, we convert it to a string first. I haven't looked at the ratios of data, but I'm pretty sure we have a lot of different strings coming in as arguments.
Let me know if this helps. If you need, I'll try to get more details.
TakeLock is only used when it is changing the model, for example because it is seeing a type for the first time. You shouldn't normally see TakeLock after the first time a particular type has been used. In most cases, using Serializaer.PrepareSerializer<SomeMessage>() should perform all the necessary initialization (and similar for any other contracts you are using).
However! I wonder if perhaps this is also related to your use of DynamicType; what are the actual objects being used here? It might be that I need to tweak the logic here, so that it doesn't spend any time on that step. If you let me know the actual objects (so I can repro), I will try to run some tests.
As for whether the precompiler would change this; yes it would. A fully compiled static model has a completely different implementation of the ProtoBuf.Meta.TypeModel.GetKey method, so it would never call TakeLock (you don't need to protect a model that can never change!). But you can actuallydo something very similar without needing to use precompile. Consider the following, run as part of your app's initialization:
static readonly TypeModel serializer;
...
var model = TypeModel.Create();
model.Add(typeof(SomeMessage), true);
// TODO add other contracts you use here
serializer = model.Compile();
This will create a fully static-compiled serializer assembly in memory (instead of a mutable model with individual operations compiled). If you now use serializer.Serialize(...) instead of Serializer.Serialize (i.e. the instance method on your stored TypeModel rather than the static method on Serializer) then it will essentially be doing something very similar to "precompiler", but without the need to actualy precompile it (obviously this will only be available on "full" .NET). This will then never call TakeLock, as it is running a fixed model, rather than a flexible model. It does, however, require you to know what contract-types you use. You could use reflection to find these, by looking for all those types with a given attribute:
static readonly TypeModel serializer;
...
var model = TypeModel.Create();
Type attributeType = typeof(ProtoContractAttribute);
foreach (var type in typeof(SomeMessage).Assembly.GetTypes()) {
if (Attribute.IsDefined(type, attributeType)) {
model.Add(type, true);
}
}
serializer = model.Compile();
But emphasis: the above is a workaround; it sounds like there's a glitch, which I'll happily investigate if I can see an example where it actually happens; most importantly: what are the objects in SomeArguments?

Separation of Concerns: Returning Projected Data between layers From a Linq Query

I'm using Linq and having trouble doing something that I believe should be trivial. I want to return data from one layer so it can be used independently of linq in another layer.
Suppose I have a Data Access Layer. It knows about the entity framework and how to interact with it. But, it doesn't care who accesses it. The one interesting requirement I have is that the queries in the entity framework return projected data that is not part of the Entity Model itself. Please don't ask me to change this part of the requirement and make POCOs for each return type, as it is not the best design given the problem I am trying to solve. Below is an example.
public class ChartData
{
public function <<returnType??>> GetData()
{
MyEntities context = new MyEntities();
var results = from context.vManyColumnsOfData as v
where v.CompanyName = "acme"
select new {Year = v.SalesYear, Income = v.Income};
return ??;
}
}
Then, I would like to have an ASP.Net UI layer be able to call into the Data Access Layer to get the data in order to bind it to a control. The UI layer should have no notion of where the data came from. It should only know that it has the data it needs to bind. Below is an example.
protected void chart_Load(object sender, EventArgs e)
{
// set some chart properties
chart.Skin = "Default";
...
// Set the data source
ChartData dataMgr = new ChartData();
<<returnType?>> data = dataMgr.GetData();
chart.DataSource = data;
chart.DataBind();
}
What is the best way to send linq projected data back to another layer?
If you don't need to use the projected type statically, just return IEnumerable<object>.
Please don't ask me to change this part of the requirement and make
POCOs for each return type, as it is not the best design given the
problem I am trying to solve.
I feel like I should rightly ignore this, as the best thing to do is to return a defined type. Anonymous types are useful when they are wholly contained within the method that creates them. Once you start passing them around, it is time to go ahead and give them the proper class treatment.
However, to live within your imposed limitations, you can return IEnumerable<object> from the method and use that or var at the callsite and rely upon the dynamic binding of the control to get at the data. It's not going to help you if you need to deal with the object programmatically, but it will serve fine for databinding.
You can not return an anonymous type, so basically for this you will need POCO's even though you don't want them.
"not the best design given the problem I am trying to solve"
Could you explain what you are trying to achieve a little more? It might be possible to return some type of list containing a dictionary of items (ie rows and columns). Think something like an untyped dataset (yuck)
Your GetData method can use IEnumerable (the "old" non-generic interface) as its return type.
Any dynamic resolution (e.g. ASP.NET or XAML bindings) should work as expected, which seems to be what you want to do.
However, if you want to use the results in your code, you will probably have to resort to .NET 4's dynamic keyword.
The following example can be run in LINQPad (in "C# Program" mode) and illustrates this:
void Main()
{
var v = GetData();
foreach (dynamic element in v)
{
((string)element.Name).Dump();
}
}
public IEnumerable GetData()
{
return from i in Enumerable.Range(1, 10)
select new
{
Name = "Item " + i,
Value = i
};
}
Keep in mind that, design-wise, coding like this will make most people frown and can affect performance.

Safe to hold context within a Dictionary

OK so my question is self explanatory, here is some code so you can understand a little more.
public Dictionary<string,VcardWindow> VcardWindowManager
= new Dictionary<string,VcardWindow>();'
And access like so:
public void ShowVcardWindow(string VcardOwner)
{
VcardWindow Window;
if(VcardWindowManager.ContainsKey(VcardOwner))
{
Window = VcardWindowManager[VcardOwner];
}
else
{
Window = new VcardWindow(VcardOwner);
//Startup Code
VcardWindowManager.Add(VcardOwner,Window);
}
//Invoker here
}
Is by storing windows in a dictionary OK? Are there other means that are faster and safer?
An instance of a Form is an object like any other, and so you can store its reference in a Dictionary. Using a Dictionary in this case is the correct way to store a collection of objects that need to be accessed according to a key, in a single-threaded scenario.

Resources