├── .gitignore ├── LICENSE ├── README.md ├── appveyor.yml └── source ├── .gitignore ├── CleanAll.bat ├── Components ├── ServiceLocator │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ServiceContainer.cs │ └── ServiceLocator.csproj └── Settings │ ├── Settings │ ├── Interfaces │ │ ├── IOptions.cs │ │ ├── IOptionsPanel.cs │ │ ├── IProfile.cs │ │ ├── ISettingsManager.cs │ │ └── IViewPosSizeModel.cs │ ├── Internal │ │ └── SettingsManagerImpl.cs │ ├── ProgramSettings │ │ ├── LanguageCollection.cs │ │ └── OptionsPanel.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── SerializableDictionary.cs │ ├── Settings.csproj │ ├── SettingsManager.cs │ ├── UserProfile │ │ ├── IViewSize.cs │ │ ├── LocalizabilityAttribute.cs │ │ ├── Profile.cs │ │ ├── ViewPosSizeModel.cs │ │ └── ViewSize.cs │ └── packages.config │ └── SettingsModel │ ├── ExtensionMethods │ └── SecureStringExtensionMethod.cs │ ├── Interfaces │ ├── IEngine.cs │ ├── IOptionGroup.cs │ └── IOptionsSchema.cs │ ├── Models │ ├── Engine.cs │ ├── Factory.cs │ ├── FileReference.cs │ ├── OptionGroup.cs │ ├── OptionsSchema.cs │ └── XML │ │ ├── Converters │ │ ├── AlternativeDataTypeHandler.cs │ │ ├── IAlternativeDataTypeHandler.cs │ │ └── SecureStringHandler.cs │ │ └── XMLLayer.cs │ ├── Overview.cd │ ├── Properties │ └── AssemblyInfo.cs │ ├── SettingsModel.csproj │ └── packages.config ├── Demos ├── CachedPathSuggest │ ├── CachedPathSuggest.csproj │ ├── Infrastructure │ │ ├── DirectoryHelper.cs │ │ └── LiteRepository.cs │ └── ViewModels │ │ ├── BaseItem.cs │ │ ├── ItemSeperator.cs │ │ └── PathInformation.cs ├── CachedPathSuggestBox.Demo │ ├── App.xaml │ ├── App.xaml.cs │ ├── AssemblyInfo.cs │ ├── CachedPathSuggestBox.Demo.csproj │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── Service │ │ ├── CachedAsyncSuggest.cs │ │ ├── CombinedAsyncSuggest.cs │ │ └── DirectoryAsyncSuggest.cs │ └── ViewModel │ │ └── AppViewModel.cs ├── SuggestBoxDemo │ ├── App.config │ ├── App.xaml │ ├── App.xaml.cs │ ├── GenericSuggestBoxDemo.csproj │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ ├── Resources.resx │ │ ├── Settings.Designer.cs │ │ └── Settings.settings │ └── packages.config ├── SuggestBoxTestLib │ ├── DataSources │ │ ├── Auto │ │ │ ├── AutoSuggestSource.cs │ │ │ ├── Interfaces │ │ │ │ └── IHierarchyHelper.cs │ │ │ ├── LocationIndicator.cs │ │ │ ├── PathHierarchyHelper.cs │ │ │ └── PropertyPathHelper.cs │ │ ├── Directory │ │ │ └── DirectorySuggestSource.cs │ │ ├── Dummy │ │ │ └── DummySuggestions.cs │ │ └── SuggestQueryResultModel.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── SuggestBoxTestLib.csproj │ ├── ViewModels │ │ ├── AppViewModel.cs │ │ ├── DummySuggestSource.cs │ │ └── FakeViewModel.cs │ └── Views │ │ ├── DemoView.xaml │ │ └── DemoView.xaml.cs └── ThemedSuggestBoxDemo │ ├── App.xaml │ ├── App.xaml.cs │ ├── Behaviors │ └── SelectionChangedCommand.cs │ ├── BindToMLib │ ├── MWindowLib │ │ └── DarkLightBrushs.xaml │ └── SuggestionLibDarkLightBrushs.xaml │ ├── Demos │ ├── Behaviors │ │ └── SelectionChangedBehavior.cs .cs │ ├── Models │ │ └── FolderBrowserResult.cs │ └── ViewModels │ │ └── DemoViewModel.cs │ ├── Models │ ├── AppCore.cs │ ├── LocatorViewModel.cs │ └── SettingDefaults.cs │ ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings │ ├── ServiceInjector.cs │ ├── ThemedSuggestBoxDemo.csproj │ ├── ViewModels │ ├── AppLifeCycleViewModel.cs │ ├── AppViewModel.cs │ ├── ThemeDefinitionViewModel.cs │ └── ThemeViewModel.cs │ ├── Views │ ├── MainWindow.xaml │ └── MainWindow.xaml.cs │ ├── app.config │ └── packages.config ├── Infrastructure ├── Infrastructure.csproj ├── RelayCommand.cs └── ViewModelBase.cs ├── LICENSE ├── SuggestBoxLib.sln └── SuggestBoxLib ├── AssemblyInfo.cs ├── Converters ├── BoolToVisibilityPropConverter.cs ├── DoubleAddConverter.cs ├── IntToVisibilityPropConverter.cs ├── InvertBoolConverter.cs └── RecentSuggestsVisibilityConverter.cs ├── Events └── NextTargetLocationArgs.cs ├── Infrastructure ├── FastObservableCollection.cs └── NameOfExtension.cs ├── Interfaces ├── IAsyncSuggest.cs └── ISuggestResult.cs ├── Model ├── SuggestResult.cs └── Tip.cs ├── PathTrimmingTextBlock.cs ├── Resources └── AutoComplete_64x.png ├── Styles ├── ListBoxTemplate.xaml └── ResizeGrip.xaml ├── SuggestBox.cs ├── SuggestBoxBase.xaml ├── SuggestBoxBase.xaml.cs ├── SuggestBoxLib.csproj ├── SuggestBoxLib.xml ├── SuggestComboBox.cs ├── SuggestComboBox.xaml ├── SuggestComboBoxButtonStyle.xaml ├── Themes ├── DarkBrushs.xaml ├── Generic.xaml ├── LightBrushs.xaml └── ResourceKeys.cs └── Utils ├── InvalidValidationRule.cs └── TreeHelper.cs /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://ci.appveyor.com/api/projects/status/nw16d7fi59x0se0p?svg=true)](https://ci.appveyor.com/project/Dirkster99/suggestboxlib) [![Release](https://img.shields.io/github/release/Dirkster99/SuggestBoxLib.svg)](https://github.com/Dirkster99/SuggestBoxLib/releases/latest) [![NuGet](https://img.shields.io/nuget/dt/Dirkster.SuggestBoxLib.svg)](http://nuget.org/packages/Dirkster.SuggestBoxLib) 2 | 3 | ![Net4](https://badgen.net/badge/Framework/.Net 4/blue) ![NetCore3](https://badgen.net/badge/Framework/NetCore 3/blue) 4 | 5 | The SuggestBox control in this repository was originally developed by Leung Yat Chun Joseph lycj in his FileExplorer application originating from CodePlex and CodeProject. 6 | 7 | # SuggestBoxLib 8 | 9 |

 Overview

