In the previous Post, I have spoken about a solution for DialogMessaging service. Now I would you like propose another solution for read and write data from the LocalSettings or RoamingSettings using IOC design pattern and MVVM Light toolkit.
So, Let’s start with the definition of an Interface that allows the support to the Local/Remote Settings.
public interface ISettingsDataService
{
T GetItem<T>(string container, string id);
IEnumerable GetItems<T>(string container);
void SetValue<T>(string container, string id, T data);
IEnumerable GetEntities<T>(string container)
where T: new()
void SetEntity<T>(string conatiner, T entity)
where T: new()
}
Now we have to move to the implementation:
public class SettingsDataService: ISettingsDataService
{
private ApplicationDataContainer settingsContainer;
public SettingsStoreService(ApplicationDataContainer applicationDataContainer)
{
this.settingsContainer = applicationDataContainer;
}
public T GetItem<T>(string container, string id)
{
if (container == null)
throw new ArgumentNullException("Container cannot be null.");
if (id == null)
throw new ArgumentNullException("Id cannot be null");
ApplicationDataContainer dataContainer =
settingsContainer.CreateContainer(container, ApplicationDataCreateDisposition.Always);
var value = dataContainer.Values.ContainsKey(id)? dataContainer.Values[id]: null;
if (value == null) return default(T);
return (T)value;
}
public IEnumerable GetItems<T>(string container)
{
if (container == null)
throw new ArgumentNullException("Container cannot be null");
ApplicationDataContainer dataContainer =
settingsContainer.CreateContainer(container, ApplicationDataCreateDisposition.Always);
var values = new List();
foreach (var value in dataContainer.Values)
values.Add((T)value.Value);
return values;
}
public IEnumerable GetEntities<T>(string container) where T : new()
{
if (container == null)
throw new ArgumentNullException("Container cannot be null");
ApplicationDataContainer dataContainer =
settingsContainer.CreateContainer(container, ApplicationDataCreateDisposition.Always);
var values = new List();
foreach (var compositeValue in dataContainer.Values)
{
var entity = CreateEntity((ApplicationDataCompositeValue)compositeValue.Value);
values.Add(entity);
}
return values;
}
public void SetValue<T>(string container, string id, T value)
{
if (container == null)
throw new ArgumentNullException("Container cannot be null");
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException("Id cannot be null");
if (value == null)
throw new ArgumentNullException("Value cannot be null");
ApplicationDataContainer dataContainer =
settingsContainer.CreateContainer(container, ApplicationDataCreateDisposition.Always);
dataContainer.Values[id] = value;
}
public void SetEntity<T>(string container, string id, T value) where T : new()
{
if (container == null)
throw new ArgumentNullException("Container cannot be null");
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException("Id cannot be null");
if (value == null)
throw new ArgumentNullException("Value cannot be null");
ApplicationDataContainer dataContainer =
settingsContainer.CreateContainer(container, ApplicationDataCreateDisposition.Always);
ApplicationDataCompositeValue compositeValue = GetCompositeValue(value);
dataContainer.Values[id] = compositeValue;
}
private T CreateEntity<T>(ApplicationDataCompositeValue compositeValue)
where T : new()
{
var entity = new T();
if (entity != null)
{
foreach (var keyValue in compositeValue)
entity.GetType().GetRuntimeProperty(keyValue.Key).SetValue(entity, keyValue.Value);
}
return entity;
}
private ApplicationDataCompositeValue GetCompositeValue(object entity)
{
var compositeValue = new ApplicationDataCompositeValue();
var entitySerializable = entity.GetType()
.GetRuntimeProperties()
.Where(p => p.PropertyType.GetTypeInfo()
.IsSerializable
foreach (var property in entitySerializable))
compositeValue[property.Name] = entity.GetType().GetRuntimeProperty(property.Name).GetValue(entity);
return compositeValue;
}
}
And then, we need to register this service when the app starts.
So, define the following method in the ViewModelLocator class:
public class ViewModelLocator
{
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (!ViewModelBase.IsInDesignModeStatic)
{
Registers();
}
}
public void Registers()
{
SimpleIoc.Default.Register(() => new SettingsDataService(ApplicationData.Current.LocalSettings));
}
}
In the viewmodel, where we need the SettingsDataService we use dependency injection in this way:
public class MainViewModel: ViewModelBase
{
public MainViewModel(ISettingsDataService settingsDataService)
{
//Get a simple value from the LocalStore using ISettingsDataService
var title = settingsDataService.GetItem<string>("ContainerStoreApp", "TitleApp");
//Set a simple Entity
MyClass c = new MyClass();
c.MyProperty = "MyValue";
c.MyComplexProperty = "MyComplexProperty";
settingsDataService.SetEntity<MyClass>("ContainerStoreApp", c);
}
}
In this way we are able to interact with the SettingsData using IOC and MVVM Light.
Enjoy
Maurizio