This post describes an example of the using NuGet packages under the common title Ikc5.Prism.Settings
: Ikc5.Prism.Settings.Library, Ikc5.Prism.Settings.Module and Ikc5.Prism.Settings.Application. These packages allow manipulate user settings in Prism applications and serialize/deserialize them in xml files. All package contains the same library and last two packages add models, view models and views to the project. Full code is accessible on GitHub Blog repository.
Application
Let’s create Windows application in WPF using the Prism Library. Application and two modules have their own sets of user settings and two common properties: BackgroundColor
and Name
. These values will be used in order to show current values of user settings. At first launch all settings have default values and application window looks in the following way:

Then user may call the settings window, modify and save settings:




Application window changes look according to new values:

Folder NewSettings
located in application launch folder contains three files for user settings:

When user will launch application at the next time, it deserializes user settings and will look exactly in the same way.
Solution
Now describe steps of the development. Let’s create new solution and add 4 projects:
- Class library
CommonLibrary
. It is shared library that contains custom user settings provider. For example, we just override name of folder where settings are stored; - Wpf user control library
Part1Module
that contains Prism module; - Wpf user control library
Part2Module
that contains Prism module; - Wpf Application
WpfApplication
that is the startup project.
CommonLibrary
At first, add NuGet package Ikc5.Prism.Settings.Library
to the library.

It adds two other packages, Ikc5.TypeLibrary
and Prism.Core
. Let’s add FileXmlUserSettingsProvider.cs
file for custom file provider, and write the following code:
public class FileXmlUserSettingsProvider<T> : LocalXmlUserSettingsProvider<T> where T : class, IUserSettings { public FileXmlUserSettingsProvider(ILiteObjectService liteObjectService, ILoggerFacade logger) : base(liteObjectService, logger) { var assembly = Assembly.GetEntryAssembly(); FolderName = Path.Combine(Path.GetDirectoryName(assembly.Location) ?? "", "NewSettings"); } }
In default constructor it overrides folder name, and makes it equals NewSettings
.
Part1Module and Part2Module
These two projects are modified in the similar way. Let’s add NuGet package Ikc5.Prism.Settings.Module
to the module projects.

This package depends on several packages: Ikc5.TypeLibrary
, Prism.Core
, Prism.Wpf
, and Prism.Unity
. Also, it adds empty settings models, settings view models and views to the project.

In the readme file code for Module class is listed, and therefore we add Part1Module.cs
and Part2Module.cs
files and modified them:

public class Part1Module : IModule { private readonly IRegionManager _regionManager; private readonly IUnityContainer _container; public Part1Module(IRegionManager regionManager, IUnityContainer container) { _regionManager = regionManager; _container = container; ConfigureContainer(); } private void ConfigureContainer() { _container.RegisterType<ISettings, Models.Settings>(new ContainerControlledLifetimeManager()); } public void Initialize() { _regionManager.RegisterViewWithRegion($"{GetType().Name}{RegionNames.ModuleSettingsRegion}", typeof(SettingsView)); _regionManager.RegisterViewWithRegion($"{GetType().Name}{RegionNames.ModuleViewRegion}", typeof(UserControl1)); } }
public class Part2Module : IModule { private readonly IRegionManager _regionManager; private readonly IUnityContainer _container; public Part2Module(IRegionManager regionManager, IUnityContainer container) { _regionManager = regionManager; _container = container; ConfigureContainer(); } private void ConfigureContainer() { _container.RegisterType<ISettings, Models.Settings>(new ContainerControlledLifetimeManager()); } public void Initialize() { _regionManager.RegisterViewWithRegion($"{GetType().Name}{RegionNames.ModuleSettingsRegion}", typeof(SettingsView)); _regionManager.RegisterViewWithRegion($"{GetType().Name}{RegionNames.ModuleViewRegion}", typeof(UserControl1)); } }
Now we need to add some properties to modules. Module Part1Module
has four properties:
/// <summary> /// Common settings for Module. /// </summary> public interface ISettings { /// <summary> /// Module's name. /// </summary> string Name { get; set; } /// <summary> /// Background color. /// </summary> Color BackgroundColor { get; set; } /// <summary> /// Checked state. /// </summary> bool IsChecked { get; set; } /// <summary> /// Desired count of something. /// </summary> int Count { get; set; } }
Respectively, module Part2Module
has other four properties:
/// <summary> /// Common settings for Module. /// </summary> public interface ISettings { /// <summary> /// Module's name. /// </summary> string Name { get; set; } /// <summary> /// Background color. /// </summary> Color BackgroundColor { get; set; } /// <summary> /// Desired width of Part2. /// </summary> int Width { get; set; } /// <summary> /// Desired height of Part2. /// </summary> int Height { get; set; } }
Then we need add implementation to Settings.cs
and SettingsViewModel.cs
. As Settings
class is derived from UserSettings
class, and it implements INotifyPropertyChanged
interface, it worth to implement properties in notifiable way. Also, properties are initialize only by their DefaultValue
attribute. For example, implementation of Settings.cs
is the following:
[Serializable] public class Settings : UserSettings, ISettings { public Settings(IUserSettingsService userSettingsService, IUserSettingsProvider<Settings> userSettingsProvider) : base(userSettingsService, userSettingsProvider) { } #region ISettings private string _name; // = "Part1"; private Color _backgroundColor; // = Colors.DarkSeaGreen; private bool _isChecked; // = true; private int _count; // = 100; /// <summary> /// Module's name. /// </summary> [DefaultValue("Part1")] public string Name { get { return _name; } set { SetProperty(ref _name, value); } } /// <summary> /// Background color. /// </summary> [DefaultValue(typeof(Color), "#FF8FBC8F")] public Color BackgroundColor { get { return _backgroundColor; } set { SetProperty(ref _backgroundColor, value); } } /// <summary> /// Checked state. /// </summary> [DefaultValue(true)] public bool IsChecked { get { return _isChecked; } set { SetProperty(ref _isChecked, value); } } /// <summary> /// Desired count of something. /// </summary> [DefaultValue(100)] public int Count { get { return _count; } set { SetProperty(ref _count, value); } } #endregion }
The last step is to modify SettingsView.xaml
in order to provide user possibility to change values of user settings. In this sample, we provide simple list-looks set of corresponding user controls that are bound to user setting properties. For example,
<TextBlock Grid.Row="0" Grid.Column="0" Text="Name"/> <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Name, Mode=TwoWay}" TabIndex="101" Margin="5 2 5 2"/>
There are all steps for the implementing user settings in Prism module.
WpfApplication
Similar to previous projects, we add NuGet package Ikc5.Prism.Settings.Application
.

