diff --git a/MBS.Framework/Application.cs b/MBS.Framework/Application.cs
index f7ccad6..6dae0ae 100644
--- a/MBS.Framework/Application.cs
+++ b/MBS.Framework/Application.cs
@@ -21,6 +21,7 @@
using System;
using System.Collections.Generic;
using System.Text;
+using MBS.Framework.Collections.Generic;
namespace MBS.Framework
{
@@ -63,6 +64,13 @@ namespace MBS.Framework
///
public static Application Instance { get; set; } = null;
+ ///
+ /// Searches for the file with the given and
+ /// returns all matching fully-qualified file names.
+ ///
+ /// The files.
+ /// Filename.
+ /// Options.
public string[] FindFiles(string filename, FindFileOptions options = FindFileOptions.All)
{
if (filename.StartsWith("~/"))
@@ -82,9 +90,16 @@ namespace MBS.Framework
}
return files.ToArray();
}
- public string FindFile(string fileName, FindFileOptions options = FindFileOptions.All)
+ ///
+ /// Searches for the file with the given and
+ /// returns the first matching fully-qualified file name.
+ ///
+ /// The files.
+ /// Filename.
+ /// Options.
+ public string FindFile(string filename, FindFileOptions options = FindFileOptions.All)
{
- string[] files = FindFiles(fileName, options);
+ string[] files = FindFiles(filename, options);
if (files.Length > 0)
{
return files[0];
@@ -92,8 +107,16 @@ namespace MBS.Framework
return null;
}
+ ///
+ /// Gets a collection of s registered for this
+ /// .
+ ///
+ /// The event filters.
public EventFilter.EventFilterCollection EventFilters { get; } = new EventFilter.EventFilterCollection();
+ ///
+ /// Finds the command with the given .
+ ///
protected virtual Command FindCommandInternal(string commandID)
{
return null;
@@ -125,10 +148,18 @@ namespace MBS.Framework
return null;
}
+ ///
+ /// Finds the with the given
+ /// .
+ ///
protected virtual Context FindContextInternal(Guid contextID)
{
return null;
}
+ ///
+ /// Finds the with the given
+ /// .
+ ///
public Context FindContext(Guid contextID)
{
Context ctx = FindContextInternal(contextID);
@@ -303,10 +334,221 @@ namespace MBS.Framework
Initialized = true;
}
+ public event ApplicationActivatedEventHandler Activated;
+ protected virtual void OnActivated(ApplicationActivatedEventArgs e)
+ {
+ Activated?.Invoke(this, e);
+ }
+
protected virtual int StartInternal()
{
+ CommandLine cline = new CommandLine();
+ string[] args = CommandLine.Arguments;
+
+ if (args.Length > 0)
+ {
+ int i = 0;
+ for (i = 0; i < args.Length; i++)
+ {
+ if (ParseOption(args, ref i, cline.Options, CommandLine.Options))
+ break;
+ }
+
+ // we have finished parsing the first set of options ("global" options)
+ // now we see if we have commands
+ if (CommandLine.Commands.Count > 0 && i < args.Length)
+ {
+ // we support commands like git and apt, "appname --app-global-options --command-options"
+ CommandLineCommand cmd = CommandLine.Commands[args[i]];
+ if (cmd != null)
+ {
+ for (i++; i < args.Length; i++)
+ {
+ if (ParseOption(args, ref i, null, cmd.Options))
+ break;
+ }
+
+ cline.Command = cmd;
+ }
+ else
+ {
+ // assume filename
+ }
+ }
+
+ for (/* intentionally left blank */; i < args.Length; i++)
+ {
+ cline.FileNames.Add(args[i]);
+ }
+ }
+
+ OnActivated(new ApplicationActivatedEventArgs(true, ApplicationActivationType.CommandLineLaunch, cline));
return 0;
}
+
+
+ protected void PrintUsageStatement(CommandLineCommand command = null)
+ {
+ Console.Write("usage: {0} ", ShortName);
+ foreach (CommandLineOption option in CommandLine.Options)
+ {
+ PrintUsageStatementOption(option);
+ }
+ Console.WriteLine();
+ // Console.Write("[]");
+
+ if (command != null)
+ {
+ Console.WriteLine(" {0}{1}", command.Name, command.Description == null ? null : String.Format(" - {0}", command.Description));
+ foreach (CommandLineOption option in command.Options)
+ {
+ PrintUsageStatementOption(option);
+ }
+ }
+ else
+ {
+ if (CommandLine.Commands.Count > 0)
+ {
+ Console.WriteLine(" []");
+ Console.WriteLine();
+
+ List commands = new List(CommandLine.Commands);
+ commands.Sort((x, y) =>
+ {
+ return x.Name.CompareTo(y.Name);
+ });
+ foreach (CommandLineCommand command1 in commands)
+ {
+ Console.WriteLine(" {0}{1}", command1.Name, command1.Description == null ? null : String.Format(" - {0}", command1.Description));
+ }
+ }
+ }
+ }
+
+ private void PrintUsageStatementOption(CommandLineOption option)
+ {
+ Console.Write(" ");
+ if (option.Optional)
+ {
+ Console.Write('[');
+ }
+
+ string shortOptionPrefix = CommandLine.ShortOptionPrefix ?? "-";
+ string longOptionPrefix = CommandLine.LongOptionPrefix ?? "--";
+
+ if (option.Abbreviation != '\0')
+ {
+ Console.Write("{0}{1}", shortOptionPrefix, option.Abbreviation);
+ if (option.Type == CommandLineOptionValueType.Single)
+ {
+ Console.Write(" ");
+ }
+ else if (option.Type == CommandLineOptionValueType.Multiple)
+ {
+ Console.Write(" [,,...]");
+ }
+
+ Console.Write(" | {0}{1}", longOptionPrefix, option.Name);
+ if (option.Type == CommandLineOptionValueType.Single)
+ {
+ Console.Write("=");
+ }
+ else if (option.Type == CommandLineOptionValueType.Multiple)
+ {
+ Console.Write("=[,,...]");
+ }
+ }
+ else
+ {
+ Console.Write(longOptionPrefix ?? "--");
+ Console.Write("{0}", option.Name);
+ if (option.Type == CommandLineOptionValueType.Single)
+ {
+ Console.Write("=");
+ }
+ else if (option.Type == CommandLineOptionValueType.Multiple)
+ {
+ Console.Write("=[,,...]");
+ }
+ }
+ if (option.Optional)
+ {
+ Console.Write(']');
+ }
+ // Console.WriteLine();
+ }
+
+ ///
+ /// Parses the option.
+ ///
+ /// true, if option was parsed, false otherwise.
+ /// Arguments.
+ /// Index.
+ /// The list into which to add the option if it has been specified.
+ /// The set of available options.
+ private bool ParseOption(string[] args, ref int index, IList list, CommandLineOption.CommandLineOptionCollection optionSet)
+ {
+ string longOptionPrefix = "--", shortOptionPrefix = "-";
+
+ bool breakout = false;
+ if (args[index].StartsWith(shortOptionPrefix) && args[index].Length == (shortOptionPrefix.Length + 1))
+ {
+ char shortOptionChar = args[index][args[index].Length - 1];
+ CommandLineOption option = optionSet[shortOptionChar];
+ if (option != null)
+ {
+ if (option.Abbreviation == shortOptionChar)
+ {
+ if (option.Type != CommandLineOptionValueType.None)
+ {
+ index++;
+ option.Value = args[index];
+ }
+
+ if (list != null)
+ list.Add(option);
+ }
+ }
+ else
+ {
+ list.Add(new CommandLineOption() { Abbreviation = shortOptionChar });
+ }
+ }
+ else if (args[index].StartsWith(longOptionPrefix))
+ {
+ // long option format is --name[=value]
+ string name = args[index].Substring(longOptionPrefix.Length);
+ string value = null;
+ if (name.Contains("="))
+ {
+ int idx = name.IndexOf('=');
+ value = name.Substring(idx + 1);
+ name = name.Substring(0, idx);
+ }
+ CommandLineOption option = optionSet[name];
+ if (option != null)
+ {
+ if (option.Type != CommandLineOptionValueType.None)
+ {
+ // index++;
+ // option.Value = args[index];
+ option.Value = value;
+ }
+ list.Add(option);
+ }
+ else
+ {
+ list.Add(new CommandLineOption() { Name = name });
+ }
+ }
+ else
+ {
+ // we have reached a non-option
+ return true;
+ }
+ return false;
+ }
+
public int Start()
{
if (Application.Instance == null)
diff --git a/MBS.Framework/ApplicationActivatedEvent.cs b/MBS.Framework/ApplicationActivatedEvent.cs
new file mode 100644
index 0000000..8dbfa1e
--- /dev/null
+++ b/MBS.Framework/ApplicationActivatedEvent.cs
@@ -0,0 +1,41 @@
+//
+// ApplicationActivatedEvent.cs
+//
+// Author:
+// Mike Becker
+//
+// Copyright (c) 2019 Mike Becker
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+using System;
+using System.Collections.Generic;
+
+namespace MBS.Framework
+{
+ public class ApplicationActivatedEventArgs : EventArgs
+ {
+ public bool FirstRun { get; } = true;
+ public CommandLine CommandLine { get; } = null;
+ public int ExitCode { get; set; } = 0;
+ public ApplicationActivationType ActivationType { get; } = ApplicationActivationType.Launch;
+
+ public ApplicationActivatedEventArgs(bool firstRun, ApplicationActivationType activationType, CommandLine commandLine)
+ {
+ FirstRun = firstRun;
+ ActivationType = activationType;
+ CommandLine = commandLine;
+ }
+ }
+ public delegate void ApplicationActivatedEventHandler(object sender, ApplicationActivatedEventArgs e);
+}
diff --git a/MBS.Framework/ApplicationActivationType.cs b/MBS.Framework/ApplicationActivationType.cs
new file mode 100644
index 0000000..75a13a8
--- /dev/null
+++ b/MBS.Framework/ApplicationActivationType.cs
@@ -0,0 +1,276 @@
+//
+// ActivationType.cs
+//
+// Author:
+// Michael Becker
+//
+// Copyright (c) 2022 Mike Becker's Software
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+using System;
+namespace MBS.Framework
+{
+ ///
+ /// Specifies the type of activation when the application is started
+ /// from layout on a layout-aware operating system.
+ ///
+ ///
+ ///
+ /// Values are mutually exclusive and cannot be combined. Each one
+ /// relates to a different type of activation, and an app instance can
+ /// be activated in only one way at a time.
+ ///
+ ///
+ /// The activation types are based on those supported by Windows 11,
+ /// however the enum values are operating system agnostic. Translation
+ /// (e.g. by an Engine) must be done before calls to operating system
+ /// specific methods are made.
+ ///
+ ///
+ /// On non-layout-aware operating systems, such as Linux, a wrapper
+ /// executable (bootstrapper) must be used to invoke the app activation
+ /// with the desired .
+ ///
+ ///
+ public enum ApplicationActivationType
+ {
+ ///
+ /// The activation type was not specified.
+ ///
+ Unspecified = -1,
+
+ ///
+ /// The user wants to manage appointments that are provided by the
+ /// app.
+ ///
+ AppointmentsProvider,
+ ///
+ /// The app was activated as a barcode scanner provider.
+ ///
+ BarcodeScannerProvider,
+ ///
+ /// The user wants to save a file for which the app provides content
+ /// management.
+ ///
+ CachedFileUpdater,
+ ///
+ /// The app captures photos or video from an attached camera.
+ ///
+ CameraSettings,
+ ///
+ /// The app was launched from the command line.
+ ///
+ CommandLineLaunch,
+ ///
+ /// Reserved for system use. Introduced in Windows 10, version 1507
+ /// (10.0.10240).
+ ///
+ ComponentUI,
+ ///
+ /// The user wants to handle calls or messages for the phone number
+ /// of a contact that is provided by the app.
+ ///
+ Contact,
+ ///
+ /// The app was launched from the My People UI. Note: introduced in
+ /// Windows 10, version 1703 (10.0.15063), but not used. Now used
+ /// starting with Windows 10, version 1709 (10.0.16299).
+ ///
+ ContactPanel,
+ ///
+ /// The user wants to pick contacts.
+ ///
+ ContactPicker,
+ ///
+ /// The app handles AutoPlay.
+ ///
+ Device,
+ ///
+ /// This app was activated as a result of pairing a device.
+ ///
+ DevicePairing,
+ ///
+ /// This app was launched by another app on a different device by
+ /// using the DIAL protocol.Introduced in Windows 10, version 1507
+ /// (10.0.10240).
+ ///
+ DialReceiver,
+ ///
+ /// An app launched a file whose file type this app is registered to
+ /// handle.
+ ///
+ File,
+ ///
+ /// The user wants to pick files that are provided by the app.
+ ///
+ FileOpenPicker,
+ ///
+ /// Reserved for system use. Introduced in Windows 10, version 1607
+ /// (10.0.14393).
+ ///
+ FilePickerExperience,
+ ///
+ /// The user wants to save a file and selected the app as the
+ /// location.
+ ///
+ FileSavePicker,
+ ///
+ /// The app was activated because it was launched by the OS due to a
+ /// game's request for Xbox-specific UI. Introduced in Windows 10,
+ /// version 1703 (10.0.15063).
+ ///
+ GameUIProvider,
+ ///
+ /// The user launched the app or tapped a content tile.
+ ///
+ Launch,
+ ///
+ /// The app was activated as the lock screen. Introduced in Windows
+ /// 10, version 1507 (10.0.10240).
+ ///
+ LockScreen,
+ ///
+ /// Windows Store only. The app launches a call from the lock screen.
+ /// If the user wants to accept the call, the app displays its call
+ /// UI directly on the lock screen without requiring the user to
+ /// unlock. A lock-screen call is a special type of launch
+ /// activation.
+ ///
+ LockScreenCall,
+ ///
+ /// Reserved for system use. Introduced in Windows 10, version 1703
+ /// (10.0.15063).
+ ///
+ LockScreenComponent,
+ ///
+ /// The app was activated in response to a phone call.
+ ///
+ PhoneCallActivation,
+ ///
+ /// Windows Phone only. The app was activated after the completion of
+ /// a picker.
+ ///
+ PickerReturned,
+ ///
+ /// Windows Phone only. The app was activated after the app was
+ /// suspended for a file picker operation.
+ ///
+ PickFileContinuation,
+ ///
+ /// Windows Phone only. The app was activated after the app was
+ /// suspended for a folder picker operation.
+ ///
+ PickFolderContinuation,
+ ///
+ /// Windows Phone only. The app was activated after the app was
+ /// suspended for a file save picker operation.
+ ///
+ PickSaveFileContinuation,
+ ///
+ /// This app was launched by another app to provide a customized
+ /// printing experience for a 3D printer. Introduced in Windows 10,
+ /// version 1507 (10.0.10240).
+ ///
+ Print3DWorkflow,
+ ///
+ /// The app was activated as a print workflow job UI extension.
+ ///
+ PrintSupportJobUI,
+ ///
+ /// The app was activated as a print support settings UI extension.
+ ///
+ PrintSupportSettingsUI,
+ ///
+ /// The app handles print tasks.
+ ///
+ PrintTaskSettings,
+ ///
+ /// The app was activated because the user is printing to a printer
+ /// that has a Print Workflow Application associated with it which
+ /// has requested user input.
+ ///
+ PrintWorkflowForegroundTask,
+ ///
+ /// An app launched a URI whose scheme name this app is registered to
+ /// handle.
+ ///
+ Protocol,
+ ///
+ /// The app was launched by another app with the expectation that it
+ /// will return a result back to the caller. Introduced in Windows
+ /// 10, version 1507 (10.0.10240).
+ ///
+ ProtocolForResults,
+ ///
+ /// Windows Store only. The user launched the restricted app.
+ ///
+ RestrictedLaunch,
+ ///
+ /// The user wants to search with the app.
+ ///
+ Search,
+ ///
+ /// The app is activated as a target for share operations.
+ ///
+ ShareTarget,
+ ///
+ /// The app was activated because the app is specified to launch at
+ /// system startup or user log-in. Introduced in Windows 10, version
+ /// 1703 (10.0.15063).
+ ///
+ StartupTask,
+ ///
+ /// The app was activated when a user tapped on the body of a toast
+ /// notification or performed an action inside a toast notification.
+ /// Introduced in Windows 10, version 1507 (10.0.10240).
+ ///
+ ToastNotification,
+ ///
+ /// The app was launched to handle the user interface for account
+ /// management. In circumstances where the system would have shown
+ /// the default system user interface, it instead has invoked your
+ /// app with the UserDataAccountProvider contract. The activation
+ /// payload contains information about the type of operation being
+ /// requested and all the information necessary to replicate the
+ /// system-provided user interface. This activation kind is limited
+ /// to 1st party apps. To use this field, you must add the
+ /// userDataAccountsProvider capability in your app's package
+ /// manifest. For more info see App capability declarations.
+ /// Introduced in Windows 10, version 1607 (10.0.14393).
+ ///
+ UserDataAccountsProvider,
+ ///
+ /// The app was activated as the result of a voice command.
+ ///
+ VoiceCommand,
+ ///
+ /// The app is a VPN foreground app that was activated by the plugin.
+ /// For more details, see VpnChannel.ActivateForeground.
+ ///
+ VpnForeground,
+ ///
+ /// The app was activated to perform a Wallet operation.
+ ///
+ WalletAction,
+ ///
+ /// The app was activated by a web account provider.
+ ///
+ WebAccountProvider,
+ ///
+ /// The app was activated after the app was suspended for a web
+ /// authentication broker operation.
+ ///
+ WebAuthenticationBrokerContinuation
+ }
+}
diff --git a/MBS.Framework/ArrayExtensions.cs b/MBS.Framework/ArrayExtensions.cs
index b6e54b6..1ffcbfa 100644
--- a/MBS.Framework/ArrayExtensions.cs
+++ b/MBS.Framework/ArrayExtensions.cs
@@ -19,10 +19,23 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
using System;
+using System.Collections.Generic;
+
namespace MBS.Framework
{
public static class ArrayExtensions
{
+ ///
+ /// Splits the into two arrays at the specified
+ /// , where contains the
+ /// elements before and
+ /// contains the elements after .
+ ///
+ /// The array to split.
+ /// The index at which to split the array.
+ /// The array containing elements before the split point.
+ /// The array containing elements after the split point.
+ /// The of elements in the array.
public static void Bisect(this T[] array, int index, out T[] left, out T[] right)
{
left = new T[index];
@@ -55,12 +68,25 @@ namespace MBS.Framework
Array.Copy(sourceArray, 0, destinationArray, start, sourceArray.Length);
}
- public static bool Matches(this T[] array1, T[] array2)
+ ///
+ /// Determines if and
+ /// contain the same elements.
+ ///
+ ///
+ /// if both arrays contain the same elements,
+ /// otherwise.
+ /// The first array to search.
+ /// The second array to search.
+ /// The 1st type parameter.
+ public static bool Matches(this IList array1, IList array2)
{
- if (array1.Length != array2.Length)
+ if (array1.Count != array2.Count)
+ {
+ // short-circuit if arrays have different lengths
return false;
+ }
- for (int i = 0; i < array1.Length; i++)
+ for (int i = 0; i < array1.Count; i++)
{
if (!array1[i].Equals(array2[i]))
return false;
diff --git a/MBS.Framework/CommandLine.cs b/MBS.Framework/CommandLine.cs
index 3405149..1705c68 100644
--- a/MBS.Framework/CommandLine.cs
+++ b/MBS.Framework/CommandLine.cs
@@ -40,10 +40,20 @@ namespace MBS.Framework
public CommandLineParser Parser { get; set; } = null;
public CommandLineOption.CommandLineOptionCollection Options { get; } = new CommandLineOption.CommandLineOptionCollection();
+ public CommandLineCommand.CommandLineCommandCollection Commands { get; } = new CommandLineCommand.CommandLineCommandCollection();
+ public CommandLineCommand Command { get; internal set; } = null;
+ public string ShortOptionPrefix { get; set; } = null;
+ public string LongOptionPrefix { get; set; } = null;
public CommandLine()
{
- Options.Add(new CommandLineOption() { Name = "activation-type", Description = "The type of activation for this app", Type = CommandLineOptionValueType.Single });
+ string[] args = Environment.GetCommandLineArgs();
+ string[] args2 = new string[args.Length - 1];
+ Array.Copy(args, 1, args2, 0, args2.Length);
+ Arguments = args2;
+
+ Options.Add(new CommandLineOption() { Abbreviation = 'A', Name = "activation-type", Description = "The type of activation for this app", Type = CommandLineOptionValueType.Single, Optional = true });
+ Options.Add(new CommandLineOption() { Name = "help", Description = "Displays help", Type = CommandLineOptionValueType.None, Optional = true });
}
public override string ToString()
diff --git a/MBS.Framework/CommandLineCommand.cs b/MBS.Framework/CommandLineCommand.cs
new file mode 100644
index 0000000..a8ddbe9
--- /dev/null
+++ b/MBS.Framework/CommandLineCommand.cs
@@ -0,0 +1,59 @@
+//
+// CommandLineCommand.cs
+//
+// Author:
+// Michael Becker
+//
+// Copyright (c) 2022 Mike Becker's Software
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+using System;
+using MBS.Framework.Collections.Generic;
+
+namespace MBS.Framework
+{
+ public class CommandLineCommand
+ {
+ public class CommandLineCommandCollection
+ : System.Collections.ObjectModel.Collection
+ {
+ public CommandLineCommand this[string name]
+ {
+ get
+ {
+ foreach (CommandLineCommand item in this)
+ {
+ if (item.Name == name)
+ return item;
+ }
+ return null;
+ }
+ }
+ }
+
+ public string Name { get; set; } = null;
+ public string Description { get; set; } = null;
+
+ public CommandLineOption.CommandLineOptionCollection Options { get; } = new CommandLineOption.CommandLineOptionCollection();
+
+ public CommandLineCommand(string command, CommandLineOption[] options = null)
+ {
+ Name = command;
+ if (options != null)
+ {
+ Options.AddRange(options);
+ }
+ }
+ }
+}
diff --git a/MBS.Framework/CommandLineOption.cs b/MBS.Framework/CommandLineOption.cs
index 58e68e8..51148fa 100644
--- a/MBS.Framework/CommandLineOption.cs
+++ b/MBS.Framework/CommandLineOption.cs
@@ -117,6 +117,12 @@ namespace MBS.Framework
public object DefaultValue { get; set; } = null;
+ ///
+ /// Gets or sets a value indicating whether this is optional.
+ ///
+ /// true if optional; otherwise, false.
+ public bool Optional { get; set; } = false;
+
///
/// The description displayed in the help text.
///
diff --git a/MBS.Framework/FindFileOptions.cs b/MBS.Framework/FindFileOptions.cs
index be964f2..e08bc94 100644
--- a/MBS.Framework/FindFileOptions.cs
+++ b/MBS.Framework/FindFileOptions.cs
@@ -21,9 +21,20 @@
using System;
namespace MBS.Framework
{
+ ///
+ /// Controls the behavior of relative file resolution.
+ ///
public enum FindFileOptions
{
+ ///
+ /// Returns all matching fully-qualified file paths across all global,
+ /// application, and user directories.
+ ///
All = 0,
+ ///
+ /// Returns only file paths that are writable by the user (i.e., in the
+ /// user's local or roaming data directory).
+ ///
UserWritable = 1
}
}
diff --git a/MBS.Framework/MBS.Framework.csproj b/MBS.Framework/MBS.Framework.csproj
index 3f47052..8eac4d0 100644
--- a/MBS.Framework/MBS.Framework.csproj
+++ b/MBS.Framework/MBS.Framework.csproj
@@ -135,6 +135,9 @@
+
+
+
@@ -146,5 +149,8 @@
+
+
+
diff --git a/MBS.Framework/MemorySettingsProvider.cs b/MBS.Framework/MemorySettingsProvider.cs
new file mode 100644
index 0000000..4271ae3
--- /dev/null
+++ b/MBS.Framework/MemorySettingsProvider.cs
@@ -0,0 +1,82 @@
+//
+// MemorySettingsProvider.cs
+//
+// Author:
+// Michael Becker
+//
+// Copyright (c) 2022 Mike Becker's Software
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+using System;
+using System.Collections.Generic;
+using MBS.Framework.Settings;
+
+namespace MBS.Framework
+{
+ public class MemorySettingsProvider : SettingsProvider
+ {
+ private Dictionary _values = new Dictionary();
+ protected override void LoadSettingsInternal()
+ {
+ base.LoadSettingsInternal();
+ foreach (SettingsGroup sg in SettingsGroups)
+ {
+ foreach (Setting s in sg.Settings)
+ {
+ LoadSetting(s);
+ }
+ }
+ }
+ protected override void SaveSettingsInternal()
+ {
+ base.SaveSettingsInternal();
+ foreach (SettingsGroup sg in SettingsGroups)
+ {
+ foreach (Setting s in sg.Settings)
+ {
+ SaveSetting(s);
+ }
+ }
+ }
+
+ private void LoadSetting(Setting s)
+ {
+ if (s is GroupSetting)
+ {
+ foreach (Setting s2 in ((GroupSetting)s).Options)
+ {
+ LoadSetting(s2);
+ }
+ }
+ else
+ {
+ s.SetValue(_values[s.ID]);
+ }
+ }
+ private void SaveSetting(Setting s)
+ {
+ if (s is GroupSetting)
+ {
+ foreach (Setting s2 in ((GroupSetting)s).Options)
+ {
+ SaveSetting(s2);
+ }
+ }
+ else
+ {
+ _values[s.ID] = s.GetValue();
+ }
+ }
+ }
+}