4

I'm writing a Windows Phone application. What I want to do is, when the application starts it gets some data (settings or whatever), and I want this data to persist throughout the life of the application; i.e. I don't want to keep reading the IsolatedStorage or calling the server whenever I need that piece of data.

What is the best way to do this (load and share)? Having in mind the following:

  1. I want it to be MVVM compliant
  2. I'm using Caliburn.Micro
  3. The data is not read-only.
  4. The application has more than one page/View and ViewModels that share the data

Thanks in advance.

TheBlueSky
  • 5,526
  • 7
  • 35
  • 65
  • What do you mean by the life of the application? Installation to uninstall or just from it being run to user quitting? – Phil Dec 02 '11 at 14:40
  • 1
    See also: http://stackoverflow.com/questions/4140201/windows-phone-7-data-persistence – ctacke Dec 02 '11 at 16:19
  • See also: http://stackoverflow.com/questions/3394316/whats-the-best-way-of-persisting-data-to-isolated-storage-on-windows-phone-7 – ctacke Dec 02 '11 at 16:20
  • See also: http://stackoverflow.com/questions/6830518/tombstoning-strategy-in-windows-phone-7-how-to-save-states-of-multiple-pages – ctacke Dec 02 '11 at 16:21
  • See also: http://stackoverflow.com/questions/4624603/when-to-save-the-state-of-the-application-for-tombstoning – ctacke Dec 02 '11 at 16:22
  • @ctacke I don't think that's what the question is. OP doesn't want to read from IsolatedStorage multiple times while app is running. At least that's the way I read the quesiton. – CoderDennis Dec 02 '11 at 16:30
  • @Dennis: You're probably right, but it's not entirely clear to me. There's no need to "persist" data while running, RAM does that and keeping the data in a DI container like Caliburn solves that problem. The OP is already using Caliburn, so it's not obvious to me that he's not already doing that. Anyone searching that gets here because they may want info on actually persisting data (as suggested by the question title) might benefit from some of the other linked questions. Thats' why I didn't vote to close, but instead added "related" links. – ctacke Dec 02 '11 at 16:38
  • @ctacke in my understanding, Caliburn is an MVVM framework, not a DI container. It easily integrates with containers though. – CoderDennis Dec 02 '11 at 16:44
  • @Phil, I meant from being run until quitting. – TheBlueSky Dec 02 '11 at 23:08
  • @DennisPalmer, you read the question right. – TheBlueSky Dec 02 '11 at 23:08
  • @ctacke, maybe I used an incorrect term in the title, you may suggest to change that instead, but in the question I clearly specified my requiremnet, and none includes IsolatedStorage or tombstoning. Anyway, like Dennis said, Caliburn.Micro is an MVVM framework, and although I'm using it, I'm still a beginner. I appreciate if you provide references to how "keeping the data in a DI container" works with Caliburn.Micro, instead. Thanks. – TheBlueSky Dec 02 '11 at 23:16

4 Answers4

1

If I've understood your question correctly you could use a static class with static members in it. As long as you reference this class where you want to use the members, they'll exist as long as the app is running.

I'll update the answer with another solution if I've misunderstood "application life"

Phil
  • 3,934
  • 12
  • 38
  • 62
  • You understood the question correctly. I have a question however; how does this work with my first 2 requirements? – TheBlueSky Dec 02 '11 at 23:23
1

A static class as Phil mentions is a fine idea, but I would suggest looking into using dependency injection. You may not need a full IoC container, but that would probably help for your scenario. Caliburn.Micro makes it very easy to integrate such a container.

Create a Settings class. (I would also create an ISettings interface so that you could pass stub settings into your view models for testing, but that's an extra bonus.) Then make all of your ViewModels require an instance of ISettings in their constructors.

When your app starts, you create one instance of Settings that reads from IsolatedStorage or wherever else you have settings, then pass that instance into any ViewModel that gets created.

That Settings class can be responsible for saving settings back to IsolatedStorage whenever it needs to.

An example of this scenario:

In AppBootstrapper class:

PhoneContainer container;
ISettings settings;

protected override void Configure()
{
    // Your usual stuff go here

    settings = new Settings();
    settings.LoadSettings();
    container.Instance(settings);
}

In your ViewModel class:

ISettings settings;

public MainPageViewModel(ISettings settings)
{
    this.settings = settings;
}

At this point you will have all your settings available for your ViewModel.

TheBlueSky
  • 5,526
  • 7
  • 35
  • 65
CoderDennis
  • 13,642
  • 9
  • 69
  • 105
  • Thanks for the answer. Let me do some research about this and come back. In the meanwhile, I appreciate if you have more details to share about this; code, links ... etc. – TheBlueSky Dec 02 '11 at 23:25
1

With Caliburn micro I like to create a SharedData class and register it on the container as a singleton. Then inject it into any ViewModels that need to use it. The Navigation service in CM also makes passing dta between pages simple using .WithParam.

Edit: I just realized this is basically what Dennis said. I also mention that I also use SterlingDB for persisting some things between ViewModels.

Derek Beattie
  • 9,429
  • 4
  • 30
  • 44
0

I misunderstood what Caliburn is - I was thinking, for some reason, it was a DI container. Since it's not, then I'd recommend using one. Personally I'd use the OpenNETCF IoC because I'm familiar with it, but any supported container would work. On app initialization, load your settings and any other services you want for the life of the app and put them into the DI container (or have the container create them for you).

For IoC that would look like this in the app initialization:

// assuming MySettings will initialize itself in the ctor
RootWorkItem.Services.AddNew<MySettings, IMySettings>();

or

var settings = new MySettings();
// init settings here
RootWorkItem.Services.Add<IMySettings>(settings);

Then anywhere in the app at all that you want them, you pull (resolve) by interface type:

var settings = RootWorkItem.Services.Get<IMySettings>();

And use the returned instance. You can use the concrete type instead of an interface in all cases as well, but my preference is to use interfaces to allow easier testing and mocking.

ctacke
  • 66,480
  • 18
  • 94
  • 155