10 | 11 | A WPF Dark/Light AutoComplete TextBox that can easily handle 20.000+ entries. 12 | 13 | This project implements a WPF Dark/Light AutoComplete TextBox that can easily handle 20.000+ entries in the 14 | list of suggestions. The screenshots below show a dark themed demo appliaction with a classic AutoComplete 15 | use case for browsing the file system. This control can also be used to browse other data structures since 16 | the data processing is implemented in the ViewModel/Model layers of the MVVM demo app, while 17 | the control itself is limited to the view. 18 | 19 | Review the [Wiki section](https://github.com/Dirkster99/SuggestBoxLib/wiki) to find out more details of the available API. 20 | 21 | This control is also used in a [Metro Breadcrumb control](https://github.com/Dirkster99/bm). 22 | 23 | The first two screenshots show how a seperate combobox like drop down control can be used to select an entry from 24 | a list of recently visited locations (bound to a collection in the viewmodel): 25 | ![](https://raw.githubusercontent.com/Dirkster99/Docu/master/SuggestBoxLib/screenshots/Unbenannt-7.png) 26 | 27 | ![](https://raw.githubusercontent.com/Dirkster99/Docu/master/SuggestBoxLib/screenshots/Unbenannt-8.png) 28 | 29 | A selection of a recently visited location can be used as a starting point to follow up with more suggestions: 30 | ![](https://raw.githubusercontent.com/Dirkster99/Docu/master/SuggestBoxLib/screenshots/Unbenannt-9.png) 31 | 32 | ![](https://raw.githubusercontent.com/Dirkster99/Docu/master/SuggestBoxLib/screenshots/Unbenannt-10.png) 33 | 34 | The control can shorten text that is too long for display by inserting ellipses '...' on the: 35 | - left 36 | - right or in the 37 | - center 38 | 39 | of a given string. This display is available only if the control is not currently focused. 40 | ![](https://raw.githubusercontent.com/Dirkster99/Docu/master/SuggestBoxLib/screenshots/ShowEllipses_Centered.png) 41 | 42 | ## User Feedback 43 | 44 | The control implements a [NextTargetLocationArgs](https://github.com/Dirkster99/SuggestBoxLib/blob/master/source/SuggestBoxLib/Events/NextTargetLocationArgs.cs) event that can be raised via enter/escape key in the textbox control to support keyboard 45 | gestures to confirm/cancel editing of a location. 46 | 47 | ![](https://raw.githubusercontent.com/Dirkster99/Docu/master/SuggestBoxLib/screenshots/OK_Cancel.png) 48 | 49 | ## Error Feedback 50 | The control can show a red rectangle if the user types a completely unmatchable string. This red rectangle 51 | can be triggered with the property attached to the checkbox in the demo application. 52 | 53 | ![](https://raw.githubusercontent.com/Dirkster99/Docu/master/SuggestBoxLib/screenshots/Unbenannt-6.png) 54 | 55 | ## Highlighting Color and Themes 56 | Screenshot in this repository where done with this highlighting color on Windows 10: 57 | ![](https://raw.githubusercontent.com/Dirkster99/Docu/master/SuggestBoxLib/screenshots/Untitled.png) 58 | 59 | A Dark/Light themed demo application and a Generic application are part of this repository. 60 | 61 | ![](https://raw.githubusercontent.com/Dirkster99/Docu/master/SuggestBoxLib/screenshots/Unbenannt-4.png) 62 | 63 | Load *Light* or *Dark* brush resources in you resource dictionary to take advantage of existing definitions. 64 | 65 | ```XAML 66 | 67 | 68 | 69 | ``` 70 | 71 | ```XAML 72 | 73 | 74 | 75 | ``` 76 | 77 | These definitions do not theme all controls used within this library. You should use a standard theming library, such as: 78 | - [MahApps.Metro](https://github.com/MahApps/MahApps.Metro), 79 | - [MLib](https://github.com/Dirkster99/MLib), or 80 | - [MUI](https://github.com/firstfloorsoftware/mui) 81 | 82 | to also theme standard elements, such as, button and textblock etc. 83 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.2.{build} 2 | 3 | branches: 4 | only: 5 | - master 6 | 7 | before_build: 8 | - cmd: nuget restore source/SuggestBoxLib.sln 9 | 10 | build: 11 | verbosity: minimal 12 | 13 | configuration: Release 14 | 15 | platform: Any CPU 16 | 17 | image: Visual Studio 2019 Preview 18 | 19 | install: 20 | - cmd: choco install dotnetcore-sdk --pre 21 | 22 | artifacts: 23 | - path: source\SuggestBoxLib\bin\Release 24 | name: SuggestBoxLib 25 | 26 | - path: source\Demos\SuggestBoxDemo\bin\Release 27 | name: SuggestBoxDemo 28 | 29 | - path: source\Demos\ThemedSuggestBoxDemo\bin\Release 30 | name: ThemedSuggestBoxDemo 31 | -------------------------------------------------------------------------------- /source/.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | packages/ 3 | debug/ 4 | release/ 5 | build/ 6 | bin/ 7 | obj/ 8 | cache/ 9 | log/ 10 | tmp/ 11 | 12 | *~ 13 | *.lock 14 | *.DS_Store 15 | *.swp 16 | *.out 17 | *.sou 18 | -------------------------------------------------------------------------------- /source/CleanAll.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | pushd "%~dp0" 3 | ECHO. 4 | ECHO. 5 | ECHO. 6 | ECHO This script deletes all temporary build files in their 7 | ECHO corresponding BIN and OBJ Folder contained in the following projects 8 | ECHO. 9 | ECHO SuggestBoxLib 10 | ECHO. 11 | ECHO Components\ServiceLocator 12 | ECHO Components\Settings\Settings 13 | ECHO Components\Settings\SettingsModel 14 | ECHO. 15 | ECHO Demos\SuggestBox\SuggestBoxDemo 16 | ECHO Demos\SuggestBox\SuggestBoxTestLib 17 | ECHO Demos\SuggestBox\ThemedSuggestBoxDemo 18 | ECHO. 19 | REM Ask the user if hes really sure to continue beyond this point XXXXXXXX 20 | set /p choice=Are you sure to continue (Y/N)? 21 | if not '%choice%'=='Y' Goto EndOfBatch 22 | REM Script does not continue unless user types 'Y' in upper case letter 23 | ECHO. 24 | ECHO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 25 | ECHO. 26 | ECHO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 27 | 28 | RMDIR /S /Q .vs 29 | 30 | ECHO. 31 | ECHO Deleting BIN and OBJ Folders in SuggestLib folder 32 | ECHO. 33 | RMDIR /S /Q SuggestBoxLib\bin 34 | RMDIR /S /Q SuggestBoxLib\obj 35 | 36 | ECHO. 37 | 38 | ECHO Deleting BIN and OBJ Folders in ServiceLocator folder 39 | ECHO. 40 | RMDIR /S /Q Components\ServiceLocator\bin 41 | RMDIR /S /Q Components\ServiceLocator\obj 42 | 43 | ECHO Deleting BIN and OBJ Folders in Settings\Settings folder 44 | ECHO. 45 | RMDIR /S /Q Components\Settings\Settings\bin 46 | RMDIR /S /Q Components\Settings\Settings\obj 47 | 48 | ECHO Deleting BIN and OBJ Folders in Settings\SettingsModel folder 49 | ECHO. 50 | RMDIR /S /Q Components\Settings\SettingsModel\bin 51 | RMDIR /S /Q Components\Settings\SettingsModel\obj 52 | 53 | ECHO. 54 | ECHO Deleting BIN and OBJ Folders in Demos\SuggestBox\SuggestBoxDemo folder 55 | ECHO. 56 | RMDIR /S /Q Demos\SuggestBoxDemo\bin 57 | RMDIR /S /Q Demos\SuggestBoxDemo\obj 58 | ECHO. 59 | 60 | ECHO. 61 | ECHO Deleting BIN and OBJ Folders in Demos\SuggestBox\ThemedSuggestBoxDemo folder 62 | ECHO. 63 | RMDIR /S /Q Demos\ThemedSuggestBoxDemo\bin 64 | RMDIR /S /Q Demos\ThemedSuggestBoxDemo\obj 65 | ECHO. 66 | 67 | ECHO. 68 | ECHO Deleting BIN and OBJ Folders in Demos\SuggestBox\SuggestBoxTestLib folder 69 | ECHO. 70 | RMDIR /S /Q Demos\SuggestBoxTestLib\bin 71 | RMDIR /S /Q Demos\SuggestBoxTestLib\obj 72 | ECHO. 73 | 74 | PAUSE 75 | 76 | :EndOfBatch -------------------------------------------------------------------------------- /source/Components/ServiceLocator/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ServiceLocator")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("HP")] 12 | [assembly: AssemblyProduct("ServiceLocator")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("2516097b-2435-44a4-a9b8-9899bca81a6e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /source/Components/ServiceLocator/ServiceContainer.cs: -------------------------------------------------------------------------------- 1 | namespace ServiceLocator 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | /// 7 | /// Source: http://www.codeproject.com/Articles/70223/Using-a-Service-Locator-to-Work-with-MessageBoxes 8 | /// 9 | public class ServiceContainer 10 | { 11 | #region fields 12 | public static readonly ServiceContainer Instance = new ServiceContainer(); 13 | 14 | readonly Dictionary _serviceMap; 15 | readonly object _serviceMapLock; 16 | #endregion fields 17 | 18 | #region constructors 19 | /// 20 | /// Class Constructor 21 | /// 22 | private ServiceContainer() 23 | { 24 | _serviceMap = new Dictionary(); 25 | _serviceMapLock = new object(); 26 | } 27 | #endregion constructors 28 | 29 | #region methods 30 | public void AddService(TServiceContract implementation) 31 | where TServiceContract : class 32 | { 33 | lock (_serviceMapLock) 34 | { 35 | _serviceMap[typeof(TServiceContract)] = implementation; 36 | } 37 | } 38 | 39 | public TServiceContract GetService() 40 | where TServiceContract : class 41 | { 42 | object service; 43 | lock (_serviceMapLock) 44 | { 45 | _serviceMap.TryGetValue(typeof(TServiceContract), out service); 46 | } 47 | 48 | return service as TServiceContract; 49 | } 50 | #endregion methods 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /source/Components/ServiceLocator/ServiceLocator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {252126D1-E1D9-49C3-910B-FCF2266265EF} 8 | Library 9 | Properties 10 | ServiceLocator 11 | ServiceLocator 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | true 34 | bin\x64\Debug\ 35 | DEBUG;TRACE 36 | full 37 | x64 38 | prompt 39 | MinimumRecommendedRules.ruleset 40 | 41 | 42 | bin\x64\Release\ 43 | TRACE 44 | true 45 | pdbonly 46 | x64 47 | prompt 48 | MinimumRecommendedRules.ruleset 49 | 50 | 51 | true 52 | bin\x86\Debug\ 53 | DEBUG;TRACE 54 | full 55 | x86 56 | prompt 57 | MinimumRecommendedRules.ruleset 58 | 59 | 60 | bin\x86\Release\ 61 | TRACE 62 | true 63 | pdbonly 64 | x86 65 | prompt 66 | MinimumRecommendedRules.ruleset 67 | 68 | 69 | true 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 90 | -------------------------------------------------------------------------------- /source/Components/Settings/Settings/Interfaces/IOptions.cs: -------------------------------------------------------------------------------- 1 | namespace Settings.Interfaces 2 | { 3 | public interface IOptions 4 | { 5 | #region properties 6 | 7 | bool IsDirty { get; set; } 8 | string LanguageSelected { get; set; } 9 | bool ReloadOpenFilesOnAppStart { get; set; } 10 | string SourceFilePath { get; set; } 11 | 12 | string DefaultSourceLanguage { get; set; } 13 | string DefaultTargetLanguage { get; set; } 14 | 15 | string DefaultDefaultSourceLanguage { get; } 16 | string DefaultDefaultTargetLanguage { get; } 17 | 18 | int DefaultIconSize { get; } 19 | int IconSizeMin { get; } 20 | int IconSizeMax { get; } 21 | 22 | int DefaultFontSize { get; } 23 | int FontSizeMin { get; } 24 | int FontSizeMax { get; } 25 | 26 | #endregion properties 27 | 28 | #region methods 29 | 30 | /// 31 | /// Reset the dirty flag (e.g. after saving program options when they where edit). 32 | /// 33 | /// 34 | void SetDirtyFlag(bool flag); 35 | 36 | void SetIconSize(int size); 37 | 38 | void SetFontSize(int size); 39 | 40 | #endregion methods 41 | } 42 | } -------------------------------------------------------------------------------- /source/Components/Settings/Settings/Interfaces/IOptionsPanel.cs: -------------------------------------------------------------------------------- 1 | namespace Settings.Interfaces 2 | { 3 | using SettingsModel.Interfaces; 4 | 5 | public interface IOptionsPanel 6 | { 7 | IEngine Options { get; } 8 | } 9 | } -------------------------------------------------------------------------------- /source/Components/Settings/Settings/Interfaces/IProfile.cs: -------------------------------------------------------------------------------- 1 | namespace Settings.Interfaces 2 | { 3 | using Settings.UserProfile; 4 | using SettingsModel.Models; 5 | using System.Collections.Generic; 6 | 7 | public interface IProfile 8 | { 9 | #region properties 10 | 11 | string GetLastActivePath(); 12 | 13 | string LastActiveSolution { get; set; } 14 | 15 | string LastActiveTargetFile { get; set; } 16 | 17 | List LastActiveSourceFiles { get; set; } 18 | 19 | /// 20 | /// Gets the key name of the MainWindow item in the collection. 21 | /// Ths name can be used as key in the WindowPosSz property 22 | /// to read and write MainWindow position and size information. 23 | /// 24 | string MainWindowName { get; } 25 | 26 | /// 27 | /// Gets a collection of window position and size items. 28 | /// 29 | SerializableDictionary WindowPosSz { get; } 30 | 31 | #endregion properties 32 | 33 | #region methods 34 | 35 | /// 36 | /// Checks the MainWindow for visibility when re-starting application 37 | /// (with different screen configuration). 38 | /// 39 | /// 40 | /// 41 | void CheckSettingsOnLoad(double SystemParameters_VirtualScreenLeft, double SystemParameters_VirtualScreenTop); 42 | 43 | /// 44 | /// Updates or inserts the requested window pos size item in the collection. 45 | /// 46 | /// 47 | /// 48 | /// 49 | void UpdateInsertWindowPosSize(string windowName, ViewPosSizeModel model); 50 | 51 | #endregion methods 52 | } 53 | } -------------------------------------------------------------------------------- /source/Components/Settings/Settings/Interfaces/ISettingsManager.cs: -------------------------------------------------------------------------------- 1 | namespace Settings.Interfaces 2 | { 3 | using MLib.Interfaces; 4 | using Settings.ProgramSettings; 5 | using System.Collections.Generic; 6 | using System.Xml.Serialization; 7 | 8 | public interface ISettingsManager : IOptionsPanel 9 | { 10 | void CheckSettingsOnLoad(double SystemParameters_VirtualScreenLeft, double SystemParameters_VirtualScreenTop); 11 | 12 | ////void LoadOptions(string settingsFileName); 13 | void LoadSessionData(string sessionDataFileName); 14 | 15 | ////bool SaveOptions(string settingsFileName, Settings.Interfaces.IOptions optionsModel); 16 | bool SaveSessionData(string sessionDataFileName, Settings.Interfaces.IProfile model); 17 | 18 | /// 19 | /// Get a list of all supported languages in Edi. 20 | /// 21 | /// 22 | IEnumerable GetSupportedLanguages(); 23 | 24 | #region properties 25 | 26 | Settings.Interfaces.IProfile SessionData { get; } 27 | 28 | int IconSizeMin { get; } 29 | int IconSizeMax { get; } 30 | 31 | int FontSizeMin { get; } 32 | int FontSizeMax { get; } 33 | 34 | /// 35 | /// Gets the default icon size for the application. 36 | /// 37 | int DefaultIconSize { get; } 38 | 39 | /// 40 | /// Gets the default font size for the application. 41 | /// 42 | int DefaultFontSize { get; } 43 | 44 | /// 45 | /// Gets the default fixed font size for the application. 46 | /// 47 | int DefaultFixedFontSize { get; } 48 | 49 | /// 50 | /// Gets the internal name and Uri source for all available themes. 51 | /// 52 | [XmlIgnore] 53 | IThemeInfos Themes { get; } 54 | 55 | #endregion properties 56 | } 57 | } -------------------------------------------------------------------------------- /source/Components/Settings/Settings/Interfaces/IViewPosSizeModel.cs: -------------------------------------------------------------------------------- 1 | namespace Settings.Interfaces 2 | { 3 | public interface IViewPosSizeModel 4 | { 5 | bool DefaultConstruct { get; } 6 | double Height { get; set; } 7 | bool IsMaximized { get; set; } 8 | double Width { get; set; } 9 | double X { get; set; } 10 | double Y { get; set; } 11 | 12 | void SetValidPos(double SystemParameters_VirtualScreenLeft, double SystemParameters_VirtualScreenTop); 13 | } 14 | } -------------------------------------------------------------------------------- /source/Components/Settings/Settings/ProgramSettings/LanguageCollection.cs: -------------------------------------------------------------------------------- 1 | namespace Settings.ProgramSettings 2 | { 3 | using System; 4 | 5 | /// 6 | /// Base class for enumeration over languages (and their locale) that 7 | /// are supported with specific (non-English) button and tool tip strings. 8 | /// 9 | /// The class definition is based on BCP 47 which in turn is used to 10 | /// set the UI and thread culture (which in turn selects the correct 11 | /// string resource in MsgBox assembly). 12 | /// 13 | public class LanguageCollection 14 | { 15 | public string Language { get; set; } 16 | public string Locale { get; set; } 17 | public string Name { get; set; } 18 | 19 | /// 20 | /// Get BCP47 language tag for this language 21 | /// See also http://en.wikipedia.org/wiki/IETF_language_tag 22 | /// 23 | public string BCP47 24 | { 25 | get 26 | { 27 | if (string.IsNullOrEmpty(Locale) == false) 28 | return String.Format("{0}-{1}", Language, Locale); 29 | else 30 | return String.Format("{0}", Language); 31 | } 32 | } 33 | 34 | /// 35 | /// Get BCP47 language tag for this language 36 | /// See also http://en.wikipedia.org/wiki/IETF_language_tag 37 | /// 38 | public string DisplayName 39 | { 40 | get 41 | { 42 | return String.Format("{0} {1}", Name, BCP47); 43 | } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /source/Components/Settings/Settings/ProgramSettings/OptionsPanel.cs: -------------------------------------------------------------------------------- 1 | namespace Settings.ProgramSettings 2 | { 3 | using Settings.Interfaces; 4 | using SettingsModel.Interfaces; 5 | using SettingsModel.Models; 6 | 7 | internal class OptionsPanel : IOptionsPanel 8 | { 9 | private IEngine mQuery = null; 10 | 11 | public OptionsPanel() 12 | { 13 | mQuery = Factory.CreateEngine(); 14 | } 15 | 16 | /// 17 | /// Gets the options that used to manage program options. 18 | /// 19 | public IEngine Options 20 | { 21 | get 22 | { 23 | return mQuery; 24 | } 25 | 26 | private set 27 | { 28 | mQuery = value; 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /source/Components/Settings/Settings/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Settings")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("HP")] 12 | [assembly: AssemblyProduct("Settings")] 13 | [assembly: AssemblyCopyright("The MIT License (MIT) Copyright © 2013 - 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("7f13f2b5-a017-4045-8ead-f5496101a616")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /source/Components/Settings/Settings/SerializableDictionary.cs: -------------------------------------------------------------------------------- 1 | namespace Settings 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Globalization; 6 | using System.Runtime.Serialization; 7 | using System.Xml; 8 | using System.Xml.Serialization; 9 | 10 | /// 11 | /// This class represents a serializable dictionary implementation 12 | /// of the standard generic dictionary class in .Net. 13 | /// 14 | /// Source: http://www.jankowskimichal.pl/en/2010/10/serializabledictionary/ 15 | /// 16 | [Serializable] 17 | public class SerializableDictionary : Dictionary, IXmlSerializable, ISerializable 18 | { 19 | #region Private Members 20 | 21 | private XmlSerializer _keySerializer; 22 | private XmlSerializer _valueSerializer; 23 | 24 | #endregion Private Members 25 | 26 | #region Constructors 27 | 28 | public SerializableDictionary() 29 | { 30 | } 31 | 32 | public SerializableDictionary(IDictionary dictionary) 33 | : base(dictionary) 34 | { 35 | } 36 | 37 | public SerializableDictionary(IEqualityComparer comparer) 38 | : base(comparer) 39 | { 40 | } 41 | 42 | public SerializableDictionary(int capacity) 43 | : base(capacity) 44 | { 45 | } 46 | 47 | public SerializableDictionary(IDictionary dictionary, IEqualityComparer comparer) 48 | : base(dictionary, comparer) 49 | { 50 | } 51 | 52 | public SerializableDictionary(int capacity, IEqualityComparer comparer) 53 | : base(capacity, comparer) 54 | { 55 | } 56 | 57 | #endregion Constructors 58 | 59 | #region Private Properties 60 | 61 | protected XmlSerializer ValueSerializer 62 | { 63 | get { return _valueSerializer ?? (_valueSerializer = new XmlSerializer(typeof(TVal))); } 64 | } 65 | 66 | private XmlSerializer KeySerializer 67 | { 68 | get { return _keySerializer ?? (_keySerializer = new XmlSerializer(typeof(TKey))); } 69 | } 70 | 71 | #endregion Private Properties 72 | 73 | #region ISerializable Members 74 | 75 | protected SerializableDictionary(SerializationInfo info, StreamingContext context) 76 | { 77 | int itemCount = info.GetInt32("itemsCount"); 78 | for (int i = 0; i < itemCount; i++) 79 | { 80 | KeyValuePair kvp = (KeyValuePair)info.GetValue(String.Format(CultureInfo.InvariantCulture, "Item{0}", i), typeof(KeyValuePair)); 81 | Add(kvp.Key, kvp.Value); 82 | } 83 | } 84 | 85 | void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) 86 | { 87 | info.AddValue("itemsCount", Count); 88 | int itemIdx = 0; 89 | foreach (KeyValuePair kvp in this) 90 | { 91 | info.AddValue(String.Format(CultureInfo.InvariantCulture, "Item{0}", itemIdx), kvp, typeof(KeyValuePair)); 92 | itemIdx++; 93 | } 94 | } 95 | 96 | #endregion ISerializable Members 97 | 98 | #region IXmlSerializable Members 99 | 100 | void IXmlSerializable.WriteXml(XmlWriter writer) 101 | { 102 | foreach (KeyValuePair kvp in this) 103 | { 104 | writer.WriteStartElement("item"); 105 | writer.WriteStartElement("key"); 106 | KeySerializer.Serialize(writer, kvp.Key); 107 | writer.WriteEndElement(); 108 | writer.WriteStartElement("value"); 109 | ValueSerializer.Serialize(writer, kvp.Value); 110 | writer.WriteEndElement(); 111 | writer.WriteEndElement(); 112 | } 113 | } 114 | 115 | void IXmlSerializable.ReadXml(XmlReader reader) 116 | { 117 | if (reader.IsEmptyElement) 118 | { 119 | return; 120 | } 121 | // Move past container 122 | if (reader.NodeType == XmlNodeType.Element && !reader.Read()) 123 | { 124 | throw new XmlException("Error in Deserialization of SerializableDictionary"); 125 | } 126 | while (reader.NodeType != XmlNodeType.EndElement) 127 | { 128 | reader.ReadStartElement("item"); 129 | reader.ReadStartElement("key"); 130 | TKey key = (TKey)KeySerializer.Deserialize(reader); 131 | reader.ReadEndElement(); 132 | reader.ReadStartElement("value"); 133 | TVal value = (TVal)ValueSerializer.Deserialize(reader); 134 | reader.ReadEndElement(); 135 | reader.ReadEndElement(); 136 | Add(key, value); 137 | reader.MoveToContent(); 138 | } 139 | // Move past container 140 | if (reader.NodeType == XmlNodeType.EndElement) 141 | { 142 | reader.ReadEndElement(); 143 | } 144 | else 145 | { 146 | throw new XmlException("Error in Deserialization of SerializableDictionary"); 147 | } 148 | } 149 | 150 | System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() 151 | { 152 | return null; 153 | } 154 | 155 | #endregion IXmlSerializable Members 156 | } 157 | } -------------------------------------------------------------------------------- /source/Components/Settings/Settings/SettingsManager.cs: -------------------------------------------------------------------------------- 1 | namespace Settings 2 | { 3 | using MLib.Interfaces; 4 | using Settings.Interfaces; 5 | using Settings.Internal; 6 | 7 | /// 8 | /// Helper class to initialize an 9 | /// service interface. 10 | /// 11 | public sealed class SettingsManager 12 | { 13 | /// 14 | /// Hidden default constructor. 15 | /// 16 | private SettingsManager() 17 | { 18 | } 19 | 20 | /// 21 | /// Gets an instance of an object that implements the 22 | /// interface. 23 | /// 24 | /// 25 | public static ISettingsManager GetInstance(IThemeInfos themeInfos) 26 | { 27 | return new SettingsManagerImpl(themeInfos); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /source/Components/Settings/Settings/UserProfile/IViewSize.cs: -------------------------------------------------------------------------------- 1 | namespace Settings.UserProfile 2 | { 3 | using System.Windows; 4 | 5 | /// 6 | /// Provide an interface to implement saving and loading/repositioning of Window or view. 7 | /// 8 | public interface IViewSize 9 | { 10 | // 11 | // Zusammenfassung: 12 | // Ruft die Position des linken Fensterrands im Verhältnis zum Desktop ab oder legt 13 | // diese fest. 14 | // 15 | // Rückgabewerte: 16 | // Die Position des linken Fensterrands in logischen Einheiten (1/96 Zoll). 17 | double Left { get; set; } 18 | 19 | // 20 | // Zusammenfassung: 21 | // Ruft die Position des oberen Fensterrands im Verhältnis zum Desktop ab oder legt 22 | // diese fest. 23 | // 24 | // Rückgabewerte: 25 | // Die Position des oberen Fensterrands in logischen Einheiten (1/96 "). 26 | double Top { get; set; } 27 | 28 | // 29 | // Zusammenfassung: 30 | // Ruft die Breite des Elements ab bzw. legt diese fest. 31 | // 32 | // Rückgabewerte: 33 | // Die Breite des Elements in geräteunabhängige Einheiten (1/96th inch per unit).Der 34 | // Standardwert ist System.Double.NaN.Dieser Wert muss größer oder gleich 0,0 sein.In 35 | // den Hinweisen finden Sie Informationen über obere Grenzen. 36 | double Width { get; set; } 37 | 38 | // 39 | // Zusammenfassung: 40 | // Ruft die vorgeschlagene Höhe des Elements ab oder legt diese fest. 41 | // 42 | // Rückgabewerte: 43 | // Die Höhe des Elements in geräteunabhängige Einheiten (1/96th inch per unit).Der 44 | // Standardwert ist System.Double.NaN.Dieser Wert muss größer oder gleich 0,0 sein.In 45 | // den Hinweisen finden Sie Informationen über obere Grenzen. 46 | double Height { get; set; } 47 | 48 | // 49 | // Zusammenfassung: 50 | // Ruft einen Wert ab, der angibt, ob ein Fenster wiederhergestellt, minimiert oder 51 | // maximiert ist, oder legt diesen fest. 52 | // 53 | // Rückgabewerte: 54 | // Ein System.Windows.WindowState, der bestimmt, ob ein Fenster wiederhergestellt, 55 | // minimiert oder maximiert ist.Der Standardwert ist System.Windows.WindowState.Normal 56 | // (wiederhergestellt). 57 | WindowState WindowState { get; set; } 58 | } 59 | } -------------------------------------------------------------------------------- /source/Components/Settings/Settings/UserProfile/LocalizabilityAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Settings.UserProfile 4 | { 5 | internal class LocalizabilityAttribute : Attribute 6 | { 7 | } 8 | } -------------------------------------------------------------------------------- /source/Components/Settings/Settings/UserProfile/ViewSize.cs: -------------------------------------------------------------------------------- 1 | namespace Settings.UserProfile 2 | { 3 | // 50, 50, 800, 550 4 | public class ViewSize 5 | { 6 | public ViewSize(double x, double y, double width, double height) 7 | { 8 | X = x; 9 | Y = y; 10 | Width = width; 11 | Height = height; 12 | } 13 | 14 | public double X { get; private set; } 15 | public double Y { get; private set; } 16 | public double Width { get; private set; } 17 | public double Height { get; private set; } 18 | } 19 | } -------------------------------------------------------------------------------- /source/Components/Settings/Settings/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /source/Components/Settings/SettingsModel/ExtensionMethods/SecureStringExtensionMethod.cs: -------------------------------------------------------------------------------- 1 | namespace SettingsModel.ExtensionMethods 2 | { 3 | using System; 4 | using System.Runtime.InteropServices; 5 | using System.Security; 6 | 7 | /// 8 | /// Source: http://blogs.msdn.com/b/fpintos/archive/2009/06/12/how-to-properly-convert-securestring-to-string.aspx 9 | /// 10 | internal static class SecureStringExtensionMethod 11 | { 12 | public static string ConvertToUnsecureString(this SecureString securePassword) 13 | { 14 | if (securePassword == null) 15 | throw new ArgumentNullException("securePassword"); 16 | 17 | IntPtr unmanagedString = IntPtr.Zero; 18 | try 19 | { 20 | unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword); 21 | return Marshal.PtrToStringUni(unmanagedString); 22 | } 23 | finally 24 | { 25 | Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString); 26 | } 27 | } 28 | 29 | public static SecureString ConvertToSecureString(this string password) 30 | { 31 | if (password == null) 32 | throw new ArgumentNullException("password"); 33 | 34 | var securePassword = new SecureString(); 35 | foreach (char c in password) 36 | securePassword.AppendChar(c); 37 | 38 | securePassword.MakeReadOnly(); 39 | return securePassword; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /source/Components/Settings/SettingsModel/Interfaces/IOptionGroup.cs: -------------------------------------------------------------------------------- 1 | namespace SettingsModel.Interfaces 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | /// 7 | /// An option group is a logical group of options 8 | /// (setting values or preferences) of an application. 9 | /// 10 | public interface IOptionGroup 11 | { 12 | /// 13 | /// Gets the name of this options group. This name is used to 14 | /// cluster related options around a technically relevant name. 15 | /// 16 | string Name { get; } 17 | 18 | /// 19 | /// Retrieves the schema of each option in this optiongroup. 20 | /// 21 | /// 22 | IEnumerable GetOptionDefinitions(); 23 | 24 | /// 25 | /// Retrieves the schema of an option in this optiongroup. 26 | /// 27 | /// 28 | IOptionsSchema GetOptionDefinition(string optionName); 29 | 30 | /// 31 | /// Gets the value of an option in a given or null 32 | /// if either option or does not exist. 33 | /// 34 | /// Method returns false if option or are not known. 35 | /// 36 | /// 37 | /// Indicates whether option and exist or not. 38 | /// 39 | bool GetValue(string optionName, out object optValue); 40 | 41 | /// 42 | /// Gets the value of an option in a given or 43 | /// throws an exception if either option or 44 | /// does not exist. 45 | /// 46 | /// Method the requested option value if option and are known. 47 | /// 48 | /// 49 | /// 50 | object GetValue(string optionName); 51 | 52 | /// 53 | /// Gets the requested option and returns it as typed <T> value. 54 | /// The method throws an exception if: 55 | /// - requested option value is not stored as typed <T> or 56 | /// - the and option name does not exist. 57 | /// 58 | /// 59 | /// current value of this option. 60 | T GetValue(string optionName); 61 | 62 | /// 63 | /// Sets the value of a given option in this option table. 64 | /// 65 | /// 66 | /// 67 | /// 68 | bool SetValue(string optionName, object newValue); 69 | 70 | /// 71 | /// Add a list item in a list schema 72 | /// 73 | /// 74 | /// 75 | /// 76 | /// 77 | /// Returns true if item was succesfully added or false 78 | /// if schema is not a list schema. 79 | /// 80 | bool List_AddValue(string optionName, string keyName, object value); 81 | 82 | /// 83 | /// Clear all items contained in a list. 84 | /// 85 | /// 86 | /// 87 | bool List_Clear(string optionName); 88 | 89 | /// 90 | /// Create a new option that can hold a list of items. 91 | /// 92 | /// 93 | /// 94 | /// 95 | /// 96 | /// 97 | /// 98 | IOptionsSchema List_CreateOption(string optionName, Type type, bool isOptional, List list); 99 | 100 | /// 101 | /// Gets a list of current values if this schema descripes a List. 102 | /// Return a single value schema as a list of 1 item. 103 | /// 104 | /// 105 | /// 106 | IEnumerable List_GetListOfValues(string optionName); 107 | 108 | /// 109 | /// Gets a list of current keys and values if this schema 110 | /// descripes a List. 111 | /// 112 | /// Return a single value schema as a list of 1 item. 113 | /// 114 | /// 115 | /// 116 | IEnumerable> List_GetListOfKeyValues(string optionName); 117 | 118 | /// 119 | /// Resets the IsDirty flag to false to indicate that the current 120 | /// data was not changed/edited by a user request, yet. This is 121 | /// useful after defining a new options model and starting to work 122 | /// with it, as well, as after reading options from persistance... 123 | /// 124 | /// 125 | void SetUndirty(bool isDirty); 126 | } 127 | } -------------------------------------------------------------------------------- /source/Components/Settings/SettingsModel/Interfaces/IOptionsSchema.cs: -------------------------------------------------------------------------------- 1 | namespace SettingsModel.Interfaces 2 | { 3 | using SettingsModel.Models; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | /// 8 | /// Defines available schema information for 1 option. 9 | /// 10 | public interface IOptionsSchema 11 | { 12 | /// 13 | /// Gets the type of schema (list or single value) 14 | /// 15 | OptionSchemaType SchemaType { get; } 16 | 17 | /// 18 | /// Gets the name of an option. 19 | /// 20 | string OptionName { get; } 21 | 22 | /// 23 | /// Gets the type of the option being defined here. 24 | /// 25 | Type TypeOfValue { get; } 26 | 27 | /// 28 | /// Gets whether this options is optional or required. 29 | /// This is important when perisiting data and when reading 30 | /// data from persistance. 31 | /// 32 | bool IsOptional { get; } 33 | 34 | /// 35 | /// Gets the value of this option. 36 | /// 37 | object Value { get; } 38 | 39 | /// 40 | /// Gets/sets the default value of this option. 41 | /// 42 | object DefaultValue { get; } 43 | 44 | #region methods 45 | 46 | /// 47 | /// Removes the value with the specified key 48 | /// from the internal dictionary. 49 | /// 50 | /// The key of the element to remove. 51 | /// 52 | /// true if the element is successfully found and removed; otherwise, false. 53 | /// This method returns false if key is not found in 54 | /// the System.Collections.Generic.Dictionary<TKey,TValue>. 55 | /// 56 | /// Exceptions: 57 | /// System.ArgumentNullException: 58 | /// key is null. 59 | /// 60 | bool List_Remove(string key); 61 | 62 | /// 63 | /// Gets the value associated with the specified key. 64 | /// 65 | /// 66 | /// The key of the value to get. 67 | /// 68 | /// 69 | /// When this method returns, contains the value associated with the specified 70 | /// key, if the key is found; otherwise, the default value for the type of the 71 | /// value parameter. This parameter is passed uninitialized. 72 | /// 73 | /// 74 | /// true if the System.Collections.Generic.Dictionary<TKey,TValue> contains an 75 | /// element with the specified key; otherwise, false. 76 | /// 77 | /// Exceptions: 78 | /// System.ArgumentNullException: 79 | /// key is null. 80 | /// 81 | bool List_TryGetValue(string key, out object value); 82 | 83 | /// 84 | /// Sets the value of a given option in this option object. 85 | /// 86 | /// true if data actually changed (for dirty state tracking). 87 | /// Otherwise, false if requested value was already present. 88 | /// 89 | bool SetValue(object newValue); 90 | 91 | /// 92 | /// Add a list item in a list schema 93 | /// 94 | /// 95 | /// 96 | /// 97 | /// Returns true if item was succesfully added or false 98 | /// if schema is not a list schema. 99 | /// 100 | bool List_AddValue(string name, object value); 101 | 102 | /// 103 | /// Clear all items contained in a list. 104 | /// 105 | /// 106 | bool List_Clear(); 107 | 108 | /// 109 | /// Gets a list of current values if this schema descripes a List. 110 | /// Return a single value schema as a list of 1 item. 111 | /// 112 | /// 113 | IEnumerable List_GetListOfValues(); 114 | 115 | /// 116 | /// Gets a list of current keys and values if this schema 117 | /// descripes a List. 118 | /// 119 | /// Return a single value schema as a list of 1 item. 120 | /// 121 | /// 122 | IEnumerable> List_GetListOfKeyValues(); 123 | 124 | #endregion methods 125 | } 126 | } -------------------------------------------------------------------------------- /source/Components/Settings/SettingsModel/Models/Factory.cs: -------------------------------------------------------------------------------- 1 | namespace SettingsModel.Models 2 | { 3 | using SettingsModel.Interfaces; 4 | 5 | /// 6 | /// Factory class to create an 7 | /// object from a class that is otherwise unknown to the outside world. 8 | /// 9 | public static class Factory 10 | { 11 | /// 12 | /// Create a new engine object that provides all root functions required 13 | /// to model, track, persist, and load data at run-time. 14 | /// 15 | /// 16 | public static IEngine CreateEngine() 17 | { 18 | return new OptionsEngine(); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /source/Components/Settings/SettingsModel/Models/FileReference.cs: -------------------------------------------------------------------------------- 1 | namespace SettingsModel.Models 2 | { 3 | using System.Xml.Serialization; 4 | 5 | /// 6 | /// Implement a simple file reverence model to allow XML persistence 7 | /// of a List via this class. 8 | /// 9 | public class FileReference 10 | { 11 | /// 12 | /// Gets/sets the path to a file. 13 | /// 14 | [XmlAttribute(AttributeName = "path")] 15 | public string path { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /source/Components/Settings/SettingsModel/Models/XML/Converters/AlternativeDataTypeHandler.cs: -------------------------------------------------------------------------------- 1 | namespace SettingsModel.Models.XML.Converters 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Security; 6 | 7 | /// 8 | /// Holds a collection of alternative datatype 9 | /// handlers to handle datatypes that are not supported through equivalent conversion 10 | /// in alternative datatypes. 11 | /// 12 | internal class AlternativeDataTypeHandler 13 | { 14 | #region fields 15 | 16 | private readonly Dictionary converters = null; 17 | 18 | #endregion fields 19 | 20 | public AlternativeDataTypeHandler() 21 | { 22 | converters = new Dictionary(); 23 | 24 | converters.Add(typeof(SecureString), new SecureStringHandler()); 25 | } 26 | 27 | /// 28 | /// Finds an alternative datatype handler to handle datatypes that are not 29 | /// supported through equivalent conversion in alternative datatypes. 30 | /// 31 | /// 32 | /// 33 | public IAlternativeDataTypeHandler FindHandler(Type typeOfDataType2Handle) 34 | { 35 | IAlternativeDataTypeHandler ret = null; 36 | 37 | try 38 | { 39 | converters.TryGetValue(typeOfDataType2Handle, out ret); 40 | } 41 | catch 42 | { 43 | } 44 | 45 | return ret; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /source/Components/Settings/SettingsModel/Models/XML/Converters/IAlternativeDataTypeHandler.cs: -------------------------------------------------------------------------------- 1 | namespace SettingsModel.Models.XML.Converters 2 | { 3 | using System; 4 | 5 | internal interface IAlternativeDataTypeHandler 6 | { 7 | Type SourceDataType { get; } 8 | Type TargetDataType { get; } 9 | 10 | object Convert(object objectInput); 11 | 12 | object ConvertBack(object objectEncryptedData); 13 | } 14 | } -------------------------------------------------------------------------------- /source/Components/Settings/SettingsModel/Models/XML/Converters/SecureStringHandler.cs: -------------------------------------------------------------------------------- 1 | namespace SettingsModel.Models.XML.Converters 2 | { 3 | using System; 4 | using System.Security; 5 | 6 | /// 7 | /// Source of string encryption and decryption: 8 | /// http://weblogs.asp.net/jongalloway//encrypting-passwords-in-a-net-app-config-file 9 | /// 10 | internal class SecureStringHandler : SettingsModel.Models.XML.Converters.IAlternativeDataTypeHandler 11 | { 12 | #region fields 13 | 14 | private static byte[] entropy = System.Text.Encoding.Unicode.GetBytes("Salt Is Usually Not A Password"); 15 | 16 | #endregion fields 17 | 18 | #region constructors 19 | 20 | /// 21 | /// Class constructor 22 | /// 23 | public SecureStringHandler() 24 | { 25 | } 26 | 27 | #endregion constructors 28 | 29 | #region properties 30 | 31 | /// 32 | /// Gets the type of the original data type that is to be replaced 33 | /// with an alternative (typed) representation. 34 | /// 35 | public Type SourceDataType 36 | { 37 | get 38 | { 39 | return typeof(SecureString); 40 | } 41 | } 42 | 43 | /// 44 | /// Gets the type of the target data type that is to be used 45 | /// instead of the original (typed) representation. 46 | /// 47 | public Type TargetDataType 48 | { 49 | get 50 | { 51 | return typeof(string); 52 | } 53 | } 54 | 55 | #endregion properties 56 | 57 | #region methods 58 | 59 | /// 60 | /// Converts from the source datatype into the target data type representation. 61 | /// 62 | /// 63 | /// 64 | public object Convert(object objectInput) 65 | { 66 | SecureString input = objectInput as SecureString; 67 | 68 | if (input == null) 69 | return null; 70 | 71 | byte[] encryptedData = null; 72 | try 73 | { 74 | encryptedData = System.Security.Cryptography.ProtectedData.Protect( 75 | System.Text.Encoding.Unicode.GetBytes(ToInsecureString(input)), 76 | entropy, 77 | System.Security.Cryptography.DataProtectionScope.CurrentUser); 78 | 79 | string result = System.Convert.ToBase64String(encryptedData); 80 | return result; 81 | } 82 | catch (Exception) 83 | { 84 | throw; 85 | } 86 | finally 87 | { 88 | if (encryptedData != null) 89 | { 90 | for (int i = 0; i < encryptedData.Length; i++) 91 | { 92 | encryptedData[i] = 0; 93 | } 94 | encryptedData = null; 95 | } 96 | } 97 | } 98 | 99 | /// 100 | /// Converts from the target datatype into the source data type representation. 101 | /// 102 | /// 103 | /// 104 | public object ConvertBack(object objectEncryptedData) 105 | { 106 | string encryptedData = objectEncryptedData as string; 107 | 108 | if (encryptedData == null) 109 | return null; 110 | 111 | byte[] decryptedData = null; 112 | try 113 | { 114 | decryptedData = System.Security.Cryptography.ProtectedData.Unprotect( 115 | System.Convert.FromBase64String(encryptedData), 116 | entropy, 117 | System.Security.Cryptography.DataProtectionScope.CurrentUser); 118 | 119 | SecureString s = ToSecureString(System.Text.Encoding.Unicode.GetString(decryptedData)); 120 | 121 | return s; 122 | } 123 | catch 124 | { 125 | return new SecureString(); 126 | } 127 | finally 128 | { 129 | if (decryptedData != null) 130 | { 131 | for (int i = 0; i < decryptedData.Length; i++) 132 | { 133 | decryptedData[i] = 0; 134 | } 135 | decryptedData = null; 136 | } 137 | } 138 | } 139 | 140 | #region private methods 141 | 142 | private SecureString ToSecureString(string input) 143 | { 144 | SecureString secure = new SecureString(); 145 | foreach (char c in input) 146 | { 147 | secure.AppendChar(c); 148 | } 149 | secure.MakeReadOnly(); 150 | return secure; 151 | } 152 | 153 | private string ToInsecureString(SecureString input) 154 | { 155 | string returnValue = string.Empty; 156 | IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input); 157 | try 158 | { 159 | returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr); 160 | } 161 | finally 162 | { 163 | System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr); 164 | } 165 | return returnValue; 166 | } 167 | 168 | #endregion private methods 169 | 170 | #endregion methods 171 | } 172 | } -------------------------------------------------------------------------------- /source/Components/Settings/SettingsModel/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SettingsModel")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SettingsModel")] 13 | [assembly: AssemblyCopyright("The MIT License (MIT) Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9b0ba841-5a2f-4ed3-a908-253dbca70e77")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /source/Components/Settings/SettingsModel/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /source/Demos/CachedPathSuggest/CachedPathSuggest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /source/Demos/CachedPathSuggest/Infrastructure/DirectoryHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace CachedPathSuggest.Infrastructure 7 | { 8 | public static class DirectoryHelper 9 | { 10 | public static IEnumerable<(string path, string? label)>? EnumerateSubDirectories(string input) 11 | { 12 | var subDirs = EnumerateLogicalDriveOrSubDirectories(input); 13 | 14 | // ReSharper disable PossibleMultipleEnumeration 15 | return subDirs != null 16 | ? subDirs.Any() 17 | ? subDirs.Select(a => (a, (string?)null)) : EnumerateChildren(input) 18 | : new[] { (input, (string?)"Unauthorized Access") }; 19 | 20 | // Find last separator and list directories underneath with * search-pattern 21 | static IEnumerable<(string, string?)> EnumerateChildren(string input) 22 | { 23 | var sepIdx = input.LastIndexOf('\\'); 24 | 25 | if (sepIdx >= input.Length) 26 | return EnumerateLogicalDrives(); 27 | 28 | string folder = input.Substring(0, sepIdx + 1); 29 | string searchPattern = input.Substring(sepIdx + 1) + "*"; 30 | try 31 | { 32 | return Directory 33 | .GetDirectories(folder, searchPattern) 34 | .Select(a => (a, (string?)null)).ToList(); 35 | } 36 | catch 37 | { 38 | // Catch invalid path exceptions here ... 39 | return Array.Empty<(string, string?)>(); 40 | } 41 | } 42 | 43 | static IEnumerable? EnumerateLogicalDriveOrSubDirectories(string testDrive) 44 | { 45 | if (testDrive.Length < 3) return Enumerate(testDrive); 46 | 47 | return Directory.Exists(testDrive) ? TryGetDirectories(testDrive) : Array.Empty(); 48 | 49 | static string[]? TryGetDirectories(string testDrive) 50 | { 51 | try 52 | { 53 | return Directory.GetDirectories(testDrive); 54 | } 55 | catch (UnauthorizedAccessException) 56 | { 57 | return null; 58 | } 59 | } 60 | 61 | static IEnumerable? Enumerate(string input) 62 | { 63 | return (input.Length, input.TryGetUpper(0), input.TryGetUpper(1), input.TryGetUpper(2)) switch 64 | { 65 | (1, >= 'A' and <= 'Z', _, _) => new[] { input + ":\\" }.Concat(EnumerateLogicalDriveOrSubDirectories(input + ":\\") ?? Array.Empty()), 66 | (2, >= 'A' and <= 'Z', ':', _) => new[] { input + ":\\" }.Concat(EnumerateLogicalDriveOrSubDirectories(input + "\\") ?? Array.Empty()), 67 | (3, >= 'A' and <= 'Z', ':', '\\') => EnumerateLogicalDriveOrSubDirectories(input), 68 | _ => Array.Empty() 69 | }; 70 | } 71 | } 72 | } 73 | 74 | public static IEnumerable<(string path, string? label)> EnumerateLogicalDrives() 75 | { 76 | foreach (var driveName in Environment.GetLogicalDrives()) 77 | { 78 | if (string.IsNullOrEmpty(driveName)) 79 | continue; 80 | 81 | string? volumeLabel = null; 82 | 83 | try 84 | { 85 | if (new DriveInfo(driveName) is { IsReady: true } driveInfo) 86 | volumeLabel = driveInfo.VolumeLabel; 87 | } 88 | catch (IOException) 89 | { 90 | // network path not found 91 | } 92 | catch (UnauthorizedAccessException) 93 | { 94 | // can't access path 95 | } 96 | 97 | yield return (driveName, volumeLabel); 98 | } 99 | } 100 | } 101 | 102 | internal static class StringHelper 103 | { 104 | public static char TryGetUpper(this string value, int index) 105 | { 106 | return char.ToUpper(value.ElementAtOrDefault(index)); 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /source/Demos/CachedPathSuggest/Infrastructure/LiteRepository.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using LiteDB; 8 | 9 | namespace CachedPathSuggest.Infrastructure 10 | { 11 | /// 12 | /// Implements a static service provider for searching and editing a LiteDB file. 13 | /// 14 | public class LiteRepository 15 | { 16 | private const string DbPath = @"..\..\..\Data\KeyValue.litedb"; 17 | 18 | // Collection needs a name because object, keyvaluepair is generic. 19 | private const string CollectionName = "collection"; 20 | 21 | /// 22 | /// Class constructor 23 | /// 24 | public LiteRepository() 25 | { 26 | (Directory.GetParent(DbPath) ?? throw new Exception("Can't create directory")).Create(); 27 | BsonMapper.Global.Entity>().Id(x => x.Key); 28 | } 29 | 30 | public event Action? Change; 31 | 32 | /// 33 | /// Inserts a new string into the collection of bookmarked strings. 34 | /// 35 | /// 36 | /// 37 | public void Insert(string key, string? collectionName = null) 38 | { 39 | using var db = new LiteDatabase(DbPath); 40 | var col = db.GetCollection>(collectionName ?? CollectionName); 41 | col.Upsert(new KeyValuePair(key, DateTime.Now)); 42 | Change?.Invoke(); 43 | } 44 | 45 | /// 46 | /// Inserts a new string into the collection of bookmarked strings. 47 | /// 48 | /// 49 | /// 50 | public void Remove(string key, string? collectionName = null) 51 | { 52 | using var db = new LiteDatabase(DbPath); 53 | var col = db.GetCollection>(collectionName ?? CollectionName); 54 | 55 | // Make sure string is already present 56 | if (col.FindOne(x => x.Key == key) is { } one) 57 | col.Delete(key); 58 | 59 | Change?.Invoke(); 60 | } 61 | 62 | /// 63 | /// 64 | public KeyValuePair? Find(string key, string? collectionName = null) 65 | { 66 | using var db = new LiteDatabase(DbPath); 67 | var col = db.GetCollection>(collectionName ?? CollectionName); 68 | var one = col.FindOne(x => x.Key == key); 69 | return one; 70 | } 71 | 72 | /// 73 | /// Filters the collection of bookmark strings by the given string and 74 | /// returns the resulting collection. 75 | /// 76 | public IEnumerable> Filter(string key, string? collectionName = null) 77 | { 78 | using var db = new LiteDatabase(DbPath); 79 | var col = db.GetCollection>(collectionName ?? CollectionName); 80 | return string.IsNullOrWhiteSpace(key) 81 | ? col.Query().ToArray() 82 | : col.Find(Query.Contains(nameof(KeyValuePair.Key), key)).ToArray(); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /source/Demos/CachedPathSuggest/ViewModels/BaseItem.cs: -------------------------------------------------------------------------------- 1 | using Infrastructure; 2 | 3 | namespace CachedPathSuggest.ViewModels 4 | { 5 | /// 6 | /// This class is the parent root class of other lsit item related classes. 7 | /// It exists simple for methods to produce something like IEnumerable{} 8 | /// where 'BaseItem' cen be any class inheriting from . 9 | /// This enables us to use Converters, DataTemplates or other tools in WPF to display different 10 | /// UI bits for different types of classes. 11 | /// 12 | public class BaseItem : ViewModelBase 13 | { 14 | private bool isHitTestVisible; 15 | 16 | public BaseItem(string value) 17 | { 18 | Value = value; 19 | IsHitTestVisible = true; 20 | } 21 | 22 | public string Value { get; } 23 | 24 | /// 25 | /// Gets/sets a property that indicates to the UI whether the resulting list item 26 | /// should be click-able to process data or not (a separator is part of the list but should not be clicked). 27 | /// 28 | public bool IsHitTestVisible 29 | { 30 | get => isHitTestVisible; 31 | set 32 | { 33 | isHitTestVisible = value; 34 | NotifyPropertyChanged(); 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /source/Demos/CachedPathSuggest/ViewModels/ItemSeperator.cs: -------------------------------------------------------------------------------- 1 | namespace CachedPathSuggest.ViewModels 2 | { 3 | /// 4 | /// Implements a simple viewmodel for an item that should act as separator 5 | /// between 2 sub-sequent blocks of 2 different types of items. 6 | /// This type of item is usually useful in a WPF list of items where quickly 7 | /// different types of items appear with a need for displaying their content 8 | /// with a different UI (eg.: using a Converter or DataTemplate). 9 | /// 10 | public class ItemSeparator : BaseItem 11 | { 12 | /// 13 | /// Class constructor 14 | /// 15 | public ItemSeparator() : base(string.Empty) 16 | { 17 | // a separator is part of the list but should not be clicked 18 | IsHitTestVisible = false; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /source/Demos/CachedPathSuggest/ViewModels/PathInformation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace CachedPathSuggest.ViewModels 5 | { 6 | public class CachedPathInformation : PathInformation 7 | { 8 | public CachedPathInformation(DateTime storageDate, string path) : base(path) 9 | { 10 | StorageDate = storageDate; 11 | } 12 | 13 | public DateTime StorageDate { get; } 14 | 15 | public TimeSpan StorageLength => StorageDate - DateTime.Now; 16 | } 17 | 18 | /// 19 | /// Implements a simple path information object to keep track of its full name and path etc. 20 | /// 21 | public class PathInformation : BaseItem, IEquatable 22 | { 23 | /// 24 | /// Class constructor 25 | /// 26 | /// 27 | /// 28 | public PathInformation(string path, string? information = null) : base(path) 29 | { 30 | Parent = new DirectoryInfo(path).Parent == null ? path : 31 | path.EndsWith("\\") ? Path.GetDirectoryName(path) ?? string.Empty : 32 | string.Empty; 33 | 34 | FullName = path; 35 | Information = information; 36 | } 37 | 38 | /// 39 | /// Gets the name of a directory (without the path) 40 | /// 41 | public string Parent { get; } 42 | 43 | /// 44 | /// Gets the full name (including path) for a directory 45 | /// 46 | public string FullName { get; } 47 | 48 | /// 49 | /// Any other information e.g volume-information 50 | /// 51 | public string? Information { get; } 52 | 53 | public bool Equals(PathInformation? other) 54 | { 55 | if (other is null) return false; 56 | if (ReferenceEquals(this, other)) return true; 57 | return Parent == other.Parent && FullName == other.FullName; 58 | } 59 | 60 | public override bool Equals(object? obj) 61 | { 62 | if (obj is null) return false; 63 | if (ReferenceEquals(this, obj)) return true; 64 | return obj.GetType() == GetType() && Equals((PathInformation) obj); 65 | } 66 | 67 | public override int GetHashCode() 68 | { 69 | return HashCode.Combine(Parent, FullName); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /source/Demos/CachedPathSuggestBox.Demo/App.xaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | 11 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 40 | 42 | 45 | 46 | 47 | 48 | 49 | 51 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 71 | 72 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /source/Demos/CachedPathSuggestBox.Demo/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace CachedPathSuggestBox.Demo 4 | { 5 | /// 6 | /// Interaction logic for App.xaml 7 | /// 8 | public partial class App : Application 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /source/Demos/CachedPathSuggestBox.Demo/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] -------------------------------------------------------------------------------- /source/Demos/CachedPathSuggestBox.Demo/CachedPathSuggestBox.Demo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net5.0-windows 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | $(DefaultXamlRuntime) 21 | MSBuild:Compile 22 | 23 | 24 | 25 | 26 | 27 | $(DefaultXamlRuntime) 28 | MSBuild:Compile 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /source/Demos/CachedPathSuggestBox.Demo/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 46 | 47 |