This package depends on several packages: Ikc5.TypeLibrary
, Prism.Core
, Prism.Wpf
, and Prism.Unity
. Also, it adds empty settings models, settings view models and views to the project.

Most of steps are similar to adding properties to the Prism modules. In addition, application includes SettingsWindow
window that contains region for application settings and tab control with tab items for user settings for all modules. Also, readme
file describes necessary modification in Bootstrapper.cs
file:
public class Bootstrapper : UnityBootstrapper { /// <summary> /// Configures the <see cref="IUnityContainer"/>. May be overwritten in a derived class to add specific /// type mappings required by the application. /// </summary> protected override void ConfigureContainer() { base.ConfigureContainer(); ViewModelLocationProvider.SetDefaultViewModelFactory((type) => Container.Resolve(type)); // create singleton of UserSettingsService Container .RegisterType<IUserSettingsService, UserSettingsService>(new ContainerControlledLifetimeManager()) .RegisterType<ILiteObjectService, LiteObjectService>(new ContainerControlledLifetimeManager()) .RegisterType<ISettings, Settings>(new ContainerControlledLifetimeManager()) .RegisterType<IMainViewModel, MainViewModel>(); Container.RegisterType( typeof(IUserSettingsProvider<>), typeof(FileXmlUserSettingsProvider<>), new ContainerControlledLifetimeManager()); } /// <summary> /// Initializes the shell. /// </summary> /// <remarks> /// The base implemention ensures the shell is composed in the container. /// </remarks> protected override void InitializeShell() { // add some views to region adapter var regionManager = Container.Resolve<IRegionManager>(); regionManager.RegisterViewWithRegion(RegionNames.AppSettingsRegion, typeof(SettingsView)); Application.Current.MainWindow.Show(); } protected override void ConfigureModuleCatalog() { var catalog = (ModuleCatalog)ModuleCatalog; // add all modules catalog.AddModule(typeof(Part1Module.Part1Module)); catalog.AddModule(typeof(Part2Module.Part2Module)); } }
1. All used IP-addresses, names of servers, workstations, domains, are fictional and are used exclusively as a demonstration only.
2. Information is provided «AS IS».
[…] The packages are open-source project, full code is accessible on GitHub NuGet repository. Repository contains nuspec files and file trees for Ikc5.Prism.Settings.Application and Ikc5.Prism.Settings.Module packages. Symbol’s packages was pushed to SymbolSource.org. Example of the using this package is considered in the post Examples of using Ikc5.Prism.Settings. […]
[…] sizes, colors, iteration delays. The application uses Ikc5.Prism.Settings packages, described in Examples of using Ikc5.Prism.Settings, and saves settings of the application and modules in xml files in %AppData% […]