This commit is contained in:
Stephan Maier
2024-08-27 08:10:27 +02:00
parent eb5c2fa502
commit 647f938eee
617 changed files with 73086 additions and 7137 deletions

View File

@@ -1,10 +1,2 @@
FSI.Lib http://desiaugetc7-088:3000/FSI/FSI.Lib.git (fetch)
FSI.Lib http://desiaugetc7-088:3000/FSI/FSI.Lib.git (push)
NHotkey http://desiaugetc7-088:3000/FSI/NHotkey.git (fetch)
NHotkey http://desiaugetc7-088:3000/FSI/NHotkey.git (push)
NotifyIconWpf http://desiaugetc7-088:3000/FSI/NotifyIconWpf.git (fetch)
NotifyIconWpf http://desiaugetc7-088:3000/FSI/NotifyIconWpf.git (push)
RadialMenu http://desiaugetc7-088:3000/FSI/RadialMenu.git (fetch)
RadialMenu http://desiaugetc7-088:3000/FSI/RadialMenu.git (push)
origin http://desiaugetc7-088:3000/FSI/FSI.Tools.git (fetch)
origin http://desiaugetc7-088:3000/FSI/FSI.Tools.git (push)
origin https://git.stephanmaier.duckdns.org/FSI.BT.IR/FSI.BT.IR.Tools.git (fetch)
origin https://git.stephanmaier.duckdns.org/FSI.BT.IR/FSI.BT.IR.Tools.git (push)

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<TargetFrameworks>net6.0-windows</TargetFrameworks>
<UseWPF>true</UseWPF>
<Version>1.6.0.0</Version>
<PackageProjectUrl>https://github.com/quicoli/WPF-AutoComplete-TextBox</PackageProjectUrl>
<RepositoryType />
<RepositoryUrl>https://github.com/quicoli/WPF-AutoComplete-TextBox</RepositoryUrl>
<PackageTags>wpf, autocomplete, usercontrol</PackageTags>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageReleaseNotes>
Better support for keyboard focus
</PackageReleaseNotes>
<Description>An auto complete textbox and combo box for WPF</Description>
</PropertyGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

View File

@@ -0,0 +1,49 @@
using System.Windows;
using System.Windows.Data;
namespace AutoCompleteTextBox
{
public class BindingEvaluator : FrameworkElement
{
#region "Fields"
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(BindingEvaluator), new FrameworkPropertyMetadata(string.Empty));
#endregion
#region "Constructors"
public BindingEvaluator(Binding binding)
{
ValueBinding = binding;
}
#endregion
#region "Properties"
public string Value
{
get => (string)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public Binding ValueBinding { get; set; }
#endregion
#region "Methods"
public string Evaluate(object dataItem)
{
DataContext = dataItem;
SetBinding(ValueProperty, ValueBinding);
return Value;
}
#endregion
}
}

View File

@@ -0,0 +1,612 @@
using System;
using System.Collections;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
namespace AutoCompleteTextBox.Editors
{
[TemplatePart(Name = PartEditor, Type = typeof(TextBox))]
[TemplatePart(Name = PartPopup, Type = typeof(Popup))]
[TemplatePart(Name = PartSelector, Type = typeof(Selector))]
[TemplatePart(Name = PartExpander, Type = typeof(Expander))]
public class AutoCompleteComboBox : Control
{
#region "Fields"
public const string PartEditor = "PART_Editor";
public const string PartPopup = "PART_Popup";
public const string PartSelector = "PART_Selector";
public const string PartExpander = "PART_Expander";
public static readonly DependencyProperty DelayProperty = DependencyProperty.Register("Delay", typeof(int), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(200));
public static readonly DependencyProperty DisplayMemberProperty = DependencyProperty.Register("DisplayMember", typeof(string), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty IconPlacementProperty = DependencyProperty.Register("IconPlacement", typeof(IconPlacement), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(IconPlacement.Left));
public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(object), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty IconVisibilityProperty = DependencyProperty.Register("IconVisibility", typeof(Visibility), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(Visibility.Visible));
public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty IsLoadingProperty = DependencyProperty.Register("IsLoading", typeof(bool), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty ItemTemplateSelectorProperty = DependencyProperty.Register("ItemTemplateSelector", typeof(DataTemplateSelector), typeof(AutoCompleteComboBox));
public static readonly DependencyProperty LoadingContentProperty = DependencyProperty.Register("LoadingContent", typeof(object), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty ProviderProperty = DependencyProperty.Register("Provider", typeof(IComboSuggestionProvider), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(null, OnSelectedItemChanged));
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(string.Empty, propertyChangedCallback: null, coerceValueCallback: null, isAnimationProhibited: false, defaultUpdateSourceTrigger: UpdateSourceTrigger.LostFocus, flags: FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static readonly DependencyProperty FilterProperty = DependencyProperty.Register("Filter", typeof(string), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty MaxLengthProperty = DependencyProperty.Register("MaxLength", typeof(int), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(0));
public static readonly DependencyProperty CharacterCasingProperty = DependencyProperty.Register("CharacterCasing", typeof(CharacterCasing), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(CharacterCasing.Normal));
public static readonly DependencyProperty MaxPopUpHeightProperty = DependencyProperty.Register("MaxPopUpHeight", typeof(int), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(600));
public static readonly DependencyProperty MaxPopUpWidthProperty = DependencyProperty.Register("MaxPopUpWidth", typeof(int), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(2000));
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register("Watermark", typeof(string), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty SuggestionBackgroundProperty = DependencyProperty.Register("SuggestionBackground", typeof(Brush), typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(Brushes.White));
private bool _isUpdatingText;
private bool _selectionCancelled;
private SuggestionsAdapter _suggestionsAdapter;
#endregion
#region "Constructors"
static AutoCompleteComboBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AutoCompleteComboBox), new FrameworkPropertyMetadata(typeof(AutoCompleteComboBox)));
}
#endregion
#region "Properties"
public int MaxPopupHeight
{
get => (int)GetValue(MaxPopUpHeightProperty);
set => SetValue(MaxPopUpHeightProperty, value);
}
public int MaxPopupWidth
{
get => (int)GetValue(MaxPopUpWidthProperty);
set => SetValue(MaxPopUpWidthProperty, value);
}
public BindingEvaluator BindingEvaluator { get; set; }
public CharacterCasing CharacterCasing
{
get => (CharacterCasing)GetValue(CharacterCasingProperty);
set => SetValue(CharacterCasingProperty, value);
}
public int MaxLength
{
get => (int)GetValue(MaxLengthProperty);
set => SetValue(MaxLengthProperty, value);
}
public int Delay
{
get => (int)GetValue(DelayProperty);
set => SetValue(DelayProperty, value);
}
public string DisplayMember
{
get => (string)GetValue(DisplayMemberProperty);
set => SetValue(DisplayMemberProperty, value);
}
public TextBox Editor { get; set; }
public Expander Expander { get; set; }
public DispatcherTimer FetchTimer { get; set; }
public string Filter
{
get => (string)GetValue(FilterProperty);
set => SetValue(FilterProperty, value);
}
public object Icon
{
get => GetValue(IconProperty);
set => SetValue(IconProperty, value);
}
public IconPlacement IconPlacement
{
get => (IconPlacement)GetValue(IconPlacementProperty);
set => SetValue(IconPlacementProperty, value);
}
public Visibility IconVisibility
{
get => (Visibility)GetValue(IconVisibilityProperty);
set => SetValue(IconVisibilityProperty, value);
}
public bool IsDropDownOpen
{
get => (bool)GetValue(IsDropDownOpenProperty);
set
{
this.Expander.IsExpanded = value;
SetValue(IsDropDownOpenProperty, value);
}
}
public bool IsLoading
{
get => (bool)GetValue(IsLoadingProperty);
set => SetValue(IsLoadingProperty, value);
}
public bool IsReadOnly
{
get => (bool)GetValue(IsReadOnlyProperty);
set => SetValue(IsReadOnlyProperty, value);
}
public Selector ItemsSelector { get; set; }
public DataTemplate ItemTemplate
{
get => (DataTemplate)GetValue(ItemTemplateProperty);
set => SetValue(ItemTemplateProperty, value);
}
public DataTemplateSelector ItemTemplateSelector
{
get => ((DataTemplateSelector)(GetValue(ItemTemplateSelectorProperty)));
set => SetValue(ItemTemplateSelectorProperty, value);
}
public object LoadingContent
{
get => GetValue(LoadingContentProperty);
set => SetValue(LoadingContentProperty, value);
}
public Popup Popup { get; set; }
public IComboSuggestionProvider Provider
{
get => (IComboSuggestionProvider)GetValue(ProviderProperty);
set => SetValue(ProviderProperty, value);
}
public object SelectedItem
{
get => GetValue(SelectedItemProperty);
set => SetValue(SelectedItemProperty, value);
}
public SelectionAdapter SelectionAdapter { get; set; }
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public string Watermark
{
get => (string)GetValue(WatermarkProperty);
set => SetValue(WatermarkProperty, value);
}
public Brush SuggestionBackground
{
get => (Brush)GetValue(SuggestionBackgroundProperty);
set => SetValue(SuggestionBackgroundProperty, value);
}
#endregion
#region "Methods"
public static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
AutoCompleteComboBox act = null;
act = d as AutoCompleteComboBox;
if (act != null)
{
if (act.Editor != null & !act._isUpdatingText)
{
act._isUpdatingText = true;
act.Editor.Text = act.BindingEvaluator.Evaluate(e.NewValue);
act._isUpdatingText = false;
}
}
}
private void ScrollToSelectedItem()
{
if (ItemsSelector is ListBox listBox && listBox.SelectedItem != null)
listBox.ScrollIntoView(listBox.SelectedItem);
}
public new BindingExpressionBase SetBinding(DependencyProperty dp, BindingBase binding){
var res = base.SetBinding(dp, binding);
CheckForParentTextBindingChange();
return res;
}
public new BindingExpressionBase SetBinding(DependencyProperty dp, String path) {
var res = base.SetBinding(dp, path);
CheckForParentTextBindingChange();
return res;
}
public new void ClearValue(DependencyPropertyKey key) {
base.ClearValue(key);
CheckForParentTextBindingChange();
}
public new void ClearValue(DependencyProperty dp) {
base.ClearValue(dp);
CheckForParentTextBindingChange();
}
private void CheckForParentTextBindingChange(bool force=false) {
var CurrentBindingMode = BindingOperations.GetBinding(this, TextProperty)?.UpdateSourceTrigger ?? UpdateSourceTrigger.Default;
if (CurrentBindingMode != UpdateSourceTrigger.PropertyChanged)//preventing going any less frequent than property changed
CurrentBindingMode = UpdateSourceTrigger.Default;
if (CurrentBindingMode == CurrentTextboxTextBindingUpdateMode && force == false)
return;
var binding = new Binding {
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = CurrentBindingMode,
Path = new PropertyPath(nameof(Text)),
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
};
CurrentTextboxTextBindingUpdateMode = CurrentBindingMode;
Editor?.SetBinding(TextBox.TextProperty, binding);
}
private UpdateSourceTrigger CurrentTextboxTextBindingUpdateMode;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Editor = Template.FindName(PartEditor, this) as TextBox;
Popup = Template.FindName(PartPopup, this) as Popup;
ItemsSelector = Template.FindName(PartSelector, this) as Selector;
Expander = Template.FindName(PartExpander, this) as Expander;
BindingEvaluator = new BindingEvaluator(new Binding(DisplayMember));
if (Editor != null)
{
Editor.TextChanged += OnEditorTextChanged;
Editor.PreviewKeyDown += OnEditorKeyDown;
Editor.LostFocus += OnEditorLostFocus;
CheckForParentTextBindingChange(true);
if (SelectedItem != null)
{
_isUpdatingText = true;
Editor.Text = BindingEvaluator.Evaluate(SelectedItem);
_isUpdatingText = false;
}
}
if (Expander != null)
{
Expander.IsExpanded = false;
Expander.Collapsed += Expander_Expanded;
Expander.Expanded += Expander_Expanded;
}
GotFocus += AutoCompleteComboBox_GotFocus;
if (Popup != null)
{
Popup.StaysOpen = false;
Popup.Opened += OnPopupOpened;
Popup.Closed += OnPopupClosed;
}
if (ItemsSelector != null)
{
SelectionAdapter = new SelectionAdapter(ItemsSelector);
SelectionAdapter.Commit += OnSelectionAdapterCommit;
SelectionAdapter.Cancel += OnSelectionAdapterCancel;
SelectionAdapter.SelectionChanged += OnSelectionAdapterSelectionChanged;
ItemsSelector.PreviewMouseDown += ItemsSelector_PreviewMouseDown;
}
}
private void Expander_Expanded(object sender, RoutedEventArgs e)
{
this.IsDropDownOpen = Expander.IsExpanded;
if (!this.IsDropDownOpen)
{
return;
}
if (_suggestionsAdapter == null)
{
_suggestionsAdapter = new SuggestionsAdapter(this);
}
if (SelectedItem != null || String.IsNullOrWhiteSpace(Editor.Text))
_suggestionsAdapter.ShowFullCollection();
}
private void ItemsSelector_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if ((e.OriginalSource as FrameworkElement)?.DataContext == null)
return;
if (!ItemsSelector.Items.Contains(((FrameworkElement)e.OriginalSource)?.DataContext))
return;
ItemsSelector.SelectedItem = ((FrameworkElement)e.OriginalSource)?.DataContext;
OnSelectionAdapterCommit(SelectionAdapter.EventCause.ItemClicked);
e.Handled = true;
}
private void AutoCompleteComboBox_GotFocus(object sender, RoutedEventArgs e)
{
Editor?.Focus();
}
private string GetDisplayText(object dataItem)
{
if (BindingEvaluator == null)
{
BindingEvaluator = new BindingEvaluator(new Binding(DisplayMember));
}
if (dataItem == null)
{
return string.Empty;
}
if (string.IsNullOrEmpty(DisplayMember))
{
return dataItem.ToString();
}
return BindingEvaluator.Evaluate(dataItem);
}
private void OnEditorKeyDown(object sender, KeyEventArgs e)
{
if (SelectionAdapter != null)
{
if (IsDropDownOpen)
SelectionAdapter.HandleKeyDown(e);
else
IsDropDownOpen = e.Key == Key.Down || e.Key == Key.Up;
}
}
private void OnEditorLostFocus(object sender, RoutedEventArgs e)
{
if (!IsKeyboardFocusWithin)
{
IsDropDownOpen = false;
}
}
private void OnEditorTextChanged(object sender, TextChangedEventArgs e)
{
Text = Editor.Text;
if (_isUpdatingText)
return;
if (FetchTimer == null)
{
FetchTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(Delay) };
FetchTimer.Tick += OnFetchTimerTick;
}
FetchTimer.IsEnabled = false;
FetchTimer.Stop();
SetSelectedItem(null);
if (Editor.Text.Length > 0)
{
FetchTimer.IsEnabled = true;
FetchTimer.Start();
}
else
{
IsDropDownOpen = false;
}
}
private void OnFetchTimerTick(object sender, EventArgs e)
{
FetchTimer.IsEnabled = false;
FetchTimer.Stop();
if (Provider != null && ItemsSelector != null)
{
Filter = Editor.Text;
if (_suggestionsAdapter == null)
{
_suggestionsAdapter = new SuggestionsAdapter(this);
}
_suggestionsAdapter.GetSuggestions(Filter);
}
}
private void OnPopupClosed(object sender, EventArgs e)
{
if (!_selectionCancelled)
{
OnSelectionAdapterCommit(SelectionAdapter.EventCause.PopupClosed);
}
}
private void OnPopupOpened(object sender, EventArgs e)
{
_selectionCancelled = false;
ItemsSelector.SelectedItem = SelectedItem;
}
public event EventHandler<SelectionAdapter.PreSelectionAdapterFinishArgs> PreSelectionAdapterFinish;
private bool PreSelectionEventSomeoneHandled(SelectionAdapter.EventCause cause, bool is_cancel) {
if (PreSelectionAdapterFinish == null)
return false;
var args = new SelectionAdapter.PreSelectionAdapterFinishArgs { cause = cause, is_cancel = is_cancel };
PreSelectionAdapterFinish?.Invoke(this, args);
return args.handled;
}
private void OnSelectionAdapterCancel(SelectionAdapter.EventCause cause)
{
if (PreSelectionEventSomeoneHandled(cause, true))
return;
_isUpdatingText = true;
Editor.Text = SelectedItem == null ? Filter : GetDisplayText(SelectedItem);
Editor.SelectionStart = Editor.Text.Length;
Editor.SelectionLength = 0;
_isUpdatingText = false;
IsDropDownOpen = false;
_selectionCancelled = true;
}
private void OnSelectionAdapterCommit(SelectionAdapter.EventCause cause)
{
if (PreSelectionEventSomeoneHandled(cause, false))
return;
if (ItemsSelector.SelectedItem != null)
{
SelectedItem = ItemsSelector.SelectedItem;
_isUpdatingText = true;
Editor.Text = GetDisplayText(ItemsSelector.SelectedItem);
SetSelectedItem(ItemsSelector.SelectedItem);
_isUpdatingText = false;
IsDropDownOpen = false;
}
}
private void OnSelectionAdapterSelectionChanged()
{
_isUpdatingText = true;
Editor.Text = ItemsSelector.SelectedItem == null ? Filter : GetDisplayText(ItemsSelector.SelectedItem);
Editor.SelectionStart = Editor.Text.Length;
Editor.SelectionLength = 0;
ScrollToSelectedItem();
_isUpdatingText = false;
}
private void SetSelectedItem(object item)
{
_isUpdatingText = true;
SelectedItem = item;
_isUpdatingText = false;
}
#endregion
#region "Nested Types"
private class SuggestionsAdapter
{
#region "Fields"
private readonly AutoCompleteComboBox _actb;
private string _filter;
#endregion
#region "Constructors"
public SuggestionsAdapter(AutoCompleteComboBox actb)
{
_actb = actb;
}
#endregion
#region "Methods"
public void GetSuggestions(string searchText)
{
_actb.IsLoading = true;
// Do not open drop down if control is not focused
if (_actb.IsKeyboardFocusWithin)
_actb.IsDropDownOpen = true;
_actb.ItemsSelector.ItemsSource = null;
ParameterizedThreadStart thInfo = GetSuggestionsAsync;
Thread th = new Thread(thInfo);
_filter = searchText;
th.Start(new object[] { searchText, _actb.Provider });
}
public void ShowFullCollection()
{
_filter = string.Empty;
_actb.IsLoading = true;
// Do not open drop down if control is not focused
if (_actb.IsKeyboardFocusWithin)
_actb.IsDropDownOpen = true;
_actb.ItemsSelector.ItemsSource = null;
ParameterizedThreadStart thInfo = GetFullCollectionAsync;
Thread th = new Thread(thInfo);
th.Start(_actb.Provider);
}
private void DisplaySuggestions(IEnumerable suggestions, string filter)
{
if (_filter != filter)
{
return;
}
_actb.IsLoading = false;
_actb.ItemsSelector.ItemsSource = suggestions;
// Close drop down if there are no items
if (_actb.IsDropDownOpen)
{
_actb.IsDropDownOpen = _actb.ItemsSelector.HasItems;
}
}
private void GetSuggestionsAsync(object param)
{
if (param is object[] args)
{
string searchText = Convert.ToString(args[0]);
if (args[1] is IComboSuggestionProvider provider)
{
IEnumerable list = provider.GetSuggestions(searchText);
_actb.Dispatcher.BeginInvoke(new Action<IEnumerable, string>(DisplaySuggestions), DispatcherPriority.Background, list, searchText);
}
}
}
private void GetFullCollectionAsync(object param)
{
if (param is IComboSuggestionProvider provider)
{
IEnumerable list = provider.GetFullCollection();
_actb.Dispatcher.BeginInvoke(new Action<IEnumerable, string>(DisplaySuggestions), DispatcherPriority.Background, list, string.Empty);
}
}
#endregion
}
#endregion
}
}

View File

@@ -0,0 +1,569 @@
using System;
using System.Collections;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
namespace AutoCompleteTextBox.Editors
{
[TemplatePart(Name = PartEditor, Type = typeof(TextBox))]
[TemplatePart(Name = PartPopup, Type = typeof(Popup))]
[TemplatePart(Name = PartSelector, Type = typeof(Selector))]
public class AutoCompleteTextBox : Control
{
#region "Fields"
public const string PartEditor = "PART_Editor";
public const string PartPopup = "PART_Popup";
public const string PartSelector = "PART_Selector";
public static readonly DependencyProperty DelayProperty = DependencyProperty.Register("Delay", typeof(int), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(200));
public static readonly DependencyProperty DisplayMemberProperty = DependencyProperty.Register("DisplayMember", typeof(string), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty IconPlacementProperty = DependencyProperty.Register("IconPlacement", typeof(IconPlacement), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(IconPlacement.Left));
public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(object), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty IconVisibilityProperty = DependencyProperty.Register("IconVisibility", typeof(Visibility), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(Visibility.Visible));
public static readonly DependencyProperty IsDropDownOpenProperty = DependencyProperty.Register("IsDropDownOpen", typeof(bool), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty IsLoadingProperty = DependencyProperty.Register("IsLoading", typeof(bool), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty ItemTemplateSelectorProperty = DependencyProperty.Register("ItemTemplateSelector", typeof(DataTemplateSelector), typeof(AutoCompleteTextBox));
public static readonly DependencyProperty LoadingContentProperty = DependencyProperty.Register("LoadingContent", typeof(object), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty ProviderProperty = DependencyProperty.Register("Provider", typeof(ISuggestionProvider), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(null));
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(null, OnSelectedItemChanged));
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(string.Empty, propertyChangedCallback:null,coerceValueCallback:null, isAnimationProhibited:false, defaultUpdateSourceTrigger: UpdateSourceTrigger.LostFocus, flags: FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static readonly DependencyProperty FilterProperty = DependencyProperty.Register("Filter", typeof(string), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty MaxLengthProperty = DependencyProperty.Register("MaxLength", typeof(int), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(0));
public static readonly DependencyProperty CharacterCasingProperty = DependencyProperty.Register("CharacterCasing", typeof(CharacterCasing), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(CharacterCasing.Normal));
public static readonly DependencyProperty MaxPopUpHeightProperty = DependencyProperty.Register("MaxPopUpHeight", typeof(int), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(600));
public static readonly DependencyProperty MaxPopUpWidthProperty = DependencyProperty.Register("MaxPopUpWidth", typeof(int), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(2000));
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register("Watermark", typeof(string), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(string.Empty));
public static readonly DependencyProperty SuggestionBackgroundProperty = DependencyProperty.Register("SuggestionBackground", typeof(Brush), typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(Brushes.White));
private bool _isUpdatingText;
private bool _selectionCancelled;
private SuggestionsAdapter _suggestionsAdapter;
#endregion
#region "Constructors"
static AutoCompleteTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(typeof(AutoCompleteTextBox)));
FocusableProperty.OverrideMetadata(typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata(true));
}
#endregion
#region "Properties"
public int MaxPopupHeight
{
get => (int)GetValue(MaxPopUpHeightProperty);
set => SetValue(MaxPopUpHeightProperty, value);
}
public int MaxPopupWidth
{
get => (int)GetValue(MaxPopUpWidthProperty);
set => SetValue(MaxPopUpWidthProperty, value);
}
public BindingEvaluator BindingEvaluator { get; set; }
public CharacterCasing CharacterCasing
{
get => (CharacterCasing)GetValue(CharacterCasingProperty);
set => SetValue(CharacterCasingProperty, value);
}
public int MaxLength
{
get => (int)GetValue(MaxLengthProperty);
set => SetValue(MaxLengthProperty, value);
}
public int Delay
{
get => (int)GetValue(DelayProperty);
set => SetValue(DelayProperty, value);
}
public string DisplayMember
{
get => (string)GetValue(DisplayMemberProperty);
set => SetValue(DisplayMemberProperty, value);
}
public TextBox Editor { get; set; }
public DispatcherTimer FetchTimer { get; set; }
public string Filter
{
get => (string)GetValue(FilterProperty);
set => SetValue(FilterProperty, value);
}
public object Icon
{
get => GetValue(IconProperty);
set => SetValue(IconProperty, value);
}
public IconPlacement IconPlacement
{
get => (IconPlacement)GetValue(IconPlacementProperty);
set => SetValue(IconPlacementProperty, value);
}
public Visibility IconVisibility
{
get => (Visibility)GetValue(IconVisibilityProperty);
set => SetValue(IconVisibilityProperty, value);
}
public bool IsDropDownOpen
{
get => (bool)GetValue(IsDropDownOpenProperty);
set => SetValue(IsDropDownOpenProperty, value);
}
public bool IsLoading
{
get => (bool)GetValue(IsLoadingProperty);
set => SetValue(IsLoadingProperty, value);
}
public bool IsReadOnly
{
get => (bool)GetValue(IsReadOnlyProperty);
set => SetValue(IsReadOnlyProperty, value);
}
public Selector ItemsSelector { get; set; }
public DataTemplate ItemTemplate
{
get => (DataTemplate)GetValue(ItemTemplateProperty);
set => SetValue(ItemTemplateProperty, value);
}
public DataTemplateSelector ItemTemplateSelector
{
get => ((DataTemplateSelector)(GetValue(ItemTemplateSelectorProperty)));
set => SetValue(ItemTemplateSelectorProperty, value);
}
public object LoadingContent
{
get => GetValue(LoadingContentProperty);
set => SetValue(LoadingContentProperty, value);
}
public Popup Popup { get; set; }
public ISuggestionProvider Provider
{
get => (ISuggestionProvider)GetValue(ProviderProperty);
set => SetValue(ProviderProperty, value);
}
public object SelectedItem
{
get => GetValue(SelectedItemProperty);
set => SetValue(SelectedItemProperty, value);
}
public SelectionAdapter SelectionAdapter { get; set; }
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public string Watermark
{
get => (string)GetValue(WatermarkProperty);
set => SetValue(WatermarkProperty, value);
}
public Brush SuggestionBackground
{
get => (Brush)GetValue(SuggestionBackgroundProperty);
set => SetValue(SuggestionBackgroundProperty, value);
}
#endregion
#region "Methods"
public static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
AutoCompleteTextBox act = null;
act = d as AutoCompleteTextBox;
if (act != null)
{
if (act.Editor != null & !act._isUpdatingText)
{
act._isUpdatingText = true;
act.Editor.Text = act.BindingEvaluator.Evaluate(e.NewValue);
act._isUpdatingText = false;
}
}
}
private void ScrollToSelectedItem()
{
if (ItemsSelector is ListBox listBox && listBox.SelectedItem != null)
listBox.ScrollIntoView(listBox.SelectedItem);
}
public new BindingExpressionBase SetBinding(DependencyProperty dp, BindingBase binding){
var res = base.SetBinding(dp, binding);
CheckForParentTextBindingChange();
return res;
}
public new BindingExpressionBase SetBinding(DependencyProperty dp, String path) {
var res = base.SetBinding(dp, path);
CheckForParentTextBindingChange();
return res;
}
public new void ClearValue(DependencyPropertyKey key) {
base.ClearValue(key);
CheckForParentTextBindingChange();
}
public new void ClearValue(DependencyProperty dp) {
base.ClearValue(dp);
CheckForParentTextBindingChange();
}
private void CheckForParentTextBindingChange(bool force=false) {
var CurrentBindingMode = BindingOperations.GetBinding(this, TextProperty)?.UpdateSourceTrigger ?? UpdateSourceTrigger.Default;
if (CurrentBindingMode != UpdateSourceTrigger.PropertyChanged)//preventing going any less frequent than property changed
CurrentBindingMode = UpdateSourceTrigger.Default;
if (CurrentBindingMode == CurrentTextboxTextBindingUpdateMode && force == false)
return;
var binding = new Binding {
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = CurrentBindingMode,
Path = new PropertyPath(nameof(Text)),
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
};
CurrentTextboxTextBindingUpdateMode = CurrentBindingMode;
Editor?.SetBinding(TextBox.TextProperty, binding);
}
private UpdateSourceTrigger CurrentTextboxTextBindingUpdateMode;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Editor = Template.FindName(PartEditor, this) as TextBox;
Editor.Focus();
Popup = Template.FindName(PartPopup, this) as Popup;
ItemsSelector = Template.FindName(PartSelector, this) as Selector;
BindingEvaluator = new BindingEvaluator(new Binding(DisplayMember));
if (Editor != null)
{
Editor.TextChanged += OnEditorTextChanged;
Editor.PreviewKeyDown += OnEditorKeyDown;
Editor.LostFocus += OnEditorLostFocus;
CheckForParentTextBindingChange(true);
if (SelectedItem != null)
{
_isUpdatingText = true;
Editor.Text = BindingEvaluator.Evaluate(SelectedItem);
_isUpdatingText = false;
}
}
GotFocus += AutoCompleteTextBox_GotFocus;
GotKeyboardFocus += AutoCompleteTextBox_GotKeyboardFocus;
if (Popup != null)
{
Popup.StaysOpen = false;
Popup.Opened += OnPopupOpened;
Popup.Closed += OnPopupClosed;
}
if (ItemsSelector != null)
{
SelectionAdapter = new SelectionAdapter(ItemsSelector);
SelectionAdapter.Commit += OnSelectionAdapterCommit;
SelectionAdapter.Cancel += OnSelectionAdapterCancel;
SelectionAdapter.SelectionChanged += OnSelectionAdapterSelectionChanged;
ItemsSelector.PreviewMouseDown += ItemsSelector_PreviewMouseDown;
}
}
private void ItemsSelector_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if ((e.OriginalSource as FrameworkElement)?.DataContext == null)
return;
if (!ItemsSelector.Items.Contains(((FrameworkElement)e.OriginalSource)?.DataContext))
return;
ItemsSelector.SelectedItem = ((FrameworkElement)e.OriginalSource)?.DataContext;
OnSelectionAdapterCommit(SelectionAdapter.EventCause.MouseDown);
e.Handled = true;
}
private void AutoCompleteTextBox_GotFocus(object sender, RoutedEventArgs e)
{
Editor?.Focus();
}
private void AutoCompleteTextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) {
if (e.NewFocus != this)
return;
if (e.OldFocus == Editor)
MoveFocus(new TraversalRequest(FocusNavigationDirection.Previous));
}
private string GetDisplayText(object dataItem)
{
if (BindingEvaluator == null)
{
BindingEvaluator = new BindingEvaluator(new Binding(DisplayMember));
}
if (dataItem == null)
{
return string.Empty;
}
if (string.IsNullOrEmpty(DisplayMember))
{
return dataItem.ToString();
}
return BindingEvaluator.Evaluate(dataItem);
}
private void OnEditorKeyDown(object sender, KeyEventArgs e)
{
if (SelectionAdapter != null)
{
if (IsDropDownOpen)
SelectionAdapter.HandleKeyDown(e);
else
IsDropDownOpen = e.Key == Key.Down || e.Key == Key.Up;
}
}
private void OnEditorLostFocus(object sender, RoutedEventArgs e)
{
if (!IsKeyboardFocusWithin)
{
IsDropDownOpen = false;
}
}
private void OnEditorTextChanged(object sender, TextChangedEventArgs e)
{
Text = Editor.Text;
if (_isUpdatingText)
return;
if (FetchTimer == null)
{
FetchTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(Delay) };
FetchTimer.Tick += OnFetchTimerTick;
}
FetchTimer.IsEnabled = false;
FetchTimer.Stop();
SetSelectedItem(null);
if (Editor.Text.Length > 0)
{
FetchTimer.IsEnabled = true;
FetchTimer.Start();
}
else
{
IsDropDownOpen = false;
}
}
private void OnFetchTimerTick(object sender, EventArgs e)
{
FetchTimer.IsEnabled = false;
FetchTimer.Stop();
if (Provider != null && ItemsSelector != null)
{
Filter = Editor.Text;
if (_suggestionsAdapter == null)
{
_suggestionsAdapter = new SuggestionsAdapter(this);
}
_suggestionsAdapter.GetSuggestions(Filter);
}
}
private void OnPopupClosed(object sender, EventArgs e)
{
if (!_selectionCancelled)
{
OnSelectionAdapterCommit(SelectionAdapter.EventCause.PopupClosed);
}
}
private void OnPopupOpened(object sender, EventArgs e)
{
_selectionCancelled = false;
ItemsSelector.SelectedItem = SelectedItem;
}
private void OnSelectionAdapterCancel(SelectionAdapter.EventCause cause)
{
if (PreSelectionEventSomeoneHandled(cause, true))
return;
_isUpdatingText = true;
Editor.Text = SelectedItem == null ? Filter : GetDisplayText(SelectedItem);
Editor.SelectionStart = Editor.Text.Length;
Editor.SelectionLength = 0;
_isUpdatingText = false;
IsDropDownOpen = false;
_selectionCancelled = true;
}
public event EventHandler<SelectionAdapter.PreSelectionAdapterFinishArgs> PreSelectionAdapterFinish;
private bool PreSelectionEventSomeoneHandled(SelectionAdapter.EventCause cause, bool is_cancel) {
if (PreSelectionAdapterFinish == null)
return false;
var args = new SelectionAdapter.PreSelectionAdapterFinishArgs { cause = cause, is_cancel = is_cancel };
PreSelectionAdapterFinish?.Invoke(this, args);
return args.handled;
}
private void OnSelectionAdapterCommit(SelectionAdapter.EventCause cause)
{
if (PreSelectionEventSomeoneHandled(cause, false))
return;
if (ItemsSelector.SelectedItem != null)
{
SelectedItem = ItemsSelector.SelectedItem;
_isUpdatingText = true;
Editor.Text = GetDisplayText(ItemsSelector.SelectedItem);
SetSelectedItem(ItemsSelector.SelectedItem);
_isUpdatingText = false;
IsDropDownOpen = false;
}
}
private void OnSelectionAdapterSelectionChanged()
{
_isUpdatingText = true;
Editor.Text = ItemsSelector.SelectedItem == null ? Filter : GetDisplayText(ItemsSelector.SelectedItem);
Editor.SelectionStart = Editor.Text.Length;
Editor.SelectionLength = 0;
ScrollToSelectedItem();
_isUpdatingText = false;
}
private void SetSelectedItem(object item)
{
_isUpdatingText = true;
SelectedItem = item;
_isUpdatingText = false;
}
#endregion
#region "Nested Types"
private class SuggestionsAdapter
{
#region "Fields"
private readonly AutoCompleteTextBox _actb;
private string _filter;
#endregion
#region "Constructors"
public SuggestionsAdapter(AutoCompleteTextBox actb)
{
_actb = actb;
}
#endregion
#region "Methods"
public void GetSuggestions(string searchText)
{
_filter = searchText;
_actb.IsLoading = true;
// Do not open drop down if control is not focused
if (_actb.IsKeyboardFocusWithin)
_actb.IsDropDownOpen = true;
_actb.ItemsSelector.ItemsSource = null;
ParameterizedThreadStart thInfo = GetSuggestionsAsync;
Thread th = new Thread(thInfo);
th.Start(new object[] { searchText, _actb.Provider });
}
private void DisplaySuggestions(IEnumerable suggestions, string filter)
{
if (_filter != filter)
{
return;
}
_actb.IsLoading = false;
_actb.ItemsSelector.ItemsSource = suggestions;
// Close drop down if there are no items
if (_actb.IsDropDownOpen)
{
_actb.IsDropDownOpen = _actb.ItemsSelector.HasItems;
}
}
private void GetSuggestionsAsync(object param)
{
if (param is object[] args)
{
string searchText = Convert.ToString(args[0]);
if (args[1] is ISuggestionProvider provider)
{
IEnumerable list = provider.GetSuggestions(searchText);
_actb.Dispatcher.BeginInvoke(new Action<IEnumerable, string>(DisplaySuggestions), DispatcherPriority.Background, list, searchText);
}
}
}
#endregion
}
#endregion
}
}

View File

@@ -0,0 +1,16 @@
using System.Collections;
namespace AutoCompleteTextBox.Editors
{
public interface IComboSuggestionProvider
{
#region Public Methods
IEnumerable GetSuggestions(string filter);
IEnumerable GetFullCollection();
#endregion Public Methods
}
}

View File

@@ -0,0 +1,15 @@
using System.Collections;
namespace AutoCompleteTextBox.Editors
{
public interface ISuggestionProvider
{
#region Public Methods
IEnumerable GetSuggestions(string filter);
#endregion Public Methods
}
}

View File

@@ -0,0 +1,122 @@
using System.Diagnostics;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
namespace AutoCompleteTextBox.Editors
{
public class SelectionAdapter
{
public class PreSelectionAdapterFinishArgs {
public EventCause cause;
public bool is_cancel;
public bool handled;
}
#region "Fields"
#endregion
#region "Constructors"
public SelectionAdapter(Selector selector)
{
SelectorControl = selector;
SelectorControl.PreviewMouseUp += OnSelectorMouseDown;
}
#endregion
#region "Events"
public enum EventCause { Other, PopupClosed, ItemClicked, EnterPressed, EscapePressed, TabPressed, MouseDown}
public delegate void CancelEventHandler(EventCause cause);
public delegate void CommitEventHandler(EventCause cause);
public delegate void SelectionChangedEventHandler();
public event CancelEventHandler Cancel;
public event CommitEventHandler Commit;
public event SelectionChangedEventHandler SelectionChanged;
#endregion
#region "Properties"
public Selector SelectorControl { get; set; }
#endregion
#region "Methods"
public void HandleKeyDown(KeyEventArgs key)
{
switch (key.Key)
{
case Key.Down:
IncrementSelection();
break;
case Key.Up:
DecrementSelection();
break;
case Key.Enter:
Commit?.Invoke(EventCause.EnterPressed);
break;
case Key.Escape:
Cancel?.Invoke(EventCause.EscapePressed);
break;
case Key.Tab:
Commit?.Invoke(EventCause.TabPressed);
break;
default:
return;
}
key.Handled = true;
}
private void DecrementSelection()
{
if (SelectorControl.SelectedIndex == -1)
{
SelectorControl.SelectedIndex = SelectorControl.Items.Count - 1;
}
else
{
SelectorControl.SelectedIndex -= 1;
}
SelectionChanged?.Invoke();
}
private void IncrementSelection()
{
if (SelectorControl.SelectedIndex == SelectorControl.Items.Count - 1)
{
SelectorControl.SelectedIndex = -1;
}
else
{
SelectorControl.SelectedIndex += 1;
}
SelectionChanged?.Invoke();
}
private void OnSelectorMouseDown(object sender, MouseButtonEventArgs e)
{
// If sender is the RepeatButton from the scrollbar we need to
// to skip this event otherwise focus get stuck in the RepeatButton
// and list is scrolled up or down til the end.
if (e.OriginalSource.GetType() != typeof(RepeatButton))
{
Commit?.Invoke(EventCause.MouseDown);
e.Handled = true;
}
}
#endregion
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections;
namespace AutoCompleteTextBox.Editors
{
public class SuggestionProvider : ISuggestionProvider
{
#region Private Fields
private readonly Func<string, IEnumerable> _method;
#endregion Private Fields
#region Public Constructors
public SuggestionProvider(Func<string, IEnumerable> method)
{
_method = method ?? throw new ArgumentNullException(nameof(method));
}
#endregion Public Constructors
#region Public Methods
public IEnumerable GetSuggestions(string filter)
{
return _method(filter);
}
#endregion Public Methods
}
}

View File

@@ -0,0 +1,268 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:editors="clr-namespace:AutoCompleteTextBox.Editors">
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
<Style x:Key="TextBoxSuggestionItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="ContentBorder" Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteTextBox}, Mode=OneWay}">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="ContentBorder" Property="Background" Value="{x:Static SystemColors.HighlightBrush}" />
<Setter Property="TextElement.Foreground" Value="{x:Static SystemColors.HighlightTextBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ComboBoxSuggestionItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="ContentBorder" Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteComboBox}, Mode=OneWay}">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="ContentBorder" Property="Background" Value="{x:Static SystemColors.HighlightBrush}" />
<Setter Property="TextElement.Foreground" Value="{x:Static SystemColors.HighlightTextBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="TransparentTextBoxStyle" TargetType="{x:Type TextBox}">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<ScrollViewer
x:Name="PART_ContentHost"
Background="Transparent"
CanContentScroll="True"
Focusable="True"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type editors:AutoCompleteTextBox}">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="#FFABADB3" />
<Setter Property="SuggestionBackground" Value="White" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Top" />
<Setter Property="AllowDrop" Value="true" />
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />
<Setter Property="Stylus.IsFlicksEnabled" Value="False" />
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type editors:AutoCompleteTextBox}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="0">
<Grid>
<DockPanel>
<ContentPresenter
x:Name="PART_Icon"
ContentSource="Icon"
Visibility="{TemplateBinding IconVisibility}" />
<Grid>
<TextBlock
x:Name="PART_Watermark"
Margin="3,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Focusable="False"
Foreground="Gray"
Text="{TemplateBinding Watermark}"
Visibility="Collapsed" />
<TextBox
x:Name="PART_Editor"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
CharacterCasing="{Binding Path=CharacterCasing, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=OneWay}"
MaxLength="{Binding Path=MaxLength, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
Style="{StaticResource ResourceKey=TransparentTextBoxStyle}" />
</Grid>
</DockPanel>
<Popup
x:Name="PART_Popup"
MinWidth="{TemplateBinding ActualWidth}"
MinHeight="25"
MaxHeight="600"
AllowsTransparency="True"
Focusable="False"
HorizontalOffset="0"
IsOpen="{Binding Path=IsDropDownOpen, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
PopupAnimation="Slide">
<Border
Padding="2"
Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteTextBox}, Mode=OneWay}"
BorderBrush="Gray"
BorderThickness="1"
CornerRadius="5">
<Grid Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteTextBox}, Mode=OneWay}">
<ListBox
x:Name="PART_Selector"
MaxWidth="{Binding Path=MaxPopupWidth, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
MaxHeight="{Binding Path=MaxPopupHeight, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteTextBox}, Mode=OneWay}"
BorderThickness="0"
Focusable="False"
ItemContainerStyle="{StaticResource ResourceKey=TextBoxSuggestionItemStyle}"
ItemTemplate="{TemplateBinding ItemTemplate}"
ItemTemplateSelector="{TemplateBinding ItemTemplateSelector}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
<Border Visibility="{Binding Path=IsLoading, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource ResourceKey=BoolToVisConverter}}">
<ContentPresenter ContentSource="LoadingContent" />
</Border>
</Grid>
</Border>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger SourceName="PART_Editor" Property="Text" Value="">
<Setter TargetName="PART_Watermark" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IconPlacement" Value="Left">
<Setter TargetName="PART_Icon" Property="DockPanel.Dock" Value="Left" />
</Trigger>
<Trigger Property="IconPlacement" Value="Right">
<Setter TargetName="PART_Icon" Property="DockPanel.Dock" Value="Right" />
</Trigger>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="editors:AutoCompleteComboBox">
<Setter Property="Focusable" Value="True" />
<Setter Property="SuggestionBackground" Value="White" />
<Setter Property="BorderThickness" Value="0,0,0,1" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Top" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="AllowDrop" Value="true" />
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst" />
<Setter Property="Stylus.IsFlicksEnabled" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type editors:AutoCompleteComboBox}">
<Grid>
<DockPanel>
<ContentPresenter
x:Name="PART_Icon"
ContentSource="Icon"
Visibility="{TemplateBinding IconVisibility}" />
<Grid>
<TextBlock
x:Name="PART_Watermark"
HorizontalAlignment="Left"
VerticalAlignment="Center"
DockPanel.Dock="Left"
Focusable="False"
Foreground="Gray"
Text="{TemplateBinding Watermark}"
Visibility="Collapsed" />
<DockPanel Margin="3,0">
<Expander x:Name="PART_Expander" DockPanel.Dock="Right" />
<TextBox
x:Name="PART_Editor"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
CharacterCasing="{Binding Path=CharacterCasing, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
Focusable="True"
MaxLength="{Binding Path=MaxLength, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}" />
</DockPanel>
</Grid>
</DockPanel>
<Popup
x:Name="PART_Popup"
MinWidth="{TemplateBinding ActualWidth}"
MinHeight="25"
MaxHeight="600"
AllowsTransparency="True"
Focusable="False"
HorizontalOffset="0"
IsOpen="{Binding Path=IsDropDownOpen, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
PopupAnimation="Slide">
<Border
Padding="2"
Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteComboBox}, Mode=OneWay}"
BorderBrush="Gray"
BorderThickness="1"
CornerRadius="5">
<Grid>
<ListBox
x:Name="PART_Selector"
MaxWidth="{Binding Path=MaxPopupWidth, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
MaxHeight="{Binding Path=MaxPopupHeight, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=TwoWay}"
Background="{Binding Path=SuggestionBackground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=editors:AutoCompleteComboBox}, Mode=OneWay}"
BorderThickness="0"
Focusable="False"
ItemContainerStyle="{StaticResource ResourceKey=ComboBoxSuggestionItemStyle}"
ItemTemplate="{TemplateBinding ItemTemplate}"
ItemTemplateSelector="{TemplateBinding ItemTemplateSelector}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
<Border Visibility="{Binding Path=IsLoading, RelativeSource={RelativeSource Mode=TemplatedParent}, Converter={StaticResource ResourceKey=BoolToVisConverter}}">
<ContentPresenter ContentSource="LoadingContent" />
</Border>
</Grid>
</Border>
</Popup>
</Grid>
<!--</Border>-->
<ControlTemplate.Triggers>
<Trigger SourceName="PART_Editor" Property="Text" Value="">
<Setter TargetName="PART_Watermark" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IconPlacement" Value="Left">
<Setter TargetName="PART_Icon" Property="DockPanel.Dock" Value="Left" />
</Trigger>
<Trigger Property="IconPlacement" Value="Right">
<Setter TargetName="PART_Icon" Property="DockPanel.Dock" Value="Right" />
</Trigger>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,8 @@
namespace AutoCompleteTextBox
{
public enum IconPlacement
{
Left,
Right
}
}

View File

@@ -0,0 +1,53 @@
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Markup;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("AutoCompleteTextBox")]
[assembly: AssemblyDescription("An autocomplete textbox for WPF")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AutoCompleteTextBox")]
[assembly: AssemblyCopyright("Copyright © 2019")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly:ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.1.0")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: XmlnsDefinition("http://wpfcontrols.com/", "AutoCompleteTextBox")]
[assembly: XmlnsDefinition("http://wpfcontrols.com/", "AutoCompleteTextBox.Editors")]

View File

@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace AutoCompleteTextBox.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AutoCompleteTextBox.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace AutoCompleteTextBox.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -0,0 +1,6 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/AutoCompleteTextBox;component/editors/themes/generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

View File

@@ -0,0 +1,64 @@
<Project Sdk="Microsoft.NET.Sdk" InitialTargets="Log">
<PropertyGroup>
<Copyright>Copyright (c) 2015-2022 by Ivan Gavryliuk</Copyright>
<AssemblyTitle>Config.Net</AssemblyTitle>
<Authors>Ivan Gavryliuk (@aloneguid)</Authors>
<AssemblyName>Config.Net</AssemblyName>
<PackageId>Config.Net</PackageId>
<AssemblyVersion>4.0.0.0</AssemblyVersion>
<FileVersion>4.7.3.0</FileVersion>
<Version>4.7.3</Version>
<Description>Super simple configuration framework for .NET focused on developer ergonomics and strong typing. Supports multiple configuration sources such as .ini, .json, .xml files, as well as external providers pluggable by other NuGet packages.</Description>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors />
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
<PackageIconUrl />
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<PackageProjectUrl>https://github.com/aloneguid/config</PackageProjectUrl>
<RepositoryUrl>https://github.com/aloneguid/config</RepositoryUrl>
</PropertyGroup>
<Choose>
<When Condition="'$(OS)' == 'Windows_NT'">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;netcoreapp3.1;net5.0;net6.0;net7.0</TargetFrameworks>
</PropertyGroup>
</Otherwise>
</Choose>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<Target Name="Log">
<Message Text="HELLO $(OS)" Importance="high" />
</Target>
<ItemGroup>
<PackageReference Include="Castle.Core" Version="5.0.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" />
</ItemGroup>
<!-- we need latest system.text.json in order to support writeable json in earlier targets -->
<ItemGroup Condition="'$(TargetFramework)' != 'net6.0'">
<PackageReference Include="System.Text.Json" Version="6.0.5" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="DotNet.ReproducibleBuilds" Version="1.1.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Castle.DynamicProxy;
using Config.Net.Core;
namespace Config.Net
{
public class ConfigurationBuilder<T> where T : class
{
private readonly ProxyGenerator _generator = new ProxyGenerator();
private List<IConfigStore> _stores = new List<IConfigStore>();
private TimeSpan _cacheInterval = TimeSpan.Zero;
private readonly List<ITypeParser> _customParsers = new List<ITypeParser>();
public ConfigurationBuilder()
{
TypeInfo ti = typeof(T).GetTypeInfo();
if (!ti.IsInterface) throw new ArgumentException($"{ti.FullName} must be an interface", ti.FullName);
}
/// <summary>
/// Creates an instance of the configuration interface
/// </summary>
/// <returns></returns>
public T Build()
{
var valueHandler = new ValueHandler(_customParsers);
var ioHandler = new IoHandler(_stores, valueHandler, _cacheInterval);
T instance = _generator.CreateInterfaceProxyWithoutTarget<T>(new InterfaceInterceptor(typeof(T), ioHandler));
return instance;
}
/// <summary>
/// Set to anything different from <see cref="TimeSpan.Zero"/> to add caching for values. By default
/// Config.Net doesn't cache any values
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
public ConfigurationBuilder<T> CacheFor(TimeSpan time)
{
_cacheInterval = time;
return this;
}
public ConfigurationBuilder<T> UseConfigStore(IConfigStore store)
{
_stores.Add(store);
return this;
}
/// <summary>
/// Adds a custom type parser
/// </summary>
public ConfigurationBuilder<T> UseTypeParser(ITypeParser parser)
{
if (parser == null)
{
throw new ArgumentNullException(nameof(parser));
}
_customParsers.Add(parser);
return this;
}
}
}

View File

@@ -0,0 +1,146 @@
using System.Reflection;
using Config.Net.Stores;
using System.Collections.Generic;
using Config.Net.Stores.Impl.CommandLine;
namespace Config.Net
{
/// <summary>
/// Configuration extensions
/// </summary>
public static class ConfigurationExtensions
{
/// <summary>
/// In-memory dictionary. Optionally you can pass pre-created dictionary, otherwise it will be created internally as empty.
/// </summary>
public static ConfigurationBuilder<TInterface> UseInMemoryDictionary<TInterface>(
this ConfigurationBuilder<TInterface> builder,
IDictionary<string, string>? container = null) where TInterface : class
{
builder.UseConfigStore(new DictionaryConfigStore(container));
return builder;
}
/// <summary>
/// Standard app.config (web.config) builder store. Read-only.
/// </summary>
public static ConfigurationBuilder<TInterface> UseAppConfig<TInterface>(this ConfigurationBuilder<TInterface> builder) where TInterface : class
{
builder.UseConfigStore(new AppConfigStore());
return builder;
}
/// <summary>
/// Reads builder from the .dll.config or .exe.config file.
/// </summary>
/// <param name="builder"></param>
/// <param name="assembly">Reference to the assembly to look for</param>
/// <returns></returns>
public static ConfigurationBuilder<TInterface> UseAssemblyConfig<TInterface>(this ConfigurationBuilder<TInterface> builder, Assembly assembly) where TInterface : class
{
builder.UseConfigStore(new AssemblyConfigStore(assembly));
return builder;
}
/// <summary>
/// Uses system environment variables
/// </summary>
public static ConfigurationBuilder<TInterface> UseEnvironmentVariables<TInterface>(this ConfigurationBuilder<TInterface> builder) where TInterface : class
{
builder.UseConfigStore(new EnvironmentVariablesStore());
return builder;
}
/// <summary>
/// Simple INI storage.
/// </summary>
/// <param name="builder"></param>
/// <param name="iniFilePath">File does not have to exist, however it will be created as soon as you try to write to it.</param>
/// <param name="parseInlineComments">When true, inline comments are parsed. It is set to false by default so inline comments are considered a part of the value.</param>
/// <returns></returns>
public static ConfigurationBuilder<TInterface> UseIniFile<TInterface>(this ConfigurationBuilder<TInterface> builder,
string iniFilePath,
bool parseInlineComments = false) where TInterface : class
{
builder.UseConfigStore(new IniFileConfigStore(iniFilePath, true, parseInlineComments));
return builder;
}
/// <summary>
/// Simple INI storage.
/// </summary>
/// <param name="builder"></param>
/// <param name="iniString">File contents</param>
/// <param name="parseInlineComments">When true, inline comments are parsed. It is set to false by default so inline comments are considered a part of the value</param>
/// <returns></returns>
public static ConfigurationBuilder<TInterface> UseIniString<TInterface>(this ConfigurationBuilder<TInterface> builder,
string iniString,
bool parseInlineComments = false) where TInterface : class
{
builder.UseConfigStore(new IniFileConfigStore(iniString, false, parseInlineComments));
return builder;
}
/// <summary>
/// Accepts builder from the command line arguments. This is not intended to replace a command line parsing framework but rather
/// complement it in a builder like way. Uses current process' command line parameters automatically
/// </summary>
/// <param name="builder">Configuration object</param>
/// <param name="isCaseSensitive">When true argument names are case sensitive, false by default</param>
/// <returns>Changed builder</returns>
public static ConfigurationBuilder<TInterface> UseCommandLineArgs<TInterface>(this ConfigurationBuilder<TInterface> builder,
bool isCaseSensitive = false,
params KeyValuePair<string, int>[] parameterNameToPosition)
where TInterface : class
{
builder.UseConfigStore(new CommandLineConfigStore(null, isCaseSensitive, parameterNameToPosition));
return builder;
}
public static ConfigurationBuilder<TInterface> UseCommandLineArgs<TInterface>(this ConfigurationBuilder<TInterface> builder,
bool isCaseSensitive = false,
string[]? args = null,
params KeyValuePair<string, int>[] parameterNameToPosition)
where TInterface : class
{
builder.UseConfigStore(new CommandLineConfigStore(args, isCaseSensitive, parameterNameToPosition));
return builder;
}
public static ConfigurationBuilder<TInterface> UseCommandLineArgs<TInterface>(this ConfigurationBuilder<TInterface> builder,
params KeyValuePair<string, int>[] parameterNameToPosition)
where TInterface : class
{
builder.UseConfigStore(new CommandLineConfigStore(null, false, parameterNameToPosition));
return builder;
}
/// <summary>
/// Uses JSON file as a builder storage.
/// </summary>
/// <param name="builder">Configuration object.</param>
/// <param name="jsonFilePath">Full path to json storage file.</param>
/// <returns>Changed builder.</returns>
/// <remarks>Storage file does not have to exist, however it will be created as soon as first write performed.</remarks>
public static ConfigurationBuilder<TInterface> UseJsonFile<TInterface>(this ConfigurationBuilder<TInterface> builder, string jsonFilePath) where TInterface : class
{
builder.UseConfigStore(new JsonConfigStore(jsonFilePath, true));
return builder;
}
/// <summary>
/// Uses JSON file as a builder storage.
/// </summary>
/// <param name="builder">Configuration object.</param>
/// <param name="jsonString">Json document.</param>
/// <returns>Changed builder.</returns>
/// <remarks>Storage file does not have to exist, however it will be created as soon as first write performed.</remarks>
public static ConfigurationBuilder<TInterface> UseJsonString<TInterface>(this ConfigurationBuilder<TInterface> builder, string jsonString) where TInterface : class
{
builder.UseConfigStore(new JsonConfigStore(jsonString, false));
return builder;
}
}
}

View File

@@ -0,0 +1,204 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
namespace Config.Net.Core.Box
{
static class BoxFactory
{
public static Dictionary<string, ResultBox> Discover(Type t, ValueHandler valueHandler, string? basePath)
{
var result = new Dictionary<string, ResultBox>();
DiscoverProperties(t, valueHandler, result, basePath);
DiscoverMethods(t, valueHandler, result);
return result;
}
private static void DiscoverProperties(Type t, ValueHandler valueHandler, Dictionary<string, ResultBox> result, string? basePath)
{
IEnumerable<PropertyInfo> properties = GetHierarchyPublicProperties(t);
foreach (PropertyInfo pi in properties)
{
Type propertyType = pi.PropertyType;
ResultBox rbox;
bool isCollection = false;
if(ResultBox.TryGetCollection(propertyType, out propertyType))
{
if(pi.SetMethod != null)
{
throw new NotSupportedException($"Collection properties cannot have a setter. Detected at '{OptionPath.Combine(basePath, pi.Name)}'");
}
isCollection = true;
}
if(propertyType.GetTypeInfo().IsInterface)
{
rbox = new ProxyResultBox(pi.Name, propertyType);
}
else
{
rbox = new PropertyResultBox(pi.Name, propertyType);
}
ValidateSupportedType(rbox, valueHandler);
AddAttributes(rbox, pi, valueHandler);
//adjust to collection
if(isCollection)
{
rbox = new CollectionResultBox(pi.Name, rbox);
AddAttributes(rbox, pi, valueHandler);
}
result[pi.Name] = rbox;
}
}
private static void DiscoverMethods(Type t, ValueHandler valueHandler, Dictionary<string, ResultBox> result)
{
TypeInfo ti = t.GetTypeInfo();
IEnumerable<MethodInfo> methods = ti.DeclaredMethods.Where(m => !m.IsSpecialName);
foreach (MethodInfo method in methods)
{
var mbox = new MethodResultBox(method);
AddAttributes(mbox, method, valueHandler);
result[mbox.Name] = mbox;
}
}
private static void ValidateSupportedType(ResultBox rb, ValueHandler valueHandler)
{
Type? t = null;
if (rb is PropertyResultBox pbox)
t = rb.ResultBaseType;
if (t != null && !valueHandler.IsSupported(t))
{
throw new NotSupportedException($"type {t} on object '{rb.Name}' is not supported.");
}
}
private static object? GetDefaultValue(Type t)
{
if (t.GetTypeInfo().IsValueType) return Activator.CreateInstance(t);
return null;
}
private static void AddAttributes(ResultBox box, PropertyInfo pi, ValueHandler valueHandler)
{
AddAttributes(box, valueHandler,
pi.GetCustomAttribute<OptionAttribute>(),
pi.GetCustomAttribute<DefaultValueAttribute>());
}
private static void AddAttributes(ResultBox box, MethodInfo mi, ValueHandler valueHandler)
{
AddAttributes(box, valueHandler, mi.GetCustomAttribute<OptionAttribute>(), mi.GetCustomAttribute<DefaultValueAttribute>());
}
private static void AddAttributes(ResultBox box, ValueHandler valueHandler, params Attribute?[] attributes)
{
OptionAttribute? optionAttribute = attributes.OfType<OptionAttribute>().FirstOrDefault();
DefaultValueAttribute? defaultValueAttribute = attributes.OfType<DefaultValueAttribute>().FirstOrDefault();
if (optionAttribute?.Alias != null)
{
box.StoreByName = optionAttribute.Alias;
}
box.DefaultResult = GetDefaultValue(optionAttribute?.DefaultValue, box, valueHandler) ??
GetDefaultValue(defaultValueAttribute?.Value, box, valueHandler) ??
GetDefaultValue(box.ResultType);
}
private static object? GetDefaultValue(object? defaultValue, ResultBox box, ValueHandler valueHandler)
{
object? result = null;
if (defaultValue != null)
{
//validate that types for default value match
Type dvt = defaultValue.GetType();
if (dvt != box.ResultType && dvt != typeof(string))
{
throw new InvalidCastException($"Default value for option {box.Name} is of type {dvt.FullName} whereas the property has type {box.ResultType.FullName}. To fix this, either set default value to type {box.ResultType.FullName} or a string parseable to the target type.");
}
if (box.ResultType != typeof(string) && dvt == typeof(string))
{
valueHandler.TryParse(box.ResultType, (string?)defaultValue, out result);
}
}
if (result == null)
{
result = defaultValue;
}
return result;
}
private static PropertyInfo[] GetHierarchyPublicProperties(Type type)
{
var propertyInfos = new List<PropertyInfo>();
var considered = new List<TypeInfo>();
var queue = new Queue<TypeInfo>();
considered.Add(type.GetTypeInfo());
queue.Enqueue(type.GetTypeInfo());
while (queue.Count > 0)
{
TypeInfo typeInfo = queue.Dequeue();
//add base interfaces to the queue
foreach (Type subInterface in typeInfo.ImplementedInterfaces)
{
TypeInfo subInterfaceTypeInfo = subInterface.GetTypeInfo();
if (considered.Contains(subInterfaceTypeInfo)) continue;
considered.Add(subInterfaceTypeInfo);
queue.Enqueue(subInterfaceTypeInfo);
}
//add base classes to the queue
if (typeInfo.BaseType != null)
{
TypeInfo baseType = typeInfo.BaseType.GetTypeInfo();
if (!considered.Contains(baseType))
{
considered.Add(baseType);
queue.Enqueue(baseType);
}
}
//get properties from the current type
IEnumerable<PropertyInfo> newProperties = typeInfo.DeclaredProperties.Where(p => !propertyInfos.Contains(p));
propertyInfos.InsertRange(0, newProperties);
}
return propertyInfos.ToArray();
}
}
}

View File

@@ -0,0 +1,109 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Config.Net.Core.Box
{
class CollectionResultBox : ResultBox
{
private readonly ResultBox _elementResultBox;
private string? _basePath;
private DynamicReader? _reader;
public CollectionResultBox(string name, ResultBox elementBox) : base(name, elementBox.ResultType, null)
{
_elementResultBox = elementBox;
}
public ResultBox ElementResultBox => _elementResultBox;
public bool IsInitialised { get; private set; }
public IEnumerable? CollectionInstance { get; private set; }
public void Initialise(string? basePath, int length, DynamicReader reader)
{
_basePath = basePath;
_reader = reader;
CollectionInstance = CreateGenericEnumerable(length);
IsInitialised = true;
}
private IEnumerable? CreateGenericEnumerable(int count)
{
Type t = typeof(DynamicEnumerable<>);
t = t.MakeGenericType(ResultType);
IEnumerable? instance = (IEnumerable?)Activator.CreateInstance(t, count, this);
return instance;
}
private object? ReadAt(int index)
{
return _reader?.Read(ElementResultBox, index);
}
private class DynamicEnumerable<T> : IEnumerable<T>
{
private readonly int _count;
private readonly CollectionResultBox _parent;
public DynamicEnumerable(int count, CollectionResultBox parent)
{
_count = count;
_parent = parent;
}
public IEnumerator<T> GetEnumerator()
{
return new DynamicEnumerator<T>(_count, _parent);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new DynamicEnumerator<T>(_count, _parent);
}
}
private class DynamicEnumerator<T> : IEnumerator<T>
{
private int _index = -1;
private readonly int _count;
private readonly CollectionResultBox _parent;
private T? _current;
public DynamicEnumerator(int count, CollectionResultBox parent)
{
_count = count;
_parent = parent;
}
#pragma warning disable CS8603 // Possible null reference return.
public T Current => _current ?? default(T);
object IEnumerator.Current => _current;
#pragma warning restore CS8603 // Possible null reference return.
public void Dispose()
{
}
public bool MoveNext()
{
_index += 1;
_current = (T?)_parent.ReadAt(_index);
return _index < _count;
}
public void Reset()
{
_index = -1;
}
}
}
}

View File

@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace Config.Net.Core.Box
{
class MethodResultBox : ResultBox
{
public MethodResultBox(MethodInfo methodInfo) : base(GetName(methodInfo), GetReturnType(methodInfo), null)
{
StoreByName = GetStoreName(methodInfo);
IsGettter = IsGet(methodInfo);
}
public bool IsGettter { get; private set; }
/// <summary>
/// Composes a uniqueue method name using method name itself and parameter type names, separated by underscore
/// </summary>
public static string GetName(MethodInfo mi)
{
ParameterInfo[] parameters = mi.GetParameters();
var sb = new StringBuilder();
sb.Append(mi.Name);
foreach (ParameterInfo pi in parameters)
{
sb.Append("-");
sb.Append(pi.ParameterType.ToString());
}
return sb.ToString();
}
public string GetValuePath(object[] arguments)
{
var sb = new StringBuilder();
sb.Append(StoreByName);
bool ignoreLast = !IsGettter;
for (int i = 0; i < arguments.Length - (ignoreLast ? 1 : 0); i++)
{
object value = arguments[i];
if (value == null) continue;
if (sb.Length > 0)
{
sb.Append(OptionPath.Separator);
}
sb.Append(value.ToString());
}
return sb.ToString();
}
private static string GetStoreName(MethodInfo mi)
{
string name = mi.Name;
if (name.StartsWith("get", StringComparison.OrdinalIgnoreCase) ||
name.StartsWith("set", StringComparison.OrdinalIgnoreCase))
{
name = name.Substring(3);
}
return name;
}
private static bool IsGet(MethodInfo mi)
{
return mi.ReturnType != typeof(void);
}
private static Type GetReturnType(MethodInfo mi)
{
ParameterInfo[] parameters = mi.GetParameters();
if (parameters == null || parameters.Length == 0)
{
throw new InvalidOperationException($"method {mi.Name} must have at least one parameter");
}
Type returnType = IsGet(mi) ? mi.ReturnType : parameters[parameters.Length - 1].ParameterType;
return returnType;
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.Reflection;
namespace Config.Net.Core.Box
{
class PropertyResultBox : ResultBox
{
public PropertyResultBox(string name, Type resultType) : base(name, resultType, null)
{
}
public static bool IsProperty(MethodInfo mi, out bool isGetter, out string? name)
{
if (mi.Name.StartsWith("get_"))
{
isGetter = true;
name = mi.Name.Substring(4);
return true;
}
if (mi.Name.StartsWith("set_"))
{
isGetter = false;
name = mi.Name.Substring(4);
return true;
}
isGetter = false;
name = null;
return false;
}
public static bool IsProperty(MethodInfo mi, out string? name)
{
if (mi.Name.StartsWith("get_") || mi.Name.StartsWith("set_"))
{
name = mi.Name.Substring(4);
return true;
}
name = null;
return false;
}
public static bool IsGetProperty(MethodInfo mi)
{
return mi.Name.StartsWith("get_");
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using Castle.DynamicProxy;
namespace Config.Net.Core.Box
{
class ProxyResultBox : ResultBox
{
private static readonly ProxyGenerator ProxyGenerator = new ProxyGenerator();
private readonly Dictionary<int, object> _indexToProxyInstance = new Dictionary<int, object>();
public ProxyResultBox(string name, Type interfaceType) : base(name, interfaceType, null)
{
}
public bool IsInitialisedAt(int index)
{
return _indexToProxyInstance.ContainsKey(index);
}
public object GetInstanceAt(int index)
{
return _indexToProxyInstance[index];
}
public void InitialiseAt(int index, IoHandler ioHandler, string prefix)
{
object instance = ProxyGenerator.CreateInterfaceProxyWithoutTarget(ResultBaseType,
new InterfaceInterceptor(ResultBaseType, ioHandler, prefix));
_indexToProxyInstance[index] = instance;
}
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
namespace Config.Net.Core.Box
{
abstract class ResultBox
{
private string? _storeByName;
protected ResultBox(string name, Type resultType, object? defaultResult)
{
Name = name;
ResultType = resultType;
ResultBaseType = GetBaseType(resultType);
DefaultResult = defaultResult;
}
public string Name { get; }
public string StoreByName
{
get => _storeByName ?? Name;
set => _storeByName = value;
}
public Type ResultType { get; }
public Type ResultBaseType { get; }
public object? DefaultResult { get; set; }
#region [ Utility Methods ]
private static Type GetBaseType(Type t)
{
TypeInfo ti = t.GetTypeInfo();
if (ti.IsClass)
{
return t;
}
else
{
if (ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return ti.GenericTypeArguments[0];
}
else
{
return t;
}
}
}
internal static bool TryGetCollection(Type t, out Type elementType)
{
TypeInfo ti = t.GetTypeInfo();
if(ti.IsGenericType && ti.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
elementType = ti.GenericTypeArguments[0];
return true;
}
elementType = t;
return false;
}
#endregion
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Text;
using Config.Net.Core.Box;
namespace Config.Net.Core
{
class DynamicReader
{
private readonly string? _basePath;
private readonly IoHandler _ioHandler;
public DynamicReader(string? basePath, IoHandler ioHandler)
{
_basePath = basePath;
_ioHandler = ioHandler;
}
public object? Read(ResultBox rbox, int index = -1, params object[] arguments)
{
if (rbox is PropertyResultBox pbox) return ReadProperty(pbox, index);
if (rbox is ProxyResultBox xbox) return ReadProxy(xbox, index);
if (rbox is CollectionResultBox cbox) return ReadCollection(cbox, index);
if (rbox is MethodResultBox mbox) return ReadMethod(mbox, arguments);
throw new NotImplementedException($"don't know how to read {rbox.GetType()}");
}
private object? ReadProperty(PropertyResultBox pbox, int index)
{
string path = OptionPath.Combine(index, _basePath, pbox.StoreByName);
return _ioHandler.Read(pbox.ResultBaseType, path, pbox.DefaultResult);
}
private object ReadProxy(ProxyResultBox xbox, int index)
{
if (!xbox.IsInitialisedAt(index))
{
string prefix = OptionPath.Combine(index, _basePath, xbox.StoreByName);
xbox.InitialiseAt(index, _ioHandler, prefix);
}
return xbox.GetInstanceAt(index);
}
private object? ReadCollection(CollectionResultBox cbox, int index)
{
string lengthPath = OptionPath.Combine(index, _basePath, cbox.StoreByName);
lengthPath = OptionPath.AddLength(lengthPath);
if (!cbox.IsInitialised)
{
int length = (int?)_ioHandler.Read(typeof(int), lengthPath, 0) ?? 0;
cbox.Initialise(_basePath, length, this);
}
return cbox.CollectionInstance;
}
private object? ReadMethod(MethodResultBox mbox, object[] arguments)
{
string path = mbox.GetValuePath(arguments);
path = OptionPath.Combine(_basePath, path);
return _ioHandler.Read(mbox.ResultBaseType, path, mbox.DefaultResult);
}
}
}

View File

@@ -0,0 +1,48 @@
using System;
using Config.Net.Core.Box;
namespace Config.Net.Core
{
class DynamicWriter
{
private readonly string? _basePath;
private readonly IoHandler _ioHandler;
public DynamicWriter(string? basePath, IoHandler ioHandler)
{
_basePath = basePath;
_ioHandler = ioHandler;
}
public void Write(ResultBox rbox, object[] arguments)
{
if (rbox is PropertyResultBox pbox) WriteProperty(pbox, arguments);
else if (rbox is MethodResultBox mbox) WriteMethod(mbox, arguments);
else if (rbox is ProxyResultBox xbox) WriteProxy(xbox, arguments);
else throw new NotImplementedException($"don't know how to write {rbox.GetType()}");
}
private void WriteProperty(PropertyResultBox pbox, object[] arguments)
{
string path = OptionPath.Combine(_basePath, pbox.StoreByName);
_ioHandler.Write(pbox.ResultBaseType, path, arguments[0]);
}
private void WriteMethod(MethodResultBox mbox, object[] arguments)
{
object value = arguments[arguments.Length - 1];
string path = mbox.GetValuePath(arguments);
_ioHandler.Write(mbox.ResultBaseType, path, value);
}
private void WriteProxy(ProxyResultBox xbox, object[] arguments)
{
throw new NotSupportedException("cannot assign values to interface properties");
}
}
}

View File

@@ -0,0 +1,16 @@
using System.Collections.Generic;
namespace Config.Net.Core
{
static class Extensions
{
public static TValue? GetValueOrDefaultInternal<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
where TKey: notnull
where TValue: class
{
if (!dictionary.TryGetValue(key, out TValue? value)) return default(TValue);
return value;
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Text;
using Config.Net.Core;
using Config.Net.TypeParsers;
namespace Config.Net.Core
{
/// <summary>
/// Helper class to implement flat arrays
/// </summary>
public static class FlatArrays
{
public static bool IsArrayLength(string? key, Func<string, string?> getValue, out int length)
{
if (!OptionPath.TryStripLength(key, out key))
{
length = 0;
return false;
}
string? value = key == null ? null : getValue(key);
if (value == null)
{
length = 0;
return false;
}
if (!StringArrayParser.TryParse(value, out string[]? ar))
{
length = 0;
return false;
}
length = ar?.Length ?? 0;
return true;
}
public static bool IsArrayElement(string? key, Func<string, string?> getValue, out string? value)
{
if(!OptionPath.TryStripIndex(key, out key, out int index))
{
value = null;
return false;
}
string? arrayString = key == null ? null : getValue(key);
if (!StringArrayParser.TryParse(arrayString, out string[]? array) || index >= array?.Length)
{
value = null;
return false;
}
value = array?[index] ?? null;
return true;
}
}
}

View File

@@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Text;
using Castle.DynamicProxy;
using Config.Net.Core.Box;
namespace Config.Net.Core
{
class InterfaceInterceptor : IInterceptor
{
private readonly Dictionary<string, ResultBox> _boxes;
private IoHandler _ioHandler;
private readonly string? _prefix;
private readonly DynamicReader _reader;
private readonly DynamicWriter _writer;
private readonly bool _isInpc;
private PropertyChangedEventHandler? _inpcHandler;
public InterfaceInterceptor(Type interfaceType, IoHandler ioHandler, string? prefix = null)
{
_boxes = BoxFactory.Discover(interfaceType, ioHandler.ValueHandler, prefix);
_ioHandler = ioHandler;
_prefix = prefix;
_reader = new DynamicReader(prefix, ioHandler);
_writer = new DynamicWriter(prefix, ioHandler);
_isInpc = interfaceType.GetInterface(nameof(INotifyPropertyChanged)) != null;
}
private ResultBox FindBox(IInvocation invocation)
{
if (PropertyResultBox.IsProperty(invocation.Method, out string? propertyName) && propertyName != null)
{
return _boxes[propertyName];
}
else //method
{
string name = MethodResultBox.GetName(invocation.Method);
return _boxes[name];
}
}
public void Intercept(IInvocation invocation)
{
if (TryInterceptInpc(invocation)) return;
ResultBox rbox = FindBox(invocation);
bool isRead =
(rbox is PropertyResultBox && PropertyResultBox.IsGetProperty(invocation.Method)) ||
(rbox is ProxyResultBox && PropertyResultBox.IsGetProperty(invocation.Method)) ||
(rbox is MethodResultBox mbox && mbox.IsGettter) ||
(rbox is CollectionResultBox);
if(isRead)
{
invocation.ReturnValue = _reader.Read(rbox, -1, invocation.Arguments);
return;
}
else
{
_writer.Write(rbox, invocation.Arguments);
TryNotifyInpc(invocation, rbox);
}
}
private bool TryInterceptInpc(IInvocation invocation)
{
if (!_isInpc) return false;
if (invocation.Method.Name == "add_PropertyChanged")
{
invocation.ReturnValue =
_inpcHandler =
(PropertyChangedEventHandler)Delegate.Combine(_inpcHandler, (Delegate)invocation.Arguments[0]);
return true;
}
else if(invocation.Method.Name == "remove_PropertyChanged")
{
invocation.ReturnValue =
_inpcHandler =
(PropertyChangedEventHandler?)Delegate.Remove(_inpcHandler, (Delegate)invocation.Arguments[0]);
return true;
}
return false;
}
private void TryNotifyInpc(IInvocation invocation, ResultBox rbox)
{
if (_inpcHandler == null || rbox is MethodResultBox) return;
_inpcHandler.Invoke(invocation.InvocationTarget, new PropertyChangedEventArgs(rbox.Name));
if(rbox.Name != rbox.StoreByName)
{
//notify on StoreByName as well
_inpcHandler.Invoke(invocation.InvocationTarget, new PropertyChangedEventArgs(rbox.StoreByName));
}
}
}
}

View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace Config.Net.Core
{
class IoHandler
{
private readonly IEnumerable<IConfigStore> _stores;
private readonly ValueHandler _valueHandler;
private readonly TimeSpan _cacheInterval;
private readonly ConcurrentDictionary<string, LazyVar<object>> _keyToValue = new ConcurrentDictionary<string, LazyVar<object>>();
public IoHandler(IEnumerable<IConfigStore> stores, ValueHandler valueHandler, TimeSpan cacheInterval)
{
_stores = stores ?? throw new ArgumentNullException(nameof(stores));
_valueHandler = valueHandler ?? throw new ArgumentNullException(nameof(valueHandler));
_cacheInterval = cacheInterval;
}
public ValueHandler ValueHandler => _valueHandler;
public object? Read(Type baseType, string path, object? defaultValue)
{
if(!_keyToValue.TryGetValue(path, out _))
{
var v = new LazyVar<object>(_cacheInterval, () => ReadNonCached(baseType, path, defaultValue));
_keyToValue[path] = v;
return v.GetValue();
}
return _keyToValue[path].GetValue();
}
public void Write(Type baseType, string path, object? value)
{
string? valueToWrite = _valueHandler.ConvertValue(baseType, value);
foreach (IConfigStore store in _stores.Where(s => s.CanWrite))
{
store.Write(path, valueToWrite);
}
}
private object? ReadNonCached(Type baseType, string path, object? defaultValue)
{
string? rawValue = ReadFirstValue(path);
return _valueHandler.ParseValue(baseType, rawValue, defaultValue);
}
private string? ReadFirstValue(string key)
{
foreach (IConfigStore store in _stores)
{
if (store.CanRead)
{
string? value = store.Read(key);
if (value != null) return value;
}
}
return null;
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using System.Threading.Tasks;
namespace Config.Net.Core
{
/// <summary>
/// Implements a lazy value i.e. that can expire in future
/// </summary>
/// <typeparam name="T"></typeparam>
class LazyVar<T> where T : class
{
private readonly Func<Task<T?>>? _renewFuncAsync;
private readonly Func<T?>? _renewFunc;
private DateTime _lastRenewed = DateTime.MinValue;
private readonly TimeSpan _timeToLive;
private T? _value;
/// <summary>
/// Creates an instance of a lazy variable with time-to-live value
/// </summary>
/// <param name="timeToLive">Time to live. Setting to <see cref="TimeSpan.Zero"/> disables caching completely</param>
/// <param name="renewFunc"></param>
public LazyVar(TimeSpan timeToLive, Func<Task<T?>> renewFunc)
{
_timeToLive = timeToLive;
_renewFuncAsync = renewFunc ?? throw new ArgumentNullException(nameof(renewFunc));
_renewFunc = null;
}
/// <summary>
/// Creates an instance of a lazy variable with time-to-live value
/// </summary>
/// <param name="timeToLive">Time to live. Setting to <see cref="TimeSpan.Zero"/> disables caching completely</param>
/// <param name="renewFunc"></param>
public LazyVar(TimeSpan timeToLive, Func<T?> renewFunc)
{
_timeToLive = timeToLive;
_renewFuncAsync = null;
_renewFunc = renewFunc ?? throw new ArgumentNullException(nameof(renewFunc));
}
/// <summary>
/// Gets the values, renewing it if necessary
/// </summary>
/// <returns>Value</returns>
public async Task<T?> GetValueAsync()
{
if (_renewFuncAsync == null)
{
throw new InvalidOperationException("cannot renew value, async delegate is not specified");
}
if (_timeToLive == TimeSpan.Zero)
{
return await _renewFuncAsync();
}
bool expired = (DateTime.UtcNow - _lastRenewed) > _timeToLive;
if (expired)
{
_value = await _renewFuncAsync();
_lastRenewed = DateTime.UtcNow;
}
return _value;
}
/// <summary>
/// Gets the values, renewing it if necessary
/// </summary>
/// <returns>Value</returns>
public T? GetValue()
{
if (_renewFunc == null)
{
throw new InvalidOperationException("cannot renew value, synchronous delegate is not specified");
}
if (_timeToLive == TimeSpan.Zero)
{
return _renewFunc();
}
bool expired = (DateTime.UtcNow - _lastRenewed) > _timeToLive;
if (expired)
{
_value = _renewFunc();
_lastRenewed = DateTime.UtcNow;
}
return _value;
}
}
}

View File

@@ -0,0 +1,88 @@
namespace Config.Net.Core
{
public static class OptionPath
{
public const string Separator = ".";
private const string IndexOpen = "[";
private const string IndexClose = "]";
public const string LengthFunction = ".$l";
public static string Combine(params string?[] parts)
{
return Combine(-1, parts);
}
public static string AddLength(string path)
{
return path + LengthFunction;
}
public static bool TryStripLength(string? path, out string? noLengthPath)
{
if (path == null)
{
noLengthPath = path;
return false;
}
if (!path.EndsWith(LengthFunction))
{
noLengthPath = path;
return false;
}
noLengthPath = path.Substring(0, path.Length - LengthFunction.Length);
return true;
}
/// <summary>
/// For indexed paths like "creds[1]" strips index part so it becomes:
/// - noIndexPath: "creds"
/// - index: 1
///
/// If path is not indexed returns false and noIndexPath is equal to path itself
/// </summary>
public static bool TryStripIndex(string? path, out string? noIndexPath, out int index)
{
if (path == null)
{
index = 0;
noIndexPath = path;
return false;
}
int openIdx = path.IndexOf(IndexOpen);
int closeIdx = path.IndexOf(IndexClose);
if (openIdx == -1 || closeIdx == -1 || openIdx > closeIdx || closeIdx != path.Length - 1)
{
noIndexPath = path;
index = 0;
return false;
}
noIndexPath = path.Substring(0, openIdx);
int.TryParse(path.Substring(openIdx + 1, closeIdx - openIdx - 1), out index);
return true;
}
public static string Combine(int index, params string?[] parts)
{
string s = string.Empty;
for (int i = 0; i < parts.Length; i++)
{
if (s.Length > 0) s += Separator;
if (!string.IsNullOrEmpty(parts[i])) s += parts[i];
}
if (index != -1)
{
s = $"{s}{IndexOpen}{index}{IndexClose}";
}
return s;
}
}
}

View File

@@ -0,0 +1,157 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Config.Net.TypeParsers;
namespace Config.Net.Core
{
class ValueHandler
{
private readonly DefaultParser _defaultParser = new DefaultParser();
private readonly ConcurrentDictionary<Type, ITypeParser> _allParsers = new ConcurrentDictionary<Type, ITypeParser>();
private readonly HashSet<Type> _supportedTypes = new HashSet<Type>();
private static readonly ValueHandler _default = new ValueHandler();
public ValueHandler(IEnumerable<ITypeParser>? customParsers = null)
{
foreach (ITypeParser pc in GetBuiltInParsers())
{
AddParser(pc);
}
if(customParsers != null)
{
foreach(ITypeParser pc in customParsers)
{
AddParser(pc);
}
}
}
public void AddParser(ITypeParser parser)
{
if (parser == null)
{
throw new ArgumentNullException(nameof(parser));
}
foreach (Type t in parser.SupportedTypes)
{
_allParsers[t] = parser;
_supportedTypes.Add(t);
}
}
public bool IsSupported(Type t)
{
return _supportedTypes.Contains(t) || _defaultParser.IsSupported(t);
}
public object? ParseValue(Type baseType, string? rawValue, object? defaultValue)
{
object? result;
if (rawValue == null)
{
result = defaultValue;
}
else
{
if(!TryParse(baseType, rawValue, out result))
{
result = defaultValue;
}
}
return result;
}
public bool TryParse(Type propertyType, string? rawValue, out object? result)
{
if (_defaultParser.IsSupported(propertyType)) //type here must be a non-nullable one
{
if (!_defaultParser.TryParse(rawValue, propertyType, out result))
{
return false;
}
}
else
{
ITypeParser? typeParser = GetParser(propertyType);
if (typeParser == null)
{
result = null;
return false;
}
if (!typeParser.TryParse(rawValue, propertyType, out result))
{
return false;
}
}
return true;
}
public string? ConvertValue(Type baseType, object? value)
{
string? str;
if (value == null)
{
str = null;
}
else
{
if (_defaultParser.IsSupported(baseType))
{
str = _defaultParser.ToRawString(value);
}
else
{
ITypeParser? parser = GetParser(value.GetType());
str = parser?.ToRawString(value);
}
}
return str;
}
private ITypeParser? GetParser(Type t)
{
ITypeParser? result;
_allParsers.TryGetValue(t, out result);
return result;
}
/// <summary>
/// Scans assembly for types implementing <see cref="ITypeParser"/> and builds Type => instance dictionary.
/// Not sure if I should use reflection here, however the assembly is small and this shouldn't cause any
/// performance issues
/// </summary>
/// <returns></returns>
private static IEnumerable<ITypeParser> GetBuiltInParsers()
{
return new ITypeParser[]
{
new FloatParser(),
new DoubleParser(),
new DecimalParser(),
new SByteParser(),
new ShortParser(),
new IntParser(),
new LongParser(),
new ByteParser(),
new UShortParser(),
new UIntParser(),
new ULongParser(),
new StringArrayParser(),
new StringParser(),
new TimeSpanParser(),
new CoreParsers(),
new NetworkCredentialParser()
};
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
namespace Config.Net
{
/// <summary>
/// Configuration store interface
/// </summary>
public interface IConfigStore : IDisposable
{
/// <summary>
/// Returns true if store supports read operation.
/// </summary>
bool CanRead { get; }
/// <summary>
/// Returns true if store supports write operation.
/// </summary>
bool CanWrite { get; }
/// <summary>
/// Reads a key from the store.
/// </summary>
/// <param name="key">Key name.</param>
/// <returns>If key exists in the store returns the value, othwise returns null.</returns>
string? Read(string key);
/// <summary>
/// Writes a key to the store.
/// </summary>
/// <param name="key">Key name</param>
/// <param name="value">Key value. Value of NULL usually means the key will be deleted, at least
/// this is the recomendation for the custom store implementers.</param>
void Write(string key, string? value);
}
}

32
Config.Net/ITypeParser.cs Normal file
View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
namespace Config.Net
{
/// <summary>
/// Type parser interface
/// </summary>
public interface ITypeParser
{
/// <summary>
/// Returns the list of supported types this type parser handles
/// </summary>
IEnumerable<Type> SupportedTypes { get; }
/// <summary>
/// Tries to parse a value from string
/// </summary>
/// <param name="value"></param>
/// <param name="t"></param>
/// <param name="result"></param>
/// <returns></returns>
bool TryParse(string? value, Type t, out object? result);
/// <summary>
/// Converts value to a string to store in a backed store
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
string? ToRawString(object? value);
}
}

View File

@@ -0,0 +1,19 @@
using System;
namespace Config.Net
{
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = false)]
public class OptionAttribute : Attribute
{
/// <summary>
/// Alias is used to override option name if it's stored by a different name in external stores
/// </summary>
public string? Alias { get; set; }
/// <summary>
/// Set to override the default value if option is not found in any stores
/// </summary>
public object? DefaultValue { get; set; }
}
}

View File

@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Config.Net.Tests")]

View File

@@ -0,0 +1,313 @@
/*using System;
using System.Reflection;
using System.Collections.Concurrent;
using Config.Net.TypeParsers;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
namespace Config.Net
{
/// <summary>
/// Generic container for test settings
/// </summary>
public abstract class SettingsContainer
{
private readonly IConfigConfiguration _config = new ContainerConfiguration();
private readonly ConcurrentDictionary<string, Option> _nameToOption =
new ConcurrentDictionary<string, Option>();
private readonly ConcurrentDictionary<string, OptionValue> _nameToOptionValue =
new ConcurrentDictionary<string, OptionValue>();
private static readonly DefaultParser DefaultParser = new DefaultParser();
private readonly string _namespace;
private bool _isConfigured;
/// <summary>
/// Constructs the container in default namespace
/// </summary>
protected SettingsContainer() : this(null)
{
}
/// <summary>
/// Constructs the container allowing to specify a custom namespace
/// </summary>
/// <param name="namespaceName"></param>
protected SettingsContainer(string namespaceName)
{
_namespace = namespaceName;
DiscoverProperties();
}
/// <summary>
/// Reads the option value
/// </summary>
/// <typeparam name="T">Option type</typeparam>
/// <param name="option">Option reference</param>
/// <returns>Option value</returns>
public T Read<T>(Option<T> option)
{
CheckConfigured();
CheckCanParse(option.NonNullableType);
OptionValue optionValue;
_nameToOptionValue.TryGetValue(option.Name, out optionValue);
if (!optionValue.IsExpired(_config.CacheTimeout))
{
return (T) optionValue.RawValue;
}
string value = ReadFirstValue(option.Name);
if (value == null)
{
optionValue.RawValue = option.DefaultValue;
}
else if (DefaultParser.IsSupported(option.NonNullableType))
{
object resultObject;
if (DefaultParser.TryParse(value, option.NonNullableType, out resultObject))
{
optionValue.Update<T>((T) resultObject);
}
else
{
optionValue.Update(option.DefaultValue);
}
}
else
{
ITypeParser typeParser = _config.GetParser(option.NonNullableType);
object result;
typeParser.TryParse(value, option.NonNullableType, out result);
optionValue.Update<T>((T) result);
}
OnReadOption(option, optionValue.RawValue);
return (T) optionValue.RawValue;
}
/// <summary>
/// Writes a new value to the option
/// </summary>
/// <typeparam name="T">Option type</typeparam>
/// <param name="option">Option reference</param>
/// <param name="value">New value</param>
public void Write<T>(Option<T> option, T value)
{
CheckConfigured();
CheckCanParse(option.NonNullableType);
OptionValue optionValue;
_nameToOptionValue.TryGetValue(option.Name, out optionValue);
foreach (IConfigStore store in _config.Stores)
{
if (store.CanWrite)
{
string rawValue = AreEqual(value, option.DefaultValue) ? null : GetRawStringValue(option, value);
store.Write(option.Name, rawValue);
break;
}
}
optionValue.Update(value);
OnWriteOption(option, value);
}
/// <summary>
/// This method is called internally before containers is ready for use. You can specify
/// configuration stores or any other options here.
/// </summary>
/// <param name="configuration"></param>
protected abstract void OnConfigure(IConfigConfiguration configuration);
/// <summary>
/// Called after any value is read
/// </summary>
/// <param name="option">Optiond that is read</param>
/// <param name="value">Option value read from a store</param>
protected virtual void OnReadOption(Option option, object value)
{
}
/// <summary>
/// Called before any value is written
/// </summary>
/// <param name="option">Option that is written</param>
/// <param name="value">Option value to write</param>
protected virtual void OnWriteOption(Option option, object value)
{
}
private void CheckConfigured()
{
if (_isConfigured) return;
OnConfigure(_config);
_isConfigured = true;
}
[Ignore]
private void DiscoverProperties()
{
Type t = this.GetType();
Type optionType = typeof(Option);
IEnumerable<PropertyInfo> properties = t.GetRuntimeProperties()
.Where(f => f.PropertyType.GetTypeInfo().IsSubclassOf(optionType) && f.GetCustomAttribute<IgnoreAttribute>() == null).ToList();
// Only include fields that have not already been added as properties
IEnumerable<FieldInfo> fields = t.GetRuntimeFields()
.Where(f => f.IsPublic && f.FieldType.GetTypeInfo().IsSubclassOf(optionType)).ToList();
foreach (PropertyInfo pi in properties)
{
AssignOption(pi.GetValue(this), pi, pi.PropertyType.GetTypeInfo(), pi.CanWrite, v => pi.SetValue(this, v));
}
foreach (FieldInfo fi in fields)
{
if (properties.Any(p => p.Name == fi.Name))
throw new ArgumentException(
$"Field '{fi.Name}' has already been defined as a property.");
var methInfo = fi.FieldType.GetTypeInfo();
if (!methInfo.IsSubclassOf(optionType)) continue;
AssignOption(fi.GetValue(this), fi, methInfo, true, v => fi.SetValue(this, v));
}
}
private void AssignOption(object objValue, MemberInfo pi, TypeInfo propInfo, bool writeable,
Action<object> setter)
{
{
//check if it has the value
if (objValue == null)
{
// Throw an exception if it's impossible to assign a default value to a read-only property with no default object assigned
if (!writeable)
throw new ArgumentException(
$"Property/Field '{pi.Name}' must either be settable or be pre-initialised with an Option<> object as a property, or marked as readonly if a field");
//create default instance if it doesn't exist
var nt = typeof(Option<>);
Type[] ntArgs = propInfo.GetGenericArguments();
Type ntGen = nt.MakeGenericType(ntArgs);
objValue = Activator.CreateInstance(ntGen);
//set the instance value back to the container
setter(objValue);
}
Option value = (Option) objValue;
if (string.IsNullOrEmpty(value.Name)) value.Name = pi.Name;
value.Name = GetFullKeyName(value.Name);
value._parent = this;
value.NonNullableType = Nullable.GetUnderlyingType(value.ValueType);
value.IsNullable = value.NonNullableType != null;
if (value.NonNullableType == null) value.NonNullableType = value.ValueType;
_nameToOption[value.Name] = value;
_nameToOptionValue[value.Name] = new OptionValue();
}
}
private string GetFullKeyName(string name)
{
if (string.IsNullOrEmpty(_namespace)) return name;
return _namespace + "." + name;
}
private bool CanParse(Type t)
{
return _config.HasParser(t) || DefaultParser.IsSupported(t);
}
private string ReadFirstValue(string key)
{
foreach (IConfigStore store in _config.Stores)
{
if (store.CanRead)
{
string value = store.Read(key);
if (value != null) return value;
}
}
return null;
}
private void CheckCanParse(Type t)
{
if (!CanParse(t))
{
throw new ArgumentException("value parser for " + t.FullName +
" is not registered and not supported by default parser");
}
}
private bool AreEqual(object value1, object value2)
{
if (value1 == null && value2 == null) return true;
if (value1 != null && value2 != null)
{
Type t1 = value1.GetType();
Type t2 = value2.GetType();
if (t1.IsArray && t2.IsArray)
{
return AreEqual((Array) value1, (Array) value2);
}
}
return value1 != null && value1.Equals(value2);
}
private bool AreEqual(Array a, Array b)
{
if (a == null && b == null) return true;
if (a == null || b == null) return false;
if (a.Length != b.Length) return false;
for (int i = 0; i < a.Length; i++)
{
object obj1 = a.GetValue(i);
object obj2 = b.GetValue(i);
if (!AreEqual(obj1, obj2)) return false;
}
return true;
}
private string GetRawStringValue<T>(Option<T> option, T value)
{
string stringValue = null;
ITypeParser typeParser = _config.GetParser(option.NonNullableType);
if (typeParser != null)
{
stringValue = typeParser.ToRawString(value);
}
else
{
if (DefaultParser.IsSupported(typeof(T)))
{
stringValue = DefaultParser.ToRawString(value);
}
}
return stringValue;
}
}
}*/

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Specialized;
using System.Configuration;
namespace Config.Net.Stores
{
/// <summary>
/// Standard app.config (web.config) configuration store. Read-only.
/// </summary>
class AppConfigStore : IConfigStore
{
public string Name => "App.config";
public bool CanRead => true;
public bool CanWrite => false;
public string? Read(string key)
{
if(key == null) return null;
//first, look at appsettings and connection strings
string? value = ConfigurationManager.AppSettings[key] ?? ConfigurationManager.ConnectionStrings[key]?.ConnectionString;
if(value == null)
{
int idx = key.IndexOf('.');
if(idx != -1)
{
string sectionName = key.Substring(0, idx);
if(ConfigurationManager.GetSection(sectionName) is NameValueCollection nvsc)
{
string keyName = key.Substring(idx + 1);
value = nvsc[keyName];
}
}
}
return value;
}
public void Write(string key, string? value) => throw new NotSupportedException();
public void Dispose()
{
}
}
}

View File

@@ -0,0 +1,61 @@
using System;
using System.Configuration;
using System.IO;
using System.Reflection;
namespace Config.Net.Stores
{
/// <summary>
/// Reads configuration from the .dll.config or .exe.config file.
/// </summary>
class AssemblyConfigStore : IConfigStore
{
private readonly Configuration _configuration;
/// <summary>
/// Creates a new instance of assembly configuration store (.dll.config files)
/// </summary>
/// <param name="assembly">reference to the assembly to look for</param>
public AssemblyConfigStore(Assembly assembly)
{
_configuration = ConfigurationManager.OpenExeConfiguration(assembly.Location);
}
/// <summary>
/// Store name
/// </summary>
public string Name => Path.GetFileName(_configuration.FilePath);
/// <summary>
/// Store is readable
/// </summary>
public bool CanRead => true;
/// <summary>
/// Store is not writeable
/// </summary>
public bool CanWrite => false;
/// <summary>
/// Reads the value by key
/// </summary>
public string? Read(string key)
{
KeyValueConfigurationElement element = _configuration.AppSettings.Settings[key];
return element?.Value;
}
/// <summary>
/// Writing is not supported
/// </summary>
public void Write(string key, string? value) => throw new NotSupportedException();
/// <summary>
/// Nothing to dispose
/// </summary>
public void Dispose()
{
}
}
}

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using Config.Net.Core;
namespace Config.Net.Stores
{
class DictionaryConfigStore : IConfigStore
{
private readonly IDictionary<string, string> _container;
public DictionaryConfigStore(IDictionary<string, string>? container = null)
{
_container = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
if(container != null)
{
foreach(KeyValuePair<string, string> item in container)
{
_container[item.Key] = item.Value;
}
}
}
public bool CanRead => true;
public bool CanWrite => true;
public void Dispose()
{
}
public string? Read(string key)
{
if (key == null) return null;
if (FlatArrays.IsArrayLength(key, k => _container.GetValueOrDefaultInternal(k), out int length))
{
return length.ToString();
}
if (FlatArrays.IsArrayElement(key, k => _container.GetValueOrDefaultInternal(k), out string? element))
{
return element;
}
return _container.GetValueOrDefaultInternal(key);
}
public void Write(string key, string? value)
{
if (key == null) return;
if (value == null)
{
_container.Remove(key);
}
else
{
_container[key] = value;
}
}
}
}

View File

@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using Config.Net.Core;
namespace Config.Net.Stores
{
/// <summary>
/// Uses system environment variables
/// </summary>
class EnvironmentVariablesStore : IConfigStore
{
/// <summary>
/// Readable
/// </summary>
public bool CanRead => true;
/// <summary>
/// Writeable
/// </summary>
public bool CanWrite => true;
/// <summary>
/// Store name
/// </summary>
public string Name => "System Environment";
/// <summary>
/// Reads value by key
/// </summary>
public string? Read(string key)
{
if (key == null) return null;
foreach(string variant in GetAllKeyVariants(key))
{
if (FlatArrays.IsArrayLength(variant, k => Environment.GetEnvironmentVariable(k), out int length))
{
return length.ToString();
}
if (FlatArrays.IsArrayElement(variant, k => Environment.GetEnvironmentVariable(k), out string? element))
{
return element;
}
string? value = Environment.GetEnvironmentVariable(variant);
if (value != null) return value;
}
return null;
}
/// <summary>
/// Writes value by key
/// </summary>
public void Write(string key, string? value)
{
Environment.SetEnvironmentVariable(key, value);
}
private IEnumerable<string> GetAllKeyVariants(string key)
{
var result = new List<string>();
result.Add(key);
result.Add(key.ToUpper().Replace(".", "_"));
return result;
}
/// <summary>
/// Nothing to dispose
/// </summary>
public void Dispose()
{
}
}
}

View File

@@ -0,0 +1,21 @@
namespace Config.Net.Stores.Formats.Ini
{
class IniComment : IniEntity
{
public const string CommentSeparator = ";";
public IniComment(string value)
{
Value = value;
}
public string Value { get; set; }
public string EscapedValue
{
get { return Value.Replace("\r", @"\r").Replace("\n", @"\n"); }
}
public override string ToString() => Value;
}
}

View File

@@ -0,0 +1,6 @@
namespace Config.Net.Stores.Formats.Ini
{
abstract class IniEntity
{
}
}

View File

@@ -0,0 +1,72 @@
using System;
namespace Config.Net.Stores.Formats.Ini
{
internal class IniKeyValue : IniEntity
{
public const string KeyValueSeparator = "=";
public IniKeyValue(string key, string value, string? comment)
{
if(key == null) throw new ArgumentNullException(nameof(key));
Key = key;
Value = value;
Comment = comment == null ? null : new IniComment(comment);
}
public string Key { get; }
public string Value { get; set; }
public string EscapedKey
{
get { return Key.Replace("\r", @"\r").Replace("\n", @"\n"); }
}
public string EscapedValue
{
get { return Value.Replace("\r", @"\r").Replace("\n", @"\n"); }
}
public IniComment? Comment { get; }
public static IniKeyValue? FromLine(string line, bool parseInlineComments, bool unescapeNewLines = false)
{
int idx = line.IndexOf(KeyValueSeparator, StringComparison.CurrentCulture);
if(idx == -1) return null;
string key = line.Substring(0, idx).Trim();
string value = line.Substring(idx + 1).Trim();
string? comment = null;
if (parseInlineComments)
{
idx = value.LastIndexOf(IniComment.CommentSeparator, StringComparison.CurrentCulture);
if (idx != -1)
{
comment = value.Substring(idx + 1).Trim();
value = value.Substring(0, idx).Trim();
}
}
if(unescapeNewLines)
{
key = UnescapeString(key);
value = UnescapeString(value);
comment = (comment != null) ? UnescapeString(comment) : null;
}
return new IniKeyValue(key, value, comment);
}
private static string UnescapeString(string key)
{
return key.Replace(@"\r", "\r").Replace(@"\n", "\n");
}
public override string ToString()
{
return $"{Value}";
}
}
}

View File

@@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace Config.Net.Stores.Formats.Ini
{
class IniSection
{
public const string SectionKeySeparator = ".";
private readonly List<IniEntity> _entities = new List<IniEntity>();
private readonly Dictionary<string, IniKeyValue> _keyToValue = new Dictionary<string, IniKeyValue>();
/// <summary>
/// Section name
/// </summary>
public string? Name { get; set; }
/// <summary>
///
/// </summary>
/// <param name="name">Pass null to work with global section</param>
public IniSection(string? name)
{
if(name != null)
{
if (name.StartsWith("[")) name = name.Substring(1);
if (name.EndsWith("]")) name = name.Substring(0, name.Length - 1);
}
Name = name;
}
public void Add(IniEntity entity)
{
_entities.Add(entity);
IniKeyValue? ikv = entity as IniKeyValue;
if(ikv != null)
{
_keyToValue[ikv.Key] = ikv;
}
}
public IniKeyValue? Set(string key, string? value)
{
if(value == null)
{
IniKeyValue? ikv;
if(_keyToValue.TryGetValue(key, out ikv))
{
_keyToValue.Remove(key);
return ikv;
}
return null;
}
else
{
IniKeyValue? ikv;
if(_keyToValue.TryGetValue(key, out ikv))
{
ikv.Value = value;
}
else
{
ikv = new IniKeyValue(key, value, null);
Add(ikv);
}
return ikv;
}
}
public static void SplitKey(string fullKey, out string? sectionName, out string keyName)
{
int idx = fullKey.IndexOf(SectionKeySeparator, StringComparison.CurrentCulture);
if(idx == -1)
{
sectionName = null;
keyName = fullKey;
}
else
{
sectionName = fullKey.Substring(0, idx);
keyName = fullKey.Substring(idx + 1);
}
}
public void WriteTo(StreamWriter writer)
{
foreach(IniEntity entity in _entities)
{
IniKeyValue? ikv = entity as IniKeyValue;
if(ikv != null)
{
writer.Write($"{ikv.EscapedKey}{IniKeyValue.KeyValueSeparator}{ikv.EscapedValue}");
if(ikv.Comment != null)
{
writer.Write(" ");
writer.Write(IniComment.CommentSeparator);
writer.Write(ikv.Comment.EscapedValue);
}
writer.WriteLine();
continue;
}
IniComment? comment = entity as IniComment;
if(comment != null)
{
writer.Write(IniComment.CommentSeparator);
writer.WriteLine(comment.Value);
}
}
}
public override string ToString()
{
return Name ?? string.Empty;
}
}
}

View File

@@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Config.Net.Stores.Formats.Ini
{
class StructuredIniFile
{
private const string _sectionBegin = "[";
private const string _sectionEnd = "]";
private static readonly char[] _sectionTrims = {'[', ']'};
private readonly IniSection _globalSection;
private readonly List<IniSection> _sections = new List<IniSection>();
private readonly Dictionary<string, IniKeyValue> _fullKeyNameToValue = new Dictionary<string, IniKeyValue>(StringComparer.InvariantCultureIgnoreCase);
public StructuredIniFile()
{
_globalSection = new IniSection(null);
_sections.Add(_globalSection);
}
public string? this[string key]
{
get
{
if(key == null) return null;
IniKeyValue? value;
return !_fullKeyNameToValue.TryGetValue(key, out value) ? null : value.Value;
}
set
{
if(key == null) return;
IniSection.SplitKey(key, out string? sectionName, out string keyName);
IniSection? section = sectionName == null
? _globalSection
: _sections.FirstOrDefault(s => s.Name == sectionName);
if(section == null)
{
section = new IniSection(sectionName);
_sections.Add(section);
}
IniKeyValue? ikv = section.Set(keyName, value);
//update the local cache
if(ikv != null)
{
if(value == null)
{
_fullKeyNameToValue.Remove(key);
}
else
{
_fullKeyNameToValue[key] = ikv;
}
}
}
}
public static StructuredIniFile ReadFrom(Stream inputStream, bool parseInlineComments, bool unescapeNewLines = false)
{
if(inputStream == null) throw new ArgumentNullException(nameof(inputStream));
var file = new StructuredIniFile();
using(var reader = new StreamReader(inputStream))
{
IniSection section = file._globalSection;
string? line;
while((line = reader.ReadLine()) != null)
{
line = line.Trim();
if(line.StartsWith(_sectionBegin))
{
//start new section
line = line.Trim();
section = new IniSection(line);
file._sections.Add(section);
}
else if(line.StartsWith(IniComment.CommentSeparator))
{
//whole line is a comment
string comment = line.Substring(1).Trim();
section.Add(new IniComment(comment));
}
else
{
IniKeyValue? ikv = IniKeyValue.FromLine(line, parseInlineComments, unescapeNewLines);
if(ikv == null) continue;
section.Add(ikv);
string fullKey = section.Name == null
? ikv.Key
: $"{section.Name}{IniSection.SectionKeySeparator}{ikv.Key}";
file._fullKeyNameToValue[fullKey] = ikv;
}
}
}
return file;
}
public void WriteTo(Stream outputStream)
{
if(outputStream == null) throw new ArgumentNullException(nameof(outputStream));
using(var writer = new StreamWriter(outputStream))
{
foreach(IniSection section in _sections)
{
if(section.Name != null)
{
writer.WriteLine();
writer.WriteLine($"{_sectionBegin}{section.Name}{_sectionEnd}");
}
section.WriteTo(writer);
}
}
}
//private static
}
}

View File

@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using Config.Net.Core;
using Config.Net.TypeParsers;
namespace Config.Net.Stores.Impl.CommandLine
{
class CommandLineConfigStore : IConfigStore
{
private readonly Dictionary<string, string> _nameToValue;
private static readonly char[] ArgPrefixes = new[] { '-', '/' };
private static readonly string[] ArgDelimiters = new[] { "=", ":" };
private readonly bool _isCaseSensitive;
public bool CanRead => true;
public bool CanWrite => false;
public CommandLineConfigStore(string[]? args = null, bool isCaseSensitive = false, IEnumerable<KeyValuePair<string, int>>? nameToPosition = null)
{
_isCaseSensitive = isCaseSensitive;
_nameToValue = new Dictionary<string, string>(_isCaseSensitive ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase);
Parse(args ?? Environment.GetCommandLineArgs(), nameToPosition);
}
public void Dispose()
{
}
public string? Read(string key)
{
if (key == null) return null;
if(FlatArrays.IsArrayLength(key, k => _nameToValue.GetValueOrDefaultInternal(k), out int length))
{
return length.ToString();
}
if(FlatArrays.IsArrayElement(key, k => _nameToValue.GetValueOrDefaultInternal(k), out string? element))
{
return element;
}
string? value;
_nameToValue.TryGetValue(key, out value);
return value;
}
private string[]? GetAsArray(string key)
{
if (!_nameToValue.TryGetValue(key, out string? allString)) return null;
if (!StringArrayParser.TryParse(allString, out string[]? ar)) return null;
return ar;
}
public void Write(string key, string? value)
{
throw new NotSupportedException("command line cannot be written to");
}
private void Parse(string[] args, IEnumerable<KeyValuePair<string, int>>? nameToPosition)
{
_nameToValue.Clear();
var posToName = new Dictionary<int, string>();
if (nameToPosition != null)
{
foreach(KeyValuePair<string, int> p in nameToPosition)
{
if (p.Key != null)
{
posToName[p.Value] = p.Key;
}
}
}
if (args == null) return;
for (int i = 0; i < args.Length; i++)
{
string? name;
string? value;
Tuple<string, string?>? nameValue = Utils.SplitByDelimiter(args[i], ArgDelimiters);
name = nameValue?.Item1.TrimStart(ArgPrefixes);
value = nameValue?.Item2;
if (name != null && value != null)
{
_nameToValue[name] = value;
}
else if(name != null && posToName.TryGetValue(i, out string? ptnName))
{
_nameToValue[ptnName] = args[i];
}
}
}
}
}

View File

@@ -0,0 +1,120 @@
using System;
using System.IO;
using System.Text;
using Config.Net.Core;
using Config.Net.Stores.Formats.Ini;
namespace Config.Net.Stores
{
/// <summary>
/// Simple INI storage.
/// </summary>
class IniFileConfigStore : IConfigStore
{
private readonly string? _fullName;
private readonly StructuredIniFile _iniFile;
/// <summary>
///
/// </summary>r
/// <param name="name">File does not have to exist, however it will be created as soon as you
/// try to write to it</param>
public IniFileConfigStore(string name, bool isFilePath, bool parseInlineComments, bool unescapeNewLines = false)
{
if (name == null) throw new ArgumentNullException(nameof(name));
if (isFilePath)
{
_fullName = Path.GetFullPath(name); // Allow relative path to INI file
string? parentDirPath = Path.GetDirectoryName(_fullName);
if (string.IsNullOrEmpty(parentDirPath)) throw new IOException("the provided directory path is not valid");
if (!Directory.Exists(parentDirPath))
{
Directory.CreateDirectory(parentDirPath);
}
_iniFile = ReadIniFile(_fullName, parseInlineComments, unescapeNewLines);
CanWrite = true;
}
else
{
_iniFile = ReadIniContent(name, parseInlineComments, unescapeNewLines);
CanWrite = false;
}
CanRead = true;
}
public string Name => ".ini";
public bool CanRead { get; }
public bool CanWrite { get; }
public string? Read(string key)
{
if (FlatArrays.IsArrayLength(key, k => _iniFile[k], out int length))
{
return length.ToString();
}
if (FlatArrays.IsArrayElement(key, k => _iniFile[k], out string? element))
{
return element;
}
return _iniFile[key];
}
public void Write(string key, string? value)
{
if (!CanWrite) return;
_iniFile[key] = value;
WriteIniFile();
}
private static StructuredIniFile ReadIniFile(string fullName, bool parseInlineComments, bool unescapeNewLines = false)
{
FileInfo iniFile = new FileInfo(fullName);
if(iniFile.Exists)
{
using(FileStream stream = iniFile.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return StructuredIniFile.ReadFrom(stream, parseInlineComments, unescapeNewLines);
}
}
else
{
return new StructuredIniFile();
}
}
private static StructuredIniFile ReadIniContent(string content, bool parseInlineComments, bool unescapeNewLines = false)
{
using (Stream input = new MemoryStream(Encoding.UTF8.GetBytes(content)))
{
return StructuredIniFile.ReadFrom(input, parseInlineComments, unescapeNewLines);
}
}
private void WriteIniFile()
{
if (_fullName == null) return;
using(FileStream stream = File.Create(_fullName))
{
_iniFile.WriteTo(stream);
}
}
public void Dispose()
{
//nothing to dispose
}
}
}

View File

@@ -0,0 +1,165 @@
using System;
using System.IO;
using System.Runtime.InteropServices.ComTypes;
using System.Text.Json;
using System.Text.Json.Nodes;
using Config.Net.Core;
namespace Config.Net.Stores
{
/// <summary>
/// Simple JSON storage using System.Text.Json
/// </summary>
public class JsonConfigStore : IConfigStore
{
private readonly string? _pathName;
private JsonNode? _j;
/// <summary>
/// Create JSON storage in the file specified in <paramref name="name"/>.
/// </summary>
/// <param name="name">Name of the file, either path to JSON storage file, or json file content.</param>
/// <param name="isFilePath">Set to true if <paramref name="name"/> specifies file name, otherwise false. </param>
/// <exception cref="ArgumentNullException"><paramref name="name"/> is null.</exception>
/// <exception cref="IOException">Provided path is not valid.</exception>
/// <remarks>Storage file does not have to exist, however it will be created as soon as first write performed.</remarks>
public JsonConfigStore(string name, bool isFilePath)
{
if (name == null) throw new ArgumentNullException(nameof(name));
if (isFilePath)
{
_pathName = Path.GetFullPath(name); // Allow relative path to JSON file
_j = ReadJsonFile(_pathName);
}
else
{
_j = ReadJsonString(name);
}
}
public void Dispose()
{
// nothing to dispose.
}
public static string Name => "json";
public bool CanRead => true;
public bool CanWrite => _pathName != null;
public string? Read(string rawKey)
{
if (string.IsNullOrEmpty(rawKey) || _j == null) return null;
bool isLength = OptionPath.TryStripLength(rawKey, out string? key);
if (key == null) return null;
string[] parts = key.Split('.');
if (parts.Length == 0) return null;
JsonNode? node = _j;
foreach (string rawPart in parts)
{
bool isIndex = OptionPath.TryStripIndex(rawPart, out string? part, out int partIndex);
if (part == null) return null;
node = node![part];
if (node == null) return null;
if (isIndex)
{
if (node is not JsonArray ja) return null;
if (partIndex < ja.Count)
{
node = ja[partIndex];
}
else
return null;
}
}
if (isLength)
return node is JsonArray ja ? ja.Count.ToString() : null;
return node!.ToString();
}
public void Write(string key, string? value)
{
if (string.IsNullOrEmpty(_pathName))
throw new InvalidOperationException("please specify file name for writeable config");
if (_j == null) _j = new JsonObject();
// navigate to target element, create if needed
string[] parts = key.Split('.');
if (parts.Length == 0) return;
JsonNode? node = _j;
string? lastPart = null;
foreach (string rawPart in parts)
{
bool isIndex = OptionPath.TryStripIndex(rawPart, out string? part, out int partIndex);
if (part == null) return;
lastPart = part;
JsonNode? nextNode = node[part];
if (isIndex)
{
throw new NotImplementedException();
}
else
{
if (nextNode == null)
{
//create missing node
nextNode = new JsonObject();
node[part] = nextNode;
}
}
node = nextNode;
}
JsonObject? parent = node.Parent as JsonObject;
parent!.Remove(lastPart!);
parent![lastPart!] = JsonValue.Create(value);
string js = _j.ToJsonString(new JsonSerializerOptions { WriteIndented = true });
FileInfo file = new(_pathName);
if (file is not null)
{
if (file.Directory is not null)
{
file.Directory.Create();
}
}
File.WriteAllText(_pathName, js);
}
private static JsonNode? ReadJsonFile(string fileName)
{
if (File.Exists(fileName))
{
string json = File.ReadAllText(fileName);
return ReadJsonString(json);
}
return null;
}
private static JsonNode? ReadJsonString(string jsonString)
{
return JsonNode.Parse(jsonString);
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Config.Net.TypeParsers
{
class ByteParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(byte) };
public bool TryParse(string? value, Type t, out object? result)
{
if(value == null)
{
result = false;
return false;
}
byte ir;
bool parsed;
if (value.StartsWith("0x"))
{
parsed = byte.TryParse(value.Substring(2), NumberStyles.HexNumber, TypeParserSettings.DefaultCulture, out ir);
}
else
{
parsed = byte.TryParse(value, NumberStyles.Integer, TypeParserSettings.DefaultCulture, out ir);
}
result = ir;
return parsed;
}
public string? ToRawString(object? value)
{
return ((byte?)value)?.ToString(TypeParserSettings.DefaultNumericFormat, TypeParserSettings.DefaultCulture);
}
}
}

View File

@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Globalization;
namespace Config.Net.TypeParsers
{
/// <summary>
/// Container for core types. Eventually all simple parsers will merge into this class.
/// </summary>
class CoreParsers : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(Uri), typeof(bool), typeof(Guid), typeof(DateTime) };
private static readonly Dictionary<string, bool> BooleanTrueValues =
new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase)
{
{"true", true},
{"yes", true},
{"1", true},
};
public string? ToRawString(object? value)
{
if (value == null) return null;
Type t = value.GetType();
if(t == typeof(Uri))
return value.ToString();
if(t == typeof(bool))
return value?.ToString()?.ToLowerInvariant();
if (t == typeof(Guid))
return value.ToString();
if(t == typeof(DateTime))
return ((DateTime)value).ToUniversalTime().ToString("u");
return null;
}
public bool TryParse(string? value, Type t, out object? result)
{
if(value == null)
{
result = null;
return false;
}
if(t == typeof(Uri))
{
Uri uri = new Uri(value);
result = uri;
return true;
}
if(t == typeof(bool))
{
if(BooleanTrueValues.ContainsKey(value))
{
result = true;
return true;
}
result = false;
return true;
}
if(t == typeof(Guid))
{
if(Guid.TryParse(value, out Guid tg))
{
result = tg;
return true;
}
result = null;
return false;
}
if(t == typeof(DateTime))
{
DateTime dateResult;
bool parsed = DateTime.TryParse(value, TypeParserSettings.DefaultCulture, DateTimeStyles.None, out dateResult);
result = dateResult;
return parsed;
}
result = null;
return false;
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Config.Net.TypeParsers
{
class DecimalParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(decimal) };
public bool TryParse(string? value, Type t, out object? result)
{
decimal dr;
bool parsed = decimal.TryParse(value, NumberStyles.Float, TypeParserSettings.DefaultCulture, out dr);
result = dr;
return parsed;
}
public string? ToRawString(object? value)
{
return ((decimal?)value)?.ToString(TypeParserSettings.DefaultNumericFormat, TypeParserSettings.DefaultCulture);
}
}
}

View File

@@ -0,0 +1,69 @@
using System;
using System.Reflection;
namespace Config.Net.TypeParsers
{
class DefaultParser
{
public bool TryParse(string? value, Type t, out object? result)
{
if(IsEnum(t))
{
if(value == null)
{
result = null;
return false;
}
try
{
result = Enum.Parse(t, value, true);
return true;
}
catch(ArgumentException)
{
}
catch(OverflowException)
{
}
result = null;
return false;
}
throw new NotSupportedException();
}
public bool IsSupported(Type t)
{
return IsEnum(t);
}
public string? ToRawString(object? value)
{
if(value == null) return null;
Type t = value.GetType();
if(IsEnum(t))
{
return value.ToString();
}
throw new NotSupportedException();
}
static bool IsEnum(Type t)
{
if(t == null) return false;
//try to get the underlying type if this is a nullable type
Type? nullable = Nullable.GetUnderlyingType(t);
if(nullable != null) t = nullable;
return t.GetTypeInfo().IsEnum;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Globalization;
namespace Config.Net.TypeParsers
{
class DoubleParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(double) };
public bool TryParse(string? value, Type t, out object? result)
{
double dr;
bool parsed = double.TryParse(value, NumberStyles.Float, TypeParserSettings.DefaultCulture, out dr);
result = dr;
return parsed;
}
public string? ToRawString(object? value)
{
return ((double?)value)?.ToString(TypeParserSettings.DefaultNumericFormat, TypeParserSettings.DefaultCulture);
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Config.Net.TypeParsers
{
class FloatParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(float) };
public bool TryParse(string? value, Type t, out object? result)
{
float dr;
bool parsed = float.TryParse(value, NumberStyles.Float, TypeParserSettings.DefaultCulture, out dr);
result = dr;
return parsed;
}
public string? ToRawString(object? value)
{
return ((float?)value)?.ToString(TypeParserSettings.DefaultNumericFormat, TypeParserSettings.DefaultCulture);
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Globalization;
namespace Config.Net.TypeParsers
{
class IntParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(int) };
public bool TryParse(string? value, Type t, out object? result)
{
int ir;
bool parsed = int.TryParse(value, NumberStyles.Integer, TypeParserSettings.DefaultCulture, out ir);
result = ir;
return parsed;
}
public string? ToRawString(object? value)
{
return ((int?)value)?.ToString(TypeParserSettings.DefaultNumericFormat, TypeParserSettings.DefaultCulture);
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Globalization;
namespace Config.Net.TypeParsers
{
class LongParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(long) };
public bool TryParse(string? value, Type t, out object? result)
{
long lr;
bool parsed = long.TryParse(value, NumberStyles.Integer, TypeParserSettings.DefaultCulture, out lr);
result = lr;
return parsed;
}
public string? ToRawString(object? value)
{
return ((long?)value)?.ToString(TypeParserSettings.DefaultNumericFormat, TypeParserSettings.DefaultCulture);
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Net;
namespace Config.Net.TypeParsers
{
class NetworkCredentialParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(NetworkCredential) };
public string? ToRawString(object? value)
{
NetworkCredential? nc = value as NetworkCredential;
return Utils.ToFriendlyString(nc);
}
public bool TryParse(string? value, Type t, out object? result)
{
NetworkCredential? nc = value.ToNetworkCredential();
result = nc;
return true;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Config.Net.TypeParsers
{
class SByteParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(sbyte) };
public bool TryParse(string? value, Type t, out object? result)
{
sbyte ir;
bool parsed = sbyte.TryParse(value, NumberStyles.Integer, TypeParserSettings.DefaultCulture, out ir);
result = ir;
return parsed;
}
public string? ToRawString(object? value)
{
return ((sbyte?)value)?.ToString(TypeParserSettings.DefaultNumericFormat, TypeParserSettings.DefaultCulture);
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Config.Net.TypeParsers
{
class ShortParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(short) };
public bool TryParse(string? value, Type t, out object? result)
{
short ir;
bool parsed = short.TryParse(value, NumberStyles.Integer, TypeParserSettings.DefaultCulture, out ir);
result = ir;
return parsed;
}
public string? ToRawString(object? value)
{
return ((short?)value)?.ToString(TypeParserSettings.DefaultNumericFormat, TypeParserSettings.DefaultCulture);
}
}
}

View File

@@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Config.Net.TypeParsers
{
class StringArrayParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(string[]) };
public bool TryParse(string? value, Type t, out object? result)
{
if (value == null)
{
result = null;
return false;
}
result = ParseAsArray(value);
return true;
}
public static bool TryParse(string? value, out string[]? result)
{
if(value == null)
{
result = null;
return false;
}
result = ParseAsArray(value);
return true;
}
public string? ToRawString(object? value)
{
string[]? arv = (string[]?)value;
if (arv == null || arv.Length == 0) return null;
return string.Join(" ", arv.Select(Escape));
}
private static string Escape(string s)
{
string s1 = s.Replace("\"", "\"\"");
return (s == s1 && !s.Contains(" "))
? s
: $"\"{s1}\"";
}
private static string[] ParseAsArray(string s)
{
var a = new List<string>();
string v = string.Empty;
int state = 0;
for(int i = 0; i < s.Length;)
{
char ch = s[i];
switch(state)
{
case 0: //default
if (ch == '\"')
{
state = 2;
}
else if(ch == ' ')
{
//skip spaces in default mode
}
else
{
v += ch;
state = 1;
}
i++;
break;
case 1: //reading unquoted value
if (ch == ' ')
{
a.Add(v);
v = string.Empty;
state = 0;
}
else
{
v += ch;
}
i++;
break;
case 2: //reading quoted value
if(ch == '\"')
{
state = 3;
}
else
{
v += ch;
}
i++;
break;
case 3: //after quote in quoted mode
if (ch == '\"')
{
v += ch;
state = 2;
}
else
{
a.Add(v);
v = string.Empty;
state = 0;
}
i++;
break;
}
}
if(!string.IsNullOrEmpty(v))
{
a.Add(v);
}
return a.ToArray();
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
namespace Config.Net.TypeParsers
{
class StringParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(string) };
public bool TryParse(string? value, Type t, out object? result)
{
result = value;
return value != null;
}
public string? ToRawString(object? value)
{
return value as string;
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
namespace Config.Net.TypeParsers
{
class TimeSpanParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(TimeSpan) };
public bool TryParse(string? value, Type t, out object? result)
{
TimeSpan ts;
bool parsed = TimeSpan.TryParse(value, TypeParserSettings.DefaultCulture, out ts);
result = ts;
return parsed;
}
public string? ToRawString(object? value)
{
return ((TimeSpan?)value)?.ToString(null, TypeParserSettings.DefaultCulture);
}
}
}

View File

@@ -0,0 +1,11 @@
using System.Globalization;
namespace Config.Net.TypeParsers
{
internal static class TypeParserSettings
{
public const string DefaultNumericFormat = "G";
public static readonly CultureInfo DefaultCulture = CultureInfo.InvariantCulture;
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Config.Net.TypeParsers
{
class UIntParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(uint) };
public bool TryParse(string? value, Type t, out object? result)
{
uint ir;
bool parsed = uint.TryParse(value, NumberStyles.Integer, TypeParserSettings.DefaultCulture, out ir);
result = ir;
return parsed;
}
public string? ToRawString(object? value)
{
return ((uint?)value)?.ToString(TypeParserSettings.DefaultNumericFormat, TypeParserSettings.DefaultCulture);
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Config.Net.TypeParsers
{
class ULongParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(ulong) };
public bool TryParse(string? value, Type t, out object? result)
{
ulong ir;
bool parsed = ulong.TryParse(value, NumberStyles.Integer, TypeParserSettings.DefaultCulture, out ir);
result = ir;
return parsed;
}
public string? ToRawString(object? value)
{
return ((ulong?)value)?.ToString(TypeParserSettings.DefaultNumericFormat, TypeParserSettings.DefaultCulture);
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Config.Net.TypeParsers
{
class UShortParser : ITypeParser
{
public IEnumerable<Type> SupportedTypes => new[] { typeof(ushort) };
public bool TryParse(string? value, Type t, out object? result)
{
ushort ir;
bool parsed = ushort.TryParse(value, NumberStyles.Integer, TypeParserSettings.DefaultCulture, out ir);
result = ir;
return parsed;
}
public string? ToRawString(object? value)
{
return ((ushort?)value)?.ToString(TypeParserSettings.DefaultNumericFormat, TypeParserSettings.DefaultCulture);
}
}
}

87
Config.Net/Utils.cs Normal file
View File

@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
namespace Config.Net
{
static class Utils
{
public static NetworkCredential? ToNetworkCredential(this string? s)
{
if (s == null) return null;
Tuple<string, string?>? credsAndDomain = SplitByDelimiter(s, "@");
string? creds = credsAndDomain?.Item1;
string? domain = credsAndDomain?.Item2;
Tuple<string, string?>? usernameAndPassword = SplitByDelimiter(creds, ":");
string? username = usernameAndPassword?.Item1;
string? password = usernameAndPassword?.Item2;
return new NetworkCredential(username, password, domain);
}
public static string? ToFriendlyString(NetworkCredential? credential)
{
if (credential == null) return null;
string usernameAndPassword;
if (string.IsNullOrEmpty(credential.UserName) && string.IsNullOrEmpty(credential.Password))
{
usernameAndPassword = string.Empty;
}
else if (string.IsNullOrEmpty(credential.UserName))
{
usernameAndPassword = $":{credential.Password}";
}
else if (string.IsNullOrEmpty(credential.Password))
{
usernameAndPassword = credential.UserName;
}
else
{
usernameAndPassword = $"{credential.UserName}:{credential.Password}";
}
return string.IsNullOrEmpty(credential.Domain)
? usernameAndPassword
: $"{usernameAndPassword}@{credential.Domain}";
}
public static Tuple<string, string?>? SplitByDelimiter(string? s, params string[] delimiter)
{
if (s == null) return null;
string key;
string? value;
if (delimiter == null || delimiter.Length == 0)
{
key = s.Trim();
value = null;
}
else
{
List<int> indexes = delimiter.Where(d => d != null).Select(d => s.IndexOf(d)).Where(d => d != -1).ToList();
if (indexes.Count == 0)
{
key = s.Trim();
value = null;
}
else
{
int idx = indexes.OrderBy(i => i).First();
key = s.Substring(0, idx);
value = s.Substring(idx + 1);
}
}
return new Tuple<string, string?>(key, value);
}
}
}

View File

@@ -3,15 +3,21 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSI.BT.Tools", "FSI.BT.Tools\FSI.BT.Tools.csproj", "{21041032-87C5-4842-B540-9EB3ACD8A16D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSI.BT.Tools", "FSI.BT.Tools\FSI.BT.Tools.csproj", "{49AC17F0-02B1-4972-A07E-C413233803BF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSI.Lib", "FSI.Lib\FSI.Lib\FSI.Lib.csproj", "{3232DF9C-FAAC-4429-8E7D-E3E9F266118F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoCompleteTextBox", "AutoCompleteTextBox\AutoCompleteTextBox.csproj", "{A9F40DCC-0B40-4F5D-A639-0DFB89EB4657}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotifyIconWpf", "NotifyIconWpf\NotifyIconWpf\NotifyIconWpf.csproj", "{C60282E9-2046-4D76-86F8-0B5CBFDE6D26}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Config.Net", "Config.Net\Config.Net.csproj", "{88E60518-EABA-433D-85C1-B257BCF6408A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHotkey.Wpf", "NHotkey\NHotkey.Wpf\NHotkey.Wpf.csproj", "{B2E18BB7-BB05-4E5E-B6E0-C05EF98F5287}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSI.Lib", "FSI.Lib\FSI.Lib\FSI.Lib.csproj", "{D6E8C3B6-822A-4491-8D52-79E451A105F6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RadialMenu", "RadialMenu\RadialMenu.csproj", "{9DF116EE-45B1-4297-BE75-0F6B78B33689}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RoboSharp", "RoboSharp\RoboSharp.csproj", "{CDC46BAE-640C-4758-91F6-AB79B6A118C1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RadialMenu", "RadialMenu\RadialMenu.csproj", "{42B3BF54-1903-4213-A536-44F60D46B1F0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpClipboard", "SharpClipboard\SharpClipboard\SharpClipboard.csproj", "{AB011A1E-03C0-4A12-86C2-4CEC2099FEEF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tulpep.NotificationWindow", "Notification-Popup-Window\Tulpep.NotificationWindow\Tulpep.NotificationWindow.csproj", "{605006EB-D4E6-4312-A293-3A43FAC43240}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -19,31 +25,43 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{21041032-87C5-4842-B540-9EB3ACD8A16D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{21041032-87C5-4842-B540-9EB3ACD8A16D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{21041032-87C5-4842-B540-9EB3ACD8A16D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{21041032-87C5-4842-B540-9EB3ACD8A16D}.Release|Any CPU.Build.0 = Release|Any CPU
{3232DF9C-FAAC-4429-8E7D-E3E9F266118F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3232DF9C-FAAC-4429-8E7D-E3E9F266118F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3232DF9C-FAAC-4429-8E7D-E3E9F266118F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3232DF9C-FAAC-4429-8E7D-E3E9F266118F}.Release|Any CPU.Build.0 = Release|Any CPU
{C60282E9-2046-4D76-86F8-0B5CBFDE6D26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C60282E9-2046-4D76-86F8-0B5CBFDE6D26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C60282E9-2046-4D76-86F8-0B5CBFDE6D26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C60282E9-2046-4D76-86F8-0B5CBFDE6D26}.Release|Any CPU.Build.0 = Release|Any CPU
{B2E18BB7-BB05-4E5E-B6E0-C05EF98F5287}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2E18BB7-BB05-4E5E-B6E0-C05EF98F5287}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2E18BB7-BB05-4E5E-B6E0-C05EF98F5287}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2E18BB7-BB05-4E5E-B6E0-C05EF98F5287}.Release|Any CPU.Build.0 = Release|Any CPU
{9DF116EE-45B1-4297-BE75-0F6B78B33689}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9DF116EE-45B1-4297-BE75-0F6B78B33689}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9DF116EE-45B1-4297-BE75-0F6B78B33689}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9DF116EE-45B1-4297-BE75-0F6B78B33689}.Release|Any CPU.Build.0 = Release|Any CPU
{49AC17F0-02B1-4972-A07E-C413233803BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{49AC17F0-02B1-4972-A07E-C413233803BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{49AC17F0-02B1-4972-A07E-C413233803BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{49AC17F0-02B1-4972-A07E-C413233803BF}.Release|Any CPU.Build.0 = Release|Any CPU
{A9F40DCC-0B40-4F5D-A639-0DFB89EB4657}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A9F40DCC-0B40-4F5D-A639-0DFB89EB4657}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A9F40DCC-0B40-4F5D-A639-0DFB89EB4657}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A9F40DCC-0B40-4F5D-A639-0DFB89EB4657}.Release|Any CPU.Build.0 = Release|Any CPU
{88E60518-EABA-433D-85C1-B257BCF6408A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{88E60518-EABA-433D-85C1-B257BCF6408A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{88E60518-EABA-433D-85C1-B257BCF6408A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{88E60518-EABA-433D-85C1-B257BCF6408A}.Release|Any CPU.Build.0 = Release|Any CPU
{D6E8C3B6-822A-4491-8D52-79E451A105F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D6E8C3B6-822A-4491-8D52-79E451A105F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D6E8C3B6-822A-4491-8D52-79E451A105F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D6E8C3B6-822A-4491-8D52-79E451A105F6}.Release|Any CPU.Build.0 = Release|Any CPU
{CDC46BAE-640C-4758-91F6-AB79B6A118C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CDC46BAE-640C-4758-91F6-AB79B6A118C1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CDC46BAE-640C-4758-91F6-AB79B6A118C1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CDC46BAE-640C-4758-91F6-AB79B6A118C1}.Release|Any CPU.Build.0 = Release|Any CPU
{42B3BF54-1903-4213-A536-44F60D46B1F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{42B3BF54-1903-4213-A536-44F60D46B1F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42B3BF54-1903-4213-A536-44F60D46B1F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42B3BF54-1903-4213-A536-44F60D46B1F0}.Release|Any CPU.Build.0 = Release|Any CPU
{AB011A1E-03C0-4A12-86C2-4CEC2099FEEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AB011A1E-03C0-4A12-86C2-4CEC2099FEEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB011A1E-03C0-4A12-86C2-4CEC2099FEEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AB011A1E-03C0-4A12-86C2-4CEC2099FEEF}.Release|Any CPU.Build.0 = Release|Any CPU
{605006EB-D4E6-4312-A293-3A43FAC43240}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{605006EB-D4E6-4312-A293-3A43FAC43240}.Debug|Any CPU.Build.0 = Debug|Any CPU
{605006EB-D4E6-4312-A293-3A43FAC43240}.Release|Any CPU.ActiveCfg = Release|Any CPU
{605006EB-D4E6-4312-A293-3A43FAC43240}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E7CCC9AB-E9BE-4414-B73F-8387EDFEEB2D}
SolutionGuid = {42ABEA59-E385-4B30-B81F-8F18064A368D}
EndGlobalSection
EndGlobal

View File

@@ -1,64 +0,0 @@
using System;
using System.Collections.Generic;
using FSI.Lib.Helpers;
namespace FSI.BT.Tools
{
internal class Admin
{
public static bool CheckSuperAdminRight()
{
if (Global.Settings.SuperAdmin == null)
{
return false;
}
System.Security.Principal.WindowsIdentity windowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent();
if (string.Equals(Global.Settings.SuperAdmin, windowsIdentity.ShortName(), StringComparison.OrdinalIgnoreCase))
return true;
return false;
}
public static bool CheckAdminRight()
{
if (Global.Settings.Admins == null)
{
return false;
}
List<string> admins = new List<string>(Global.Settings.Admins);
System.Security.Principal.WindowsIdentity windowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent();
foreach (string admin in admins)
{
if (string.Equals(admin, windowsIdentity.ShortName(), StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
public static bool CheckUserRight()
{
if (Global.Settings.Users == null)
{
return false;
}
List<string> users = new List<string>(Global.Settings.Users);
System.Security.Principal.WindowsIdentity windowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent();
foreach (string user in users)
{
if (string.Equals(user, windowsIdentity.ShortName(), StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
}
}

View File

@@ -1,18 +0,0 @@
<Application x:Class="FSI.BT.Tools.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar"
Startup="Application_Startup"
Exit="Application_Exit">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="NotifyIconResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@@ -1,60 +0,0 @@
using Hardcodet.Wpf.TaskbarNotification;
using NHotkey;
using NHotkey.Wpf;
using System.Windows;
using System.Windows.Input;
namespace FSI.BT.Tools
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : System.Windows.Application
{
private static readonly KeyGesture RadialMenu = new(Key.OemBackslash, ModifierKeys.Control);
private static readonly KeyGesture TimeStamp = new(Key.C, ModifierKeys.Control | ModifierKeys.Alt);
public void Application_Startup(object sender, StartupEventArgs e)
{
Global.Settings = new AppSettings(GetType().Namespace.ToString() + ".xml");
Global.Settings.Load();
Global.TaskbarIcon = (TaskbarIcon)FindResource("FSINotifyIcon");
Global.AdminRights = Admin.CheckAdminRight();
Global.SuperAdminRights = Admin.CheckSuperAdminRight();
Global.UserRights = Admin.CheckUserRight();
HotkeyManager.Current.AddOrReplace("RadialMenu", RadialMenu, ShowRadialMenu);
HotkeyManager.Current.AddOrReplace("TimeStampToClipboard", TimeStamp, TimeStampToClipboard);
Global.FrmRadialMenu = new();
}
private void ShowRadialMenu(object sender, HotkeyEventArgs e)
{
var cmd = new Commands.RadialMenuCommand();
if (cmd.CanExecute(null))
cmd.Execute(null);
e.Handled = true;
}
private void TimeStampToClipboard(object sender, HotkeyEventArgs e)
{
var cmd = new Commands.TimeStampToClipboardCommand();
cmd.Execute(null);
e.Handled = true;
}
private void Application_Exit(object sender, ExitEventArgs e)
{
Global.Settings.Save();
}
}
}

View File

@@ -1,59 +0,0 @@
using FSI.Lib.WinSettings;
namespace FSI.BT.Tools
{
public class AppSettings : XmlSettings
{
public AppSettings(string fileName) : base(fileName)
{
TimeStampFormat = "_yyyyMMdd_HHmmss";
EplArguments = "/Variant:\"Electric P8\"";
SuperAdmin = "maier_s";
}
[EncryptedSetting]
public string[]? Users { get; set; }
[EncryptedSetting]
public string[]? Admins{ get; set; }
public string? SuperAdmin{ get; set; }
public string? TimeStampFormat { get; set; }
public string[]? SieSimaticManagerExe { get; set; }
public string[]? SieTiaV13Exe { get; set; }
public string[]? SieTiaV14Exe { get; set; }
public string[]? SieTiaV15Exe { get; set; }
public string[]? SieTiaV16Exe { get; set; }
public string[]? SieTiaV17Exe { get; set; }
public string[]? SieTiaVStarterExe { get; set; }
public string[]? EplExe { get; set; }
public string? EplArguments { get; set; }
public string[]? NppExe { get; set; }
public string[]? TotalCmdExe { get; set; }
public string[]? TeXstudioExe { get; set; }
public string[]? TeXstudioPath { get; set; }
public string[]? VsExe { get; set; }
public string[]? VsCodeExe { get; set; }
public string[]? RdpExe { get; set; }
public string[]? OutlookExe { get; set; }
public string[]? TeamsExe { get; set; }
public string? TeamsArg { get; set; }
public string[]? ExcelExe { get; set; }
public string[]? WordExe { get; set; }
public string[]? PaintNetExe { get; set; }
public string[]? GimpExe { get; set; }
public string[]? VncExe { get; set; }
public string[]? VncAdrBookExe { get; set; }
public string? ZentralWebUrl { get; set; }
public string? SchichtbuchUrl { get; set; }
public string? SPSUrl { get; set; }
public string? Pl1PlsUrl { get; set; }
public string? Pl2PlsUrl { get; set; }
public string? Pl2Als { get; set; }
public string? Pl3PlsUrl { get; set; }
public string? GiteaUrl { get; set; }
public string? WikiUrl { get; set; }
public string? ErpUrl { get; set; }
public string? EplPdfPath { get; set; }
public string? EplPrjPath { get; set; }
}
}

View File

@@ -0,0 +1,44 @@
namespace FSI.BT.Tools.ClipboardMgt
{
using System;
using FSI.BT.Tools.Global.Utilities;
using FSI.BT.Tools.RadialMenu.Business;
using Microsoft.Win32;
using WK.Libraries.SharpClipboardNS;
/// <summary>
/// App contains the notifyicon, the taskbarform and the menus.
/// </summary>
internal class App : IDisposable
{
SharpClipboard _clipBoard;
public App()
{
AppRestart.BeforeRestarting += Dispose;
SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
_clipBoard = new SharpClipboard();
_clipBoard.ObservableFormats.Texts = true;
_clipBoard.ClipboardChanged += Clipboard_ClipboardChanged;
}
private void Clipboard_ClipboardChanged(object sender, SharpClipboard.ClipboardChangedEventArgs e)
{
var test = e.Content.ToString();
if (e.Content.ToString().StartsWith("\"") && e.Content.ToString().EndsWith("\""))
System.Windows.Forms.Clipboard.SetDataObject(e.Content.ToString().Substring(1, e.Content.ToString().Length - 2));
}
public void Dispose()
{
}
private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
{
}
}
}

View File

@@ -1,401 +0,0 @@
using FSI.Lib;
using System;
using System.Diagnostics;
using System.IO;
using System.Windows;
namespace FSI.BT.Tools.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class OpenAppCommand : CommandBase<OpenAppCommand>
{
public override void Execute(object parameter)
{
string[] files = new string[] { };
string[] pathes = new string[] { };
string arguments = string.Empty;
switch ((string)parameter)
{
case "SimaticManager":
files = Global.Settings.SieSimaticManagerExe;
break;
case "TIAv13":
files = Global.Settings.SieTiaV13Exe;
break;
case "TIAv14":
files = Global.Settings.SieTiaV14Exe;
break;
case "TIAv15":
files = Global.Settings.SieTiaV13Exe;
break;
case "TIAv16":
files = Global.Settings.SieTiaV16Exe;
break;
case "TIAv17":
files = Global.Settings.SieTiaV17Exe;
break;
case "Starter":
files = Global.Settings.SieTiaVStarterExe;
break;
case "Epl":
files = Global.Settings.EplExe;
arguments = Global.Settings.EplArguments;
break;
case "EplPrj":
Lib.Guis.Prj.Mgt.FrmMain frmMainEplPrj = new()
{
ShowPdf = false,
CloseAtLostFocus = true,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Path = Global.Settings.EplPrjPath,
EplExes = Global.Settings.EplExe,
};
frmMainEplPrj.Show();
return;
case "EplPdf":
Lib.Guis.Prj.Mgt.FrmMain frmMainEplPdf = new()
{
ShowPdf = true,
CloseAtLostFocus = true,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Path = Global.Settings.EplPdfPath,
};
frmMainEplPdf.Show();
return;
case "EplPdfMgt":
Lib.Guis.Pdf.Mgt.FrmMain frmMainEplPdfMgt = new()
{
CloseAtLostFocus = true
};
frmMainEplPdfMgt.Show();
return;
case "Npp":
files = Global.Settings.NppExe;
break;
case "TotalCmd":
files = Global.Settings.TotalCmdExe;
break;
case "TeXstudio":
files = Global.Settings.TeXstudioExe;
pathes = Global.Settings.TeXstudioPath;
break;
case "VS":
files = Global.Settings.VsExe;
break;
case "VS.Code":
files = Global.Settings.VsCodeExe;
break;
case "Rdp":
files = Global.Settings.RdpExe;
break;
case "DeEncrypt":
Lib.Guis.DeEncryptMessage.FrmMain frmMainDeEnCrypt = new()
{
Password = GetType().Namespace.ToString(),
CloseAtLostFocus = true,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
};
frmMainDeEnCrypt.Show();
return;
case "StarterCsvExporter":
Lib.Guis.SieStarterCsvExporter.FrmMain frmMain = new();
frmMain.Show();
return;
case "Admin":
Gui.FrmAdmin frmAdmin = new()
{
Admins = Global.Settings.Admins,
Users = Global.Settings.Users,
};
frmAdmin.ShowDialog();
if (frmAdmin.DialogResult.HasValue && frmAdmin.DialogResult.Value)
{
Global.Settings.Admins = frmAdmin.Admins;
Global.Settings.Users = frmAdmin.Users;
}
return;
case "Outlook":
files = Global.Settings.OutlookExe;
break;
case "Teams":
files = Global.Settings.TeamsExe;
arguments = Global.Settings.TeamsArg;
break;
case "Excel":
files = Global.Settings.ExcelExe;
break;
case "Word":
files = Global.Settings.WordExe;
break;
case "PaintNet":
files = Global.Settings.PaintNetExe;
break;
case "Gimp":
files = Global.Settings.GimpExe;
break;
case "Vnc":
files = Global.Settings.VncExe;
break;
case "VncAdrBook":
files = Global.Settings.VncAdrBookExe;
break;
}
string fileName = string.Empty;
string path = string.Empty;
for (int i = 0; i <= files.Length - 1; i++)
{
if (File.Exists(Environment.ExpandEnvironmentVariables(files[i].Trim())))
{
fileName = Environment.ExpandEnvironmentVariables(files[i].Trim());
}
if (pathes.Length == 0)
{
path = Path.GetDirectoryName(fileName);
}
else
{
path = Environment.ExpandEnvironmentVariables(pathes[i].Trim());
}
}
if (ProgramIsRunning(fileName))
{
ProgramToFront(fileName);
}
else
{
Process process = new();
process.StartInfo.FileName = fileName;
process.StartInfo.WorkingDirectory = path;
process.StartInfo.Arguments = arguments;
try
{
process.Start();
}
catch (System.ComponentModel.Win32Exception ex) when (ex.NativeErrorCode == 740)
{
try
{
process.StartInfo.UseShellExecute = true;
process.StartInfo.Verb = "runas";
process.Start();
}
catch { }
}
}
}
public override bool CanExecute(object parameter)
{
string[] files = new string[] { };
switch ((string)parameter)
{
case "SimaticManager":
files = Global.Settings.SieSimaticManagerExe;
break;
case "TIAv13":
files = Global.Settings.SieTiaV13Exe;
break;
case "TIAv14":
files = Global.Settings.SieTiaV14Exe;
break;
case "TIAv15":
files = Global.Settings.SieTiaV13Exe;
break;
case "TIAv16":
files = Global.Settings.SieTiaV16Exe;
break;
case "TIAv17":
files = Global.Settings.SieTiaV17Exe;
break;
case "Starter":
files = Global.Settings.SieTiaVStarterExe;
break;
case "Epl":
files = Global.Settings.EplExe;
break;
case "EplPrj":
return true;
case "EplPdf":
return true;
case "EplPdfMgt":
return Global.AdminRights;
case "Npp":
files = Global.Settings.NppExe;
break;
case "TotalCmd":
files = Global.Settings.TotalCmdExe;
break;
case "TeXstudio":
files = Global.Settings.TeXstudioExe;
break;
case "VS":
files = Global.Settings.VsExe;
break;
case "VS.Code":
files = Global.Settings.VsCodeExe;
break;
case "Rdp":
files = Global.Settings.RdpExe;
break;
case "DeEncrypt":
return Global.AdminRights;
case "StarterCsvExporter":
return Global.AdminRights;
case "Admin":
return Global.SuperAdminRights;
case "Outlook":
files = Global.Settings.OutlookExe;
break;
case "Teams":
files = Global.Settings.TeamsExe;
break;
case "Excel":
files = Global.Settings.ExcelExe;
break;
case "Word":
files = Global.Settings.WordExe;
break;
case "PaintNet":
files = Global.Settings.PaintNetExe;
break;
case "Gimp":
files = Global.Settings.GimpExe;
break;
case "Vnc":
files = Global.Settings.VncExe;
break;
case "VncAdrBook":
files = Global.Settings.VncAdrBookExe;
break;
default: return false;
}
foreach (string file in files)
{
if (File.Exists(Environment.ExpandEnvironmentVariables(file.Trim())))
{
return true;
}
}
return false;
}
private bool ProgramIsRunning(string FullPath)
{
string FilePath = Path.GetDirectoryName(FullPath);
string FileName = Path.GetFileNameWithoutExtension(FullPath).ToLower();
bool isRunning = false;
Process[] pList = Process.GetProcessesByName(FileName);
foreach (Process p in pList)
{
if (p.MainModule.FileName.StartsWith(FilePath, StringComparison.InvariantCultureIgnoreCase))
{
isRunning = true;
break;
}
}
return isRunning;
}
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr handle);
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool ShowWindow(IntPtr handle, int nCmdShow);
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool IsIconic(IntPtr handle);
private void ProgramToFront(string FullPath)
{
string FilePath = Path.GetDirectoryName(FullPath);
string FileName = Path.GetFileNameWithoutExtension(FullPath).ToLower();
Process[] pList = Process.GetProcessesByName(FileName);
foreach (Process p in pList)
{
if (p.MainModule.FileName.StartsWith(FilePath, StringComparison.InvariantCultureIgnoreCase))
{
IntPtr handle = p.MainWindowHandle;
if (IsIconic(handle))
{
ShowWindow(handle, 9);
}
SetForegroundWindow(handle);
break;
}
}
}
}
}

View File

@@ -1,82 +0,0 @@
using FSI.Lib;
using System;
using System.Diagnostics;
namespace FSI.BT.Tools.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class OpenLinkCommand : CommandBase<OpenLinkCommand>
{
public override void Execute(object parameter)
{
string url = String.Empty;
switch ((string)parameter)
{
case "ZentralWeb":
url = Global.Settings.ZentralWebUrl;
break;
case "Schichtbuch":
url = Global.Settings.SchichtbuchUrl;
break;
case "SPS":
url = Global.Settings.SPSUrl;
break;
case "PL1.Pls":
url = Global.Settings.Pl1PlsUrl;
break;
case "PL2.Pls":
url = Global.Settings.Pl2PlsUrl;
break;
case "PL2.Als":
url = Global.Settings.Pl2Als;
break;
case "PL3.Pls":
url = Global.Settings.Pl3PlsUrl;
break;
case "FSI.Gitea":
url = Global.Settings.GiteaUrl;
break;
case "FSI.Wiki":
url = Global.Settings.WikiUrl;
break;
case "Erp":
url = Global.Settings.ErpUrl;
break;
}
if (url == String.Empty)
return;
url = url.Replace("&", "^&");
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
}
public override bool CanExecute(object parameter)
{
string url = String.Empty;
switch ((string)parameter)
{
case "FSI.Gitea":
return Global.AdminRights;
case "FSI.Wiki":
return Global.AdminRights;
default:
return true;
}
}
}
}

View File

@@ -1,37 +0,0 @@
using FSI.Lib.Wpf.ExtensionMethods;
using System.Windows;
namespace FSI.BT.Tools.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class RadialMenuCommand : CommandBase<RadialMenuCommand>
{
public override void Execute(object parameter)
{
if (Global.FrmRadialMenu.Visibility == Visibility.Collapsed)
{
Global.FrmRadialMenu.ShowCenteredToMouse();
Global.FrmRadialMenu.ActivateCenteredToMouse();
return;
}
if (Global.FrmRadialMenu.Visibility == Visibility.Hidden)
{
Global.FrmRadialMenu.Visibility = Visibility.Visible;
}
else
{
Global.FrmRadialMenu.Visibility = Visibility.Hidden;
}
Global.FrmRadialMenu.ActivateCenteredToMouse();
}
public override bool CanExecute(object parameter)
{
return Global.AdminRights || Global.UserRights;
}
}
}

View File

@@ -1,27 +0,0 @@
using System;
using System.Windows.Controls.Primitives;
namespace FSI.BT.Tools.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class TimeStampToClipboardCommand : CommandBase<TimeStampToClipboardCommand>
{
public override void Execute(object parameter)
{
System.Windows.Forms.Clipboard.SetDataObject(DateTime.Now.ToString(Global.Settings.TimeStampFormat));
var balloon = new ToolTip()
{
BalloonText = "Zeitstempel",
BalloonDesc = "Der aktuelle Zeitstempel wurde in die Zwischenablage kopiert."
};
Global.TaskbarIcon.ShowCustomBalloon(balloon, PopupAnimation.Slide, 2000);
}
public override bool CanExecute(object parameter)
{
return true;
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,106 +1,181 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net6.0-windows</TargetFrameworks>
<OutputType>WinExe</OutputType>
<Nullable>enable</Nullable>
<TargetFramework>net6.0-windows10.0.22000.0</TargetFramework>
<RuntimeIdentifiers>win-x64</RuntimeIdentifiers>
<UseWPF>true</UseWPF>
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
<ApplicationIcon>Icons\FondiumU.ico</ApplicationIcon>
<AssemblyVersion>1.1</AssemblyVersion>
<UseWindowsForms>true</UseWindowsForms>
<Platform Condition=" '$(Platform)' == '' ">x64</Platform>
<OutputType>WinExe</OutputType>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Platforms>x64;x86;AnyCPU</Platforms>
<Configurations>Debug;Release;ReleasePackage</Configurations>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Global\Icons\FondiumU.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Optimize>True</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<Optimize>True</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<Optimize>True</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Optimize>False</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<Optimize>False</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<Optimize>False</Optimize>
</PropertyGroup>
<PropertyGroup>
<StartupObject>FSI.BT.Tools.Program</StartupObject>
<DebugType>full</DebugType>
<SupportedOSPlatformVersion>10.0.17763.0</SupportedOSPlatformVersion>
<NoWin32Manifest>true</NoWin32Manifest>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleasePackage|x64'">
<Optimize>True</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleasePackage|x86'">
<Optimize>True</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleasePackage|AnyCPU'">
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Resource Remove="Icons\Admin.jpg" />
<Resource Remove="Icons\Apps.png" />
<Resource Remove="Icons\Circuit.png" />
<Resource Remove="Icons\Close.png" />
<Resource Remove="Icons\Crypt.jpg" />
<Resource Remove="Icons\EplP8.png" />
<Resource Remove="Icons\Erp.png" />
<Resource Remove="Icons\Excel.png" />
<Resource Remove="Icons\FondiumU.ico" />
<Resource Remove="Icons\FU.png" />
<Resource Remove="Icons\Gimp.png" />
<Resource Remove="Icons\Gitea.png" />
<Resource Remove="Icons\Info.png" />
<Resource Remove="Icons\Links.png" />
<Resource Remove="Icons\NPP.png" />
<Resource Remove="Icons\Outlook.png" />
<Resource Remove="Icons\Paint.png" />
<Resource Remove="Icons\Pdf.png" />
<Resource Remove="Icons\Plc.jpg" />
<Resource Remove="Icons\Rdp.png" />
<Resource Remove="Icons\SIE.png" />
<Resource Remove="Icons\STEP7.png" />
<Resource Remove="Icons\Teams.png" />
<Resource Remove="Icons\TIAv13.jpg" />
<Resource Remove="Icons\TIAv14.jpg" />
<Resource Remove="Icons\TIAv15.jpg" />
<Resource Remove="Icons\TIAv16.jpg" />
<Resource Remove="Icons\TIAv17.jpg" />
<Resource Remove="Icons\Tools.png" />
<Resource Remove="Icons\TotalCmd.jfif" />
<Resource Remove="Icons\Vnc.png" />
<Resource Remove="Icons\VncAdrBook.png" />
<Resource Remove="Icons\Vs.png" />
<Resource Remove="Icons\VsCode.png" />
<Resource Remove="Icons\TeXstudio.png" />
<Resource Remove="Icons\Word.png" />
<None Remove="Global.json" />
<None Remove="RadialMenu.json" />
<None Remove="SystemTrayMenu.json" />
<None Remove="TimeStamp.json" />
</ItemGroup>
<ItemGroup>
<COMReference Include="IWshRuntimeLibrary">
<Guid>{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
<COMReference Include="Shell32">
<Guid>{50A7E9B0-70EF-11D1-B75A-00A0C90564FE}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="ExtTools\AudioSwitch.zip" />
<EmbeddedResource Include="ExtTools\kalk.zip" />
<EmbeddedResource Include="ExtTools\SmartSystemMenu_v2.21.2.zip" />
<EmbeddedResource Include="Global.json" />
<EmbeddedResource Include="RadialMenu.json" />
<EmbeddedResource Include="SystemTrayMenu.json" />
<EmbeddedResource Include="TimeStamp.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FSI.Lib\FSI.Lib\FSI.Lib.csproj" />
<ProjectReference Include="..\NHotkey\NHotkey.Wpf\NHotkey.Wpf.csproj" />
<ProjectReference Include="..\NotifyIconWpf\NotifyIconWpf\NotifyIconWpf.csproj" />
<ProjectReference Include="..\RadialMenu\RadialMenu.csproj" />
<PackageReference Include="H.InputSimulator" Version="1.3.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="6.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NLog.Extensions.Logging" Version="5.2.1" />
<PackageReference Include="SharpDX.DirectInput" Version="4.2.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Svg" Version="3.4.3" />
</ItemGroup>
<ItemGroup>
<Resource Include="Icons\1087815.png" />
<Resource Include="Icons\Admin.jpg" />
<Resource Include="Icons\Apps.png" />
<Resource Include="Icons\Circuit.png" />
<Resource Include="Icons\Close.png" />
<Resource Include="Icons\Crypt.jpg" />
<Resource Include="Icons\EplP8.png" />
<Resource Include="Icons\Erp.png" />
<Resource Include="Icons\Excel.png" />
<Resource Include="Icons\FondiumU.ico" />
<Resource Include="Icons\FU.png" />
<Resource Include="Icons\Gimp.png" />
<Resource Include="Icons\Gitea.png" />
<Resource Include="Icons\Info.png" />
<Resource Include="Icons\Links.png" />
<Resource Include="Icons\NPP.png" />
<Resource Include="Icons\Outlook.png" />
<Resource Include="Icons\Paint.png" />
<Resource Include="Icons\Pdf.png" />
<Resource Include="Icons\Plc.jpg" />
<Resource Include="Icons\Rdp.png" />
<Resource Include="Icons\SIE.png" />
<Resource Include="Icons\STEP7.png" />
<Resource Include="Icons\Teams.png" />
<Resource Include="Icons\TIAv13.jpg" />
<Resource Include="Icons\TIAv14.jpg" />
<Resource Include="Icons\TIAv15.jpg" />
<Resource Include="Icons\TIAv16.jpg" />
<Resource Include="Icons\TIAv17.jpg" />
<Resource Include="Icons\Tools.png" />
<Resource Include="Icons\TotalCmd.jfif" />
<Resource Include="Icons\Vnc.png" />
<Resource Include="Icons\VncAdrBook.png" />
<Resource Include="Icons\Vs.png" />
<Resource Include="Icons\VsCode.png" />
<Resource Include="Icons\TeXstudio.png" />
<Resource Include="Icons\Word.png" />
<Reference Include="Clearcove.Logging, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>FSI.BT.Tools.Global\ThirdParty\Clearcove.Logging.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AutoCompleteTextBox\AutoCompleteTextBox.csproj" />
<ProjectReference Include="..\Config.Net\Config.Net.csproj" />
<ProjectReference Include="..\FSI.Lib\FSI.Lib\FSI.Lib.csproj" />
<ProjectReference Include="..\Notification-Popup-Window\Tulpep.NotificationWindow\Tulpep.NotificationWindow.csproj" />
<ProjectReference Include="..\RadialMenu\RadialMenu.csproj" />
<ProjectReference Include="..\RoboSharp\RoboSharp.csproj" />
<ProjectReference Include="..\SharpClipboard\SharpClipboard\SharpClipboard.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="FSI.BT.Tools.xml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Resource Include="Global\Icons\1087815.png" />
<Resource Include="Global\Icons\Admin.jpg" />
<Resource Include="Global\Icons\Apps.png" />
<Resource Include="Global\Icons\Circuit.png" />
<Resource Include="Global\Icons\Close.png" />
<Resource Include="Global\Icons\Crypt.jpg" />
<Resource Include="Global\Icons\EplP8.png" />
<Resource Include="Global\Icons\Erp.png" />
<Resource Include="Global\Icons\Excel.png" />
<Resource Include="Global\Icons\Folders.png" />
<Resource Include="Global\Icons\FondiumU.ico" />
<Resource Include="Global\Icons\FU.png" />
<Resource Include="Global\Icons\Gimp.png" />
<Resource Include="Global\Icons\Gitea.png" />
<Resource Include="Global\Icons\Iba.jpg" />
<Resource Include="Global\Icons\Info.png" />
<Resource Include="Global\Icons\Links.png" />
<Resource Include="Global\Icons\NPP.png" />
<Resource Include="Global\Icons\Outlook.png" />
<Resource Include="Global\Icons\Paint.png" />
<Resource Include="Global\Icons\Pdf.png" />
<Resource Include="Global\Icons\Plc.jpg" />
<Resource Include="Global\Icons\Rdp.png" />
<Resource Include="Global\Icons\SIE.png" />
<Resource Include="Global\Icons\STEP7.png" />
<Resource Include="Global\Icons\Teams.png" />
<Resource Include="Global\Icons\TeXstudio.png" />
<Resource Include="Global\Icons\TIAv13.jpg" />
<Resource Include="Global\Icons\TIAv14.jpg" />
<Resource Include="Global\Icons\TIAv15.jpg" />
<Resource Include="Global\Icons\TIAv16.jpg" />
<Resource Include="Global\Icons\TIAv17.jpg" />
<Resource Include="Global\Icons\Tools.png" />
<Resource Include="Global\Icons\TotalCmd.jfif" />
<Resource Include="Global\Icons\txt.png" />
<Resource Include="Global\Icons\Vnc.png" />
<Resource Include="Global\Icons\VncAdrBook.png" />
<Resource Include="Global\Icons\VolDown.png" />
<Resource Include="Global\Icons\VolOff.png" />
<Resource Include="Global\Icons\VolOn.png" />
<Resource Include="Global\Icons\VolUp.png" />
<Resource Include="Global\Icons\Vs.png" />
<Resource Include="Global\Icons\VsCode.png" />
<Resource Include="Global\Icons\Word.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="SystemTrayMenu\UserInterface\Menu.resx">
<Generator></Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Update="nlog.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Settings>
<Users>+I945AMzKKYBAAAAB21haWVyX3M=</Users>
<Admins>e+Dt7FRUDDoBAAAAB21haWVyX3M=</Admins>
<SuperAdmin>maier_s</SuperAdmin>
<TimeStampFormat>_yyyyMMdd_HHmmss</TimeStampFormat>
<SieSimaticManagerExe>C:\Program Files (x86)\Siemens\Step7\S7BIN\S7tgtopx.exe</SieSimaticManagerExe>
<SieTiaV13Exe>C:\Program Files (x86)\Siemens\Automation\Portal V13\Bin\Siemens.Automation.Portal.exe</SieTiaV13Exe>
<SieTiaV14Exe>C:\Program Files\Siemens\Automation\Portal V14\Bin\Siemens.Automation.Portal.exe</SieTiaV14Exe>
<SieTiaV15Exe>C:\Program Files\Siemens\Automation\Portal V15\Bin\Siemens.Automation.Portal.exe,c:\Program Files\Siemens\Automation\Portal V15_1\Bin\Siemens.Automation.Portal.exe</SieTiaV15Exe>
<SieTiaV16Exe>C:\Program Files\Siemens\Automation\Portal V16\Bin\Siemens.Automation.Portal.exe</SieTiaV16Exe>
<SieTiaV17Exe>C:\Program Files\Siemens\Automation\Portal V17\Bin\Siemens.Automation.Portal.exe</SieTiaV17Exe>
<SieTiaVStarterExe>C:\Program Files (x86)\Siemens\Step7\S7BIN\u7wdrfax.exe</SieTiaVStarterExe>
<EplExe>C:\Program Files\EPLAN\Platform\2.9.4\Bin\EPLAN.exe,C:\Program Files\EPLAN\Platform\2022.0.3\Bin\Eplan.exe</EplExe>
<EplArguments>/Variant:"Electric P8"</EplArguments>
<NppExe>C:\Windows\system32\notepad.exe,c:\Program Files\Notepad++\notepad++.exe</NppExe>
<TotalCmdExe>C:\Program Files\totalcmd\TOTALCMD.EXE,C:\Program Files\totalcmd\TOTALCMD64.EXE,C:\totalcmd\TOTALCMD64.EXE,C:\totalcmd\TOTALCMD.EXE</TotalCmdExe>
<TeXstudioExe>C:\Program Files\texstudio\texstudio.exe</TeXstudioExe>
<TeXstudioPath>C:\Program Files\texstudio\dictionaries</TeXstudioPath>
<VsExe>C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.exe</VsExe>
<VsCodeExe>%USERPROFILE%\AppData\Local\Programs\Microsoft VS Code\Code.exe</VsCodeExe>
<RdpExe>%windir%\system32\mstsc.exe</RdpExe>
<OutlookExe>C:\Program Files (x86)\Microsoft Office\root\Office16\OUTLOOK.EXE</OutlookExe>
<TeamsExe>C:\Users\maier_s\AppData\Local\Microsoft\Teams\Update.exe</TeamsExe>
<TeamsArg>--processStart ""Teams.exe""</TeamsArg>
<ExcelExe>C:\Program Files (x86)\Microsoft Office\root\Office16\EXCEL.EXE</ExcelExe>
<WordExe>C:\Program Files (x86)\Microsoft Office\root\Office16\WINWORD.EXE</WordExe>
<PaintNetExe>C:\Program Files\paint.net\paintdotnet.exe</PaintNetExe>
<GimpExe>C:\Program Files\GIMP 2\bin\gimp-2.10.exe</GimpExe>
<VncExe>C:\Program Files\RealVNC\VNC Viewer\vncviewer.exe,c:\Users\maier_s\OneDrive - Fondium Group GmbH\Documents\Apps\VNC-Viewer-6.20.113-Windows-64bit.exe</VncExe>
<VncAdrBookExe>C:\Program Files\RealVNC\VNC Viewer\vncaddrbook.exe</VncAdrBookExe>
<ZentralWebUrl>http://desiaugetwf/web/?AspxAutoDetectCookieSupport=1</ZentralWebUrl>
<SchichtbuchUrl>http://10.10.1.42/SKSchichtbuchWeb/de-DE/Plugin/ShiftBook/ShiftBook/IR</SchichtbuchUrl>
<SPSUrl>http://10.10.1.42/SKChangeTrackerWeb/de-DE/Plugin/ChangeTracker</SPSUrl>
<Pl1PlsUrl>http://10.10.200.2/SKPL1Web/index.aspx</Pl1PlsUrl>
<Pl2PlsUrl>http://10.10.213.4/SKPL2Web/index.aspx</Pl2PlsUrl>
<Pl2Als>http://10.10.213.234:84/emb_1/index.html</Pl2Als>
<Pl3PlsUrl>http://10.10.202.10/SKPL3Web/index.aspx</Pl3PlsUrl>
<GiteaUrl>http://desiaugetc7-088:3000/</GiteaUrl>
<WikiUrl>http://desiaugetc7-088:3001/en/home</WikiUrl>
<ErpUrl>https://mingle-portal.eu1.inforcloudsuite.com/FONDIUM_prd</ErpUrl>
<EplPdfPath>\\10.10.1.40\Betriebstechnik\Eplan</EplPdfPath>
<EplPrjPath>\\fondium.org\DESI$\AUG_Abteilung\Betriebstechnik\EPL\P8\Data\Projekte\FSI\</EplPrjPath>
</Settings>

View File

@@ -1,267 +0,0 @@
using System;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
namespace FSI.BT.Tools
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class FrmRadialMenu : Window, INotifyPropertyChanged
{
public FrmRadialMenu()
{
InitializeComponent();
DataContext = this;
_isOpenHome = true;
tbversion.Text = "v" + Assembly.GetExecutingAssembly().GetName().Version.Major + "." + Assembly.GetExecutingAssembly().GetName().Version.Minor;
}
#region Home
private bool _isOpenHome = true;
public bool IsOpenHome
{
get
{
return _isOpenHome;
}
set
{
_isOpenHome = value;
RaisePropertyChanged();
}
}
public ICommand CloseRadialMenuHome
{
get
{
return new RelayCommand(() => Visibility = Visibility.Hidden);
}
}
public ICommand OpenRadialMenuHome
{
get
{
return new RelayCommand(() =>
{
IsOpenHome = true;
IsOpenEpl =
IsOpenTools =
IsOpenSie =
IsOpenApps =
IsOpenLinks = false;
});
}
}
#endregion
#region Epl
private bool _isOpenEpl = false;
public bool IsOpenEpl
{
get
{
return _isOpenEpl;
}
set
{
_isOpenEpl = value;
RaisePropertyChanged();
}
}
public ICommand OpenRadialMenuEpl
{
get
{
return new RelayCommand(() =>
{
IsOpenEpl = true;
IsOpenHome = false;
});
}
}
#endregion
#region Tools
private bool _isOpenTools = false;
public bool IsOpenTools
{
get
{
return _isOpenTools;
}
set
{
_isOpenTools = value;
RaisePropertyChanged();
}
}
public ICommand OpenRadialMenuTools
{
get
{
return new RelayCommand(() =>
{
IsOpenTools = true;
IsOpenHome = false;
});
}
}
#endregion
#region Siemens
private bool _isOpenSie = false;
public bool IsOpenSie
{
get
{
return _isOpenSie;
}
set
{
_isOpenSie = value;
RaisePropertyChanged();
}
}
public ICommand OpenRadialMenuSie
{
get
{
return new RelayCommand(() =>
{
IsOpenSie = true;
IsOpenHome = false;
});
}
}
#endregion
#region Links
private bool _isOpenLinks = false;
public bool IsOpenLinks
{
get
{
return _isOpenLinks;
}
set
{
_isOpenLinks = value;
RaisePropertyChanged();
}
}
public ICommand OpenRadialMenuLinks
{
get
{
return new RelayCommand(() =>
{
IsOpenLinks = true;
IsOpenPlantLinks =
IsOpenHome = false;
});
}
}
#endregion
#region Anlagen Links
private bool _isOpenPlantLinks = false;
public bool IsOpenPlantLinks
{
get
{
return _isOpenPlantLinks;
}
set
{
_isOpenPlantLinks = value;
RaisePropertyChanged();
}
}
public ICommand OpenRadialMenuPlantLinks
{
get
{
return new RelayCommand(() =>
{
IsOpenPlantLinks = true;
IsOpenLinks = false;
});
}
}
#endregion
#region Apps
private bool _isOpenApps = false;
public bool IsOpenApps
{
get
{
return _isOpenApps;
}
set
{
_isOpenApps = value;
RaisePropertyChanged();
}
}
public ICommand OpenRadialMenuApps
{
get
{
return new RelayCommand(() =>
{
IsOpenApps = true;
IsOpenHome = false;
});
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void Window_Deactivated(object sender, EventArgs e)
{
Visibility = Visibility.Hidden;
IsOpenHome = true;
IsOpenEpl =
IsOpenTools =
IsOpenSie =
IsOpenLinks =
IsOpenApps =
IsOpenPlantLinks = false;
}
}
}

View File

@@ -1,21 +0,0 @@
using FSI.Lib.WinSettings;
using Hardcodet.Wpf.TaskbarNotification;
namespace FSI.BT.Tools
{
internal static class Global
{
public static FrmRadialMenu? FrmRadialMenu { get; set; }
public static TaskbarIcon? TaskbarIcon { get; set; }
public static AppSettings? Settings { get; set; }
public static bool UserRights { get; set; }
public static bool AdminRights { get; set; }
public static bool SuperAdminRights { get; set; }
}
}

536
FSI.BT.Tools/Global.json Normal file
View File

@@ -0,0 +1,536 @@
{
"SuperAdmin": "QlYbjwG0MLE49l71iEav9DnCfzBlWYFtURfS4px/PB1kcePPLtByt4U7hHOPCcaLf4XhzfAz/KJ2Ud7iexbD/w==",
"Admins": [
{
"Value": "0AZTYgTy5qkhLFmi9O9taw=="
}
],
"USers": [
{
"Value": "0AZTYgTy5qkhLFmi9O9taw=="
}
],
"TimeStampFormat": {
"Value": "_yyyyMMdd_HHmmss"
},
"Cmds": [
{
"Cmd": "StartUp",
"Urls": [
"https://www.rockantenne.de/webradio/80er-rock?utm_id=streams&utm_medium=webplayer&utm_campaign=streamlist&utm_term=mountpoint-80er-rock&utm_content=alias-80er-rock",
"http://desiaugetwf/web/?AspxAutoDetectCookieSupport=1",
"http://10.10.1.42/SKSchichtbuchWeb/de-DE/Plugin/ShiftBook/ShiftBook/IR",
"http://10.10.1.42/SKChangeTrackerWeb/de-DE/Plugin/ChangeTracker"
]
},
{
"Cmd": "S7",
"Exe": [
{
"ExePath": "C:\\Program Files (x86)\\Siemens\\STEP7\\S7BIN\\S7tgtopx.exe"
}
]
},
{
"Cmd": "TiaV13",
"Exe": [
{
"ExePath": "C:\\Program Files (x86)\\Siemens\\Automation\\Portal V13\\Bin\\Siemens.Automation.Portal.exe"
},
{
"ExePath": "C:\\Program Files (x86)\\Portal V13\\Bin\\Siemens.Automation.Portal.exe"
}
]
},
{
"Cmd": "TiaV14",
"Exe": [
{
"ExePath": "C:\\Program Files\\Siemens\\Automation\\Portal V14\\Bin\\Siemens.Automation.Portal.exe"
},
{
"ExePath": "C:\\Program Files\\Portal V14\\Bin\\Siemens.Automation.Portal.exe"
}
]
},
{
"Cmd": "TiaV15",
"Exe": [
{
"ExePath": "C:\\Program Files\\Siemens\\Automation\\Portal V15\\Bin\\Siemens.Automation.Portal.exe"
},
{
"ExePath": "c:\\Program Files\\Siemens\\Automation\\Portal V15_1\\Bin\\Siemens.Automation.Portal.exe"
},
{
"ExePath": "C:\\Program Files\\Portal V15_1\\Bin\\Siemens.Automation.Portal.exe"
}
]
},
{
"Cmd": "TiaV16",
"Exe": [
{
"ExePath": "C:\\Program Files\\Siemens\\Automation\\Portal V16\\Bin\\Siemens.Automation.Portal.exe"
},
{
"ExePath": "C:\\Program Files\\Portal V16\\Bin\\Siemens.Automation.Portal.exe"
}
]
},
{
"Cmd": "TiaV17",
"Exe": [
{
"ExePath": "C:\\Program Files\\Siemens\\Automation\\Portal V17\\Bin\\Siemens.Automation.Portal.exe"
}
]
},
{
"Cmd": "Starter",
"Exe": [
{
"ExePath": "C:\\Program Files (x86)\\Siemens\\Step7\\S7BIN\\u7wdrfax.exe"
}
]
},
{
"Cmd": "Epl",
"Exe": [
{
"ExePath": "C:\\Program Files\\EPLAN\\Platform\\2.9.4\\Bin\\EPLAN.exe",
"Arguments": "/Variant:\"Electric P8\""
},
{
"ExePath": "C:\\Program Files\\EPLAN\\Platform\\2022.0.3\\Bin\\Eplan.exe",
"Arguments": "/Variant:\"Electric P8\""
}
]
},
{
"Cmd": "NPP",
"Exe": [
{
"ExePath": "C:\\Windows\\system32\\notepad.exe"
},
{
"ExePath": "c:\\Program Files\\Notepad++\\notepad++.exe"
}
]
},
{
"Cmd": "Epl",
"Exe": [
{
"ExePath": "C:\\Program Files\\EPLAN\\Platform\\2.9.4\\Bin\\EPLAN.exe",
"Arguments": "/Variant:\"Electric P8\""
},
{
"ExePath": "C:\\Program Files\\EPLAN\\Platform\\2022.0.3\\Bin\\Eplan.exe",
"Arguments": "/Variant:\"Electric P8\""
}
]
},
{
"Cmd": "TotalCmd",
"Exe": [
{
"ExePath": "C:\\Program Files\\totalcmd\\TOTALCMD.EXE"
},
{
"ExePath": "C:\\Program Files\\totalcmd\\TOTALCMD64.EXE"
},
{
"ExePath": "C:\\totalcmd\\TOTALCMD64.EXE"
},
{
"ExePath": "C:\\totalcmd\\TOTALCMD.EXE"
}
]
},
{
"Cmd": "TeXstudio",
"Exe": [
{
"ExePath": "C:\\Program Files\\texstudio\\texstudio.exe"
}
]
},
{
"Cmd": "VS",
"Exe": [
{
"ExePath": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Common7\\IDE\\devenv.exe"
}
]
},
{
"Cmd": "VsCode",
"Exe": [
{
"ExePath": "%USERPROFILE%\\AppData\\Local\\Programs\\Microsoft VS Code\\Code.exe"
}
]
},
{
"Cmd": "Rdp",
"Exe": [
{
"ExePath": "%windir%\\system32\\mstsc.exe"
}
]
},
{
"Cmd": "Outlook",
"Exe": [
{
"ExePath": "C:\\Program Files (x86)\\Microsoft Office\\root\\Office16\\OUTLOOK.EXE"
}
]
},
{
"Cmd": "Teams",
"Exe": [
{
"ExePath": "C:\\Users\\maier_s\\AppData\\Local\\Microsoft\\Teams\\Update.exe",
"Arguments": "--processStart \"Teams.exe\""
}
]
},
{
"Cmd": "Excel",
"Exe": [
{
"ExePath": "C:\\Program Files (x86)\\Microsoft Office\\root\\Office16\\EXCEL.EXE"
}
]
},
{
"Cmd": "Word",
"Exe": [
{
"ExePath": "C:\\Program Files (x86)\\Microsoft Office\\root\\Office16\\WINWORD.EXE"
}
]
},
{
"Cmd": "PaintNet",
"Exe": [
{
"ExePath": "C:\\Program Files\\paint.net\\paintdotnet.exe"
}
]
},
{
"Cmd": "Gimp",
"Exe": [
{
"ExePath": "C:\\Program Files\\GIMP 2\\bin\\gimp-2.10.exe"
}
]
},
{
"Cmd": "Vnc",
"Exe": [
{
"ExePath": "C:\\Program Files\\RealVNC\\VNC Viewer\\vncviewer.exe"
},
{
"ExePath": "c:\\Users\\maier_s\\OneDrive - Fondium Group GmbH\\Documents\\Apps\\VNC-Viewer-6.20.113-Windows-64bit.exe"
}
]
},
{
"Cmd": "VncAdrBook",
"Exe": [
{
"ExePath": "C:\\Program Files\\RealVNC\\VNC Viewer\\vncaddrbook.exe"
}
]
},
{
"Cmd": "IbaAnalyzer",
"Exe": [
{
"ExePath": "C:\\Program Files\\iba\\ibaAnalyzer\\ibaAnalyzer.exe"
}
]
},
{
"Cmd": "ZtrlWeb",
"Urls": [
"http://desiaugetwf/web/?AspxAutoDetectCookieSupport=1"
]
},
{
"Cmd": "Schichtbuch",
"Urls": [
"http://10.10.1.42/SKSchichtbuchWeb/de-DE/Plugin/ShiftBook/ShiftBook/IR"
]
},
{
"Cmd": "SPS",
"Urls": [
"http://10.10.1.42/SKChangeTrackerWeb/de-DE/Plugin/ChangeTracker"
]
},
{
"Cmd": "Pl1.Pls",
"Urls": [
"http://10.10.200.2/SKPL1Web/index.aspx"
]
},
{
"Cmd": "Pl1.Lst",
"Urls": [
"http://desiaugetwf.fondium.org/web/Seiten/Leistungsdaten_FuG.aspx?Fkt=PL1"
]
},
{
"Cmd": "Pl2.Als",
"Urls": [
"http://10.10.213.234:84/emb_1/index.html"
]
},
{
"Cmd": "Pl2.Pls",
"Urls": [
"http://10.10.213.4/SKPL2Web/index.aspx"
]
},
{
"Cmd": "Pl2.Lst",
"Urls": [
"http://desiaugetwf/web/Seiten/Leistungsdaten_PL2.aspx"
]
},
{
"Cmd": "Pl2.Nc",
"Urls": [
"http://10.10.213.4/SKPL2Web/Seiten/Taktzeiten_PopUp.aspx"
]
},
{
"Cmd": "Pl2.Key",
"Urls": [
"http://10.10.213.4/skkeymanager-pl2"
]
},
{
"Cmd": "Pl2.Alg",
"Urls": [
"http://10.10.213.4/SKPL2Web/index.aspx",
"http://10.10.213.234:84/emb_1/index.html",
"http://desiaugetwf/web/Seiten/Leistungsdaten_PL2.aspx"
]
},
{
"Cmd": "Pl3.Pls",
"Urls": [
"http://10.10.202.10/SKPL3Web/index.asp"
]
},
{
"Cmd": "Pl3.Lst",
"Urls": [
"http://desiaugetwf.fondium.org/web/Seiten/Leistungsdaten_FuG.aspx?Fkt=PL3"
]
},
{
"Cmd": "Gitea",
"Urls": [
"http://desiaugetwf/web/?AspxAutoDetectCookieSupport=1"
]
},
{
"Cmd": "Wiki",
"Urls": [
"http://desiaugetc7-088:3001/en/home"
]
},
{
"Cmd": "Erp",
"Urls": [
"https://mingle-portal.eu1.inforcloudsuite.com/FONDIUM_prd"
]
},
{
"Cmd": "Epl.Pdf"
},
{
"Cmd": "Epl.Prj"
},
{
"Cmd": "Rdp.Mgt"
},
{
"Cmd": "Epl.PdfMgt"
},
{
"Cmd": "WebRadio"
},
{
"Cmd": "Calc",
"Exe": [
{
"ExePath": "ExtTools\\kalk\\net6.0\\kalk.exe"
}
]
},
{
"Cmd": "Iba.Pda",
"Exe": [
{
"ExePath": "C:\\Program Files (x86)\\iba\\ibaPDA\\Client\\ibaPda.exe"
}
]
},
{
"Cmd": "Trilium",
"Exe": [
{
"ExePath": "c:\\Users\\maier_s\\OneDrive - Fondium Group GmbH\\Documents\\Apps\\trilium-windows-x64\\trilium-portable.bat"
}
]
},
{
"Cmd": "SmartSystemMenu",
"Exe": [
{
"ExePath": "ExtTools\\SmartSystemMenu_v2.21.2\\SmartSystemMenu.exe"
}
]
}
],
"Folders": [
{
"Plant": "Alg",
"SubPlant": "Alg",
"Name": "Wrkdir",
"Description": "Arbeitsverzeichnis",
"Path": "d:\\WrkDir"
},
{
"Plant": "Alg",
"SubPlant": "Alg",
"Name": "EplPdf",
"Description": "Eplan PDF Ablage",
"Path": "\\\\10.10.1.40\\Betriebstechnik\\Eplan"
},
{
"Plant": "Alg",
"SubPlant": "Alg",
"Name": "EplPrj",
"Description": "Eplan Projekt Ablage",
"Path": "\\\\fondium.org\\DESI$\\AUG_Abteilung\\Betriebstechnik\\EPL\\P8\\Data\\Projekte\\FSI\\"
},
{
"Plant": "PL1",
"SubPlant": "Alg",
"Description": "PL1 Backupverzeichnis",
"Path": "\\\\10.10.1.40\\Betriebstechnik\\Datensicherung\\1_IuR_Giesserei\\PL1"
},
{
"Plant": "PL2",
"SubPlant": "Alg",
"Description": "Backupverzeichnis",
"Path": "\\\\10.10.1.40\\Betriebstechnik\\Datensicherung\\1_IuR_Giesserei\\PL2"
},
{
"Plant": "PL2",
"SubPlant": "SA",
"Description": "Backupverzeichnis",
"Path": "\\\\10.10.1.40\\Betriebstechnik\\Datensicherung\\1_IuR_Giesserei\\PL2\\SA"
},
{
"Plant": "PL2",
"SubPlant": "FA",
"Description": "Backupverzeichnis",
"Path": "\\\\10.10.1.40\\Betriebstechnik\\Datensicherung\\1_IuR_Giesserei\\PL2\\FA"
},
{
"Plant": "PL3",
"SubPlant": "Alg",
"Description": "Backupverzeichnis",
"Path": "\\\\10.10.1.40\\Betriebstechnik\\Datensicherung\\1_IuR_Giesserei\\PL3"
}
],
"TxtToClip": [
{
"Plant": "Alg",
"SubPlant": "Alg",
"Description": "Siehe Prg.-Änderungen",
"Txt": "Siehe Prg.-Änderungen"
},
{
"Plant": "Alg",
"SubPlant": "Alg",
"Description": "Eplan Projekt Ablage",
"Txt": "\\\\fondium.org\\DESI$\\AUG_Abteilung\\Betriebstechnik\\EPL\\P8\\Data\\Projekte\\FSI\\"
}
],
"Rdps": [
{
"Plant": "PL1",
"SubPlant": "Alg",
"Description": "Programmier PC",
"Host": "DESIAUGETC8-028"
},
{
"Plant": "PL2",
"SubPlant": "Alg",
"Description": "Programmier PC",
"Host": "DESIAUGETD5-029"
},
{
"Plant": "PL2",
"SubPlant": "FA",
"Description": "Programmier PC (HWS)",
"Host": "DESIAUGETD5-030"
},
{
"Plant": "PL2",
"SubPlant": "ENS",
"Description": "Programmier PC",
"Host": "DESIAUGETD5-020"
},
{
"Plant": "Alg",
"SubPlant": "Alg",
"Description": "IBA PC PL1",
"Host": "DESIAUGETC7-046"
},
{
"Plant": "Alg",
"SubPlant": "Alg",
"Description": "IBA PC PL2",
"Host": "DESIAUGETC7-047"
},
{
"Plant": "Alg",
"SubPlant": "Alg",
"Description": "Programmier Maier St.",
"Host": "10.10.199.92"
}
],
"WebRadioUrls": [
{
"Name": "Rock Antenne 80ger",
"Url": "http://stream.rockantenne.de/70er-rock/stream/mp3"
}
],
"WinCC": {
"AutoStart": false,
"UpdateIntervall": 10,
"WindowsName": "",
"WindowsClassName": "#32770",
"ButtonName": "Zur Kenntnis genommen"
},
"IbaDirSync": {
"AutoStart": false,
"Source": "d:\\tmp",
"Destination": "c:\\tmp"
}
}

View File

@@ -0,0 +1,364 @@
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows;
using static FSI.BT.Tools.Global.Settings.Cmd;
using static FSI.BT.Tools.Global.Settings.Exe;
namespace FSI.BT.Tools.Global.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class CmdCommand : CommandBase<CmdCommand>
{
public override void Execute(object parameter)
{
if (parameter is not string)
{
Global.Vars.Log.Error("Parameter ist kein String");
return;
}
var cmds = Vars.GlobalSettings.Cmds.ToList();
ICmd selectedCmd = null;
switch ((string)parameter)
{
case "DarkMode":
RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", true);
if (key.GetValue("AppsUseLightTheme") != null)
{
if (Convert.ToInt32(key.GetValue("AppsUseLightTheme")) == 0)
key.SetValue("AppsUseLightTheme", 1); //sets 'someData' in 'someValue'
else
key.SetValue("AppsUseLightTheme", 0); //sets 'someData' in 'someValue'
key.Close();
}
return;
case "Epl.Prj":
Lib.Guis.Prj.Mgt.FrmMain frmMainEplPrj = new()
{
ShowPdf = false,
CloseAtLostFocus = true,
WindowStartupLocation = WindowStartupLocation.CenterScreen,
Path = Helpers.GetFolderByName.Get(Vars.GlobalSettings.Folders, "EplPrj").path,
EplExe = GetExeByCmdName("Epl").ExePath,
};
frmMainEplPrj.Show();
return;
case "Epl.Pdf":
Lib.Guis.Prj.Mgt.FrmMain frmMainEplPdf = new()
{
ShowPdf = true,
CloseAtLostFocus = true,
WindowStartupLocation = WindowStartupLocation.CenterScreen,
Path = Helpers.GetFolderByName.Get(Vars.GlobalSettings.Folders, "EplPdf").path
};
frmMainEplPdf.Show();
return;
case "Epl.PdfMgt":
Lib.Guis.Pdf.Mgt.FrmMain frmMainEplPdfMgt = new()
{
CloseAtLostFocus = true
};
frmMainEplPdfMgt.Show();
return;
case "DeEncrypt":
Lib.Guis.DeEncryptMessage.FrmMain frmMainDeEnCrypt = new()
{
Password = AppDomain.CurrentDomain.FriendlyName,
CloseAtLostFocus = true,
WindowStartupLocation = WindowStartupLocation.CenterScreen,
};
frmMainDeEnCrypt.Show();
return;
case "StarterCsvExporter":
Lib.Guis.SieStarterCsvExporter.FrmMain frmMain = new();
frmMain.Show();
return;
case "Folder":
Lib.Guis.Folder.Mgt.FrmMain frmFolderMgtMain = new()
{
CloseAtLostFocus = true,
Data = Global.Vars.GlobalSettings.Folders
};
frmFolderMgtMain.Show();
return;
//case "TxtToClip":
// Lib.Guis.TxtToClip.Mgt.FrmMain frmTxtToClipMain = new()
// {
// CloseAtLostFocus = true,
// InputData = Global.AppSettings.TxtToClip
// };
// frmTxtToClipMain.Show();
// return;
case "Rdp.Mgt":
Lib.Guis.Rdp.Mgt.FrmMain frmRdpMain = new()
{
CloseAtLostFocus = true,
InputData = Global.Vars.GlobalSettings.Rdps,
Exe = GetExeByCmdName("Rdp").ExePath,
FrmTitle = "Remotedesktopverbindungen",
};
frmRdpMain.Show();
break;
case "WebRadio":
//Lib.Guis.WebRadio.FrmMain frmWebRadio = new()
//{
// CloseAtLostFocus = false,
// InputData = Global.AppSettings.WebRadioUrls,
//};
//frmWebRadio.Show();
break;
default:
foreach (ICmd cmd in cmds)
{
if (String.Equals(parameter.ToString(), cmd.Cmd))
selectedCmd = cmd;
}
break;
}
if (selectedCmd == null)
return;
OpenExe(selectedCmd);
OpenUrl(selectedCmd);
}
public override bool CanExecute(object parameter)
{
if (parameter == null)
return false;
var cmds = Global.Vars.GlobalSettings.Cmds.ToList();
ICmd selectedCmd = null;
switch ((string)parameter)
{
case "DarkMode":
return Vars.AdminRights;
case "Epl.Prj":
return true;
case "Epl.Pdf":
return true;
case "Epl.PdfMgt":
return Vars.AdminRights;
case "DeEncrypt":
return Vars.AdminRights;
case "StarterCsvExporter":
return Vars.AdminRights;
case "Folder":
return Vars.GlobalSettings.Folders != null;
//case "TxtToClip":
// return Vars.GlobalSettings.TxtToClip != null;
case "Rdp.Mgt":
return Vars.GlobalSettings.Rdps != null;
case "WebRadio":
return false;// Global.AppSettings.WebRadioUrls != null;
default:
foreach (ICmd cmd in cmds)
{
if (String.Equals(parameter.ToString(), cmd.Cmd))
selectedCmd = cmd;
}
break;
}
if (selectedCmd == null)
return false;
foreach (var file in selectedCmd.Exe.ToList())
{
if (File.Exists(Environment.ExpandEnvironmentVariables(file.ExePath.Trim())))
return true;
else if (File.Exists(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), file.ExePath.Trim())))
return true;
}
foreach (var url in selectedCmd.Urls)
{
if (url != String.Empty)
return true;
}
return false;
}
private static void OpenExe(ICmd selectedCmd)
{
IExe selectedFile = GetApp(selectedCmd.Exe);
if (selectedFile == null)
return;
if (selectedFile.ExePath == String.Empty)
return;
if (ProgramIsRunning(selectedFile.ExePath))
{
ProgramToFront(selectedFile.ExePath);
Vars.Log.Info("Anwendung \"{0}\" wurde in den Vordergrund gebracht", selectedFile.ExePath);
}
else
{
var selectedFileExePath = string.Empty;
if (File.Exists(Environment.ExpandEnvironmentVariables(selectedFile.ExePath.Trim())))
selectedFileExePath = Environment.ExpandEnvironmentVariables(selectedFile.ExePath.Trim());
if (File.Exists(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), selectedFile.ExePath.Trim())))
selectedFileExePath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), selectedFile.ExePath.Trim());
var abc = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), selectedFileExePath.Trim());
Process process = new();
process.StartInfo.FileName = selectedFileExePath;
process.StartInfo.WorkingDirectory = selectedFile.Path ?? Path.GetDirectoryName(selectedFileExePath);
process.StartInfo.Arguments = selectedFile.Arguments ?? string.Empty;
try
{
process.Start();
Vars.Log.Info("Anwendung \"{0}\" wurde gestartet", selectedFile.ExePath);
}
catch (System.ComponentModel.Win32Exception ex) when (ex.NativeErrorCode == 740)
{
try
{
process.StartInfo.UseShellExecute = true;
process.StartInfo.Verb = "runas";
process.Start();
Vars.Log.Info("Anwendung \"{0}\" wurde als Admin gestartet", selectedFile.ExePath);
}
catch (Exception ex2)
{
Vars.Log.Info("Anwendung konnte durch folgenden Fehler \"{0}\" nicht gestartet werden.", ex2.Message);
}
}
}
}
private static void OpenUrl(ICmd selectedCmd)
{
foreach (var url in selectedCmd.Urls)
{
if (url == String.Empty)
return;
Process.Start(new ProcessStartInfo(url.Replace("&", "^&")) { UseShellExecute = true });
Vars.Log.Info("Link \"{0}\" wurde geföffnet.", url.Replace("&", "^&"));
Thread.Sleep(100);
}
}
private static IExe GetExeByCmdName(string cmdName)
{
foreach (var cmd in Vars.GlobalSettings.Cmds)
{
if (string.Equals(cmd.Cmd, cmdName, StringComparison.InvariantCultureIgnoreCase))
return GetApp(cmd.Exe);
}
return null;
}
private static bool ProgramIsRunning(string FullPath)
{
string FilePath = Path.GetDirectoryName(FullPath);
string FileName = Path.GetFileNameWithoutExtension(FullPath).ToLower();
bool isRunning = false;
Process[] pList = Process.GetProcessesByName(FileName);
foreach (Process p in pList)
{
if (p.MainModule.FileName.StartsWith(FilePath, StringComparison.InvariantCultureIgnoreCase))
{
isRunning = true;
break;
}
}
return isRunning;
}
private static IExe GetApp(IEnumerable<IExe> files)
{
if (files.ToList().Count == 0)
return null;
var selectedFile = files.ToList()[0];
foreach (var file in files.ToList())
{
if (File.Exists(Environment.ExpandEnvironmentVariables(file.ExePath.Trim())))
selectedFile = (IExe)file;
else
continue;
}
return selectedFile;
}
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr handle);
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool ShowWindow(IntPtr handle, int nCmdShow);
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool IsIconic(IntPtr handle);
private static void ProgramToFront(string FullPath)
{
string FilePath = Path.GetDirectoryName(FullPath);
string FileName = Path.GetFileNameWithoutExtension(FullPath).ToLower();
Process[] pList = Process.GetProcessesByName(FileName);
foreach (Process p in pList)
{
if (p.MainModule.FileName.StartsWith(FilePath, StringComparison.InvariantCultureIgnoreCase))
{
IntPtr handle = p.MainWindowHandle;
if (IsIconic(handle))
ShowWindow(handle, 9);
SetForegroundWindow(handle);
break;
}
}
}
}
}

View File

@@ -4,9 +4,9 @@ using System.Windows;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using Hardcodet.Wpf.TaskbarNotification;
//using Hardcodet.Wpf.TaskbarNotification;
namespace FSI.BT.Tools.Commands
namespace FSI.BT.Tools.Global.Commands
{
/// <summary>
/// Basic implementation of the <see cref="ICommand"/>
@@ -19,7 +19,7 @@ namespace FSI.BT.Tools.Commands
/// <summary>
/// A singleton instance.
/// </summary>
private static T? command;
private static T command;
/// <summary>
/// Gets a shared command instance.
@@ -78,20 +78,20 @@ namespace FSI.BT.Tools.Commands
}
/// <summary>
/// Resolves the window that owns the TaskbarIcon class.
/// </summary>
/// <param name="commandParameter"></param>
/// <returns>Window</returns>
protected Window? GetTaskbarWindow(object commandParameter)
{
if (IsDesignMode)
return null;
///// <summary>
///// Resolves the window that owns the TaskbarIcon class.
///// </summary>
///// <param name="commandParameter"></param>
///// <returns>Window</returns>
//protected Window GetTaskbarWindow(object commandParameter)
//{
// if (IsDesignMode)
// return null;
// get the showcase window off the taskbar icon
var tb = commandParameter as TaskbarIcon;
return tb == null ? null : TryFindParent<Window>(tb);
}
// // get the showcase window off the taskbar icon
// var tb = commandParameter as TaskbarIcon;
// return tb == null ? null : TryFindParent<Window>(tb);
//}
#region TryFindParent helper
@@ -104,7 +104,7 @@ namespace FSI.BT.Tools.Commands
/// <returns>The first parent item that matches the submitted
/// type parameter. If not matching item can be found, a null
/// reference is being returned.</returns>
public static TParent? TryFindParent<TParent>(DependencyObject child) where TParent : DependencyObject
public static TParent TryFindParent<TParent>(DependencyObject child) where TParent : DependencyObject
{
//get parent item
DependencyObject parentObject = GetParentObject(child);
@@ -131,7 +131,7 @@ namespace FSI.BT.Tools.Commands
/// <param name="child">The item to be processed.</param>
/// <returns>The submitted item's parent, if available. Otherwise
/// null.</returns>
public static DependencyObject? GetParentObject(DependencyObject child)
public static DependencyObject GetParentObject(DependencyObject child)
{
if (child == null) return null;
@@ -140,7 +140,7 @@ namespace FSI.BT.Tools.Commands
DependencyObject parent = ContentOperations.GetParent(contentElement);
if (parent != null) return parent;
FrameworkContentElement? fce = contentElement as FrameworkContentElement;
FrameworkContentElement fce = contentElement as FrameworkContentElement;
return fce?.Parent;
}

View File

@@ -1,6 +1,6 @@
using System.Windows;
namespace FSI.BT.Tools.Commands
namespace FSI.BT.Tools.Global.Commands
{
/// <summary>
/// Shows the main window.
@@ -9,6 +9,7 @@ namespace FSI.BT.Tools.Commands
{
public override void Execute(object parameter)
{
Vars.Log.Info("Anwendung wurde beendet!");
Application.Current.Shutdown();
}

View File

@@ -1,6 +1,6 @@
using System.Windows;
namespace FSI.BT.Tools.Commands
namespace FSI.BT.Tools.Global.Commands
{
/// <summary>
/// Shows the main window.
@@ -9,15 +9,24 @@ namespace FSI.BT.Tools.Commands
{
public override void Execute(object parameter)
{
Lib.Guis.AutoPw.FrmMain frmMain = new()
Lib.Guis.AutoPw.FrmMain frmMain = new Lib.Guis.AutoPw.FrmMain()
{
CloseAtLostFocus = false,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
WindowStartupLocation = WindowStartupLocation.CenterScreen,
};
frmMain.ShowDialog();
Global.UserRights =
Global.AdminRights = frmMain.PwOk;
Global.Vars.UserRights =
Vars.AdminRights = frmMain.PwOk;
if (frmMain.PwOk)
{
Vars.Log.Info("Admin-Passowrt wurde korrekt eingegben.");
}
else
{
Vars.Log.Info("Anmeldung wurde vom Benutzer abgebrochen.");
}
}
public override bool CanExecute(object parameter)

View File

@@ -0,0 +1,24 @@
namespace FSI.BT.Tools.Global.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class ProcessCommand : CommandBase<ProcessCommand>
{
public override void Execute(object parameter)
{
RadialMenu.UserInterface.FrmProcesses frm = new RadialMenu.UserInterface.FrmProcesses()
{
WinCC = Vars.WinCC
};
frm.Iba = Vars.Iba;
frm.ShowDialog();
}
public override bool CanExecute(object parameter)
{
return Vars.AdminRights;
}
}
}

View File

@@ -0,0 +1,68 @@
// <copyright file="BringWindowToTop.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.Global.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
private const int SwRestore = 9;
public static void ForceForegroundWindow(IntPtr hWnd)
{
uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
uint appThread = GetCurrentThreadId();
const int SW_SHOW = 5;
int cmdShow = SW_SHOW;
if (IsIconic(hWnd))
{
cmdShow = SwRestore;
}
if (foreThread != appThread)
{
AttachThreadInput(foreThread, appThread, true);
BringWindowToTop(hWnd);
ShowWindow(hWnd, cmdShow);
AttachThreadInput(foreThread, appThread, false);
}
else
{
BringWindowToTop(hWnd);
ShowWindow(hWnd, cmdShow);
}
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr processId);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern uint GetCurrentThreadId();
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern bool BringWindowToTop(IntPtr hWnd);
}
}

View File

@@ -0,0 +1,25 @@
// <copyright file="CreatePopupMenu.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.Global.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
public static IntPtr User32CreatePopupMenu()
{
return CreatePopupMenu();
}
// The CreatePopupMenu function creates a drop-down menu, submenu, or shortcut menu. The menu is initially empty. You can insert or append menu items by using the InsertMenuItem function. You can also use the InsertMenu function to insert menu items and the AppendMenu function to append menu items.
[DllImport("user32", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern IntPtr CreatePopupMenu();
}
}

View File

@@ -0,0 +1,40 @@
// <copyright file="CreateRoundRectRgn.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.Global.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
public static bool GetRegionRoundCorners(int width, int height, int widthEllipse, int heightEllipse, out System.Drawing.Region region)
{
bool success = false;
region = null;
IntPtr handle = CreateRoundRectRgn(0, 0, width, height, widthEllipse, heightEllipse);
if (handle != IntPtr.Zero)
{
region = System.Drawing.Region.FromHrgn(handle);
_ = DeleteObject(handle);
success = true;
}
return success;
}
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr CreateRoundRectRgn(
int nLeftRect, // x-coordinate of upper-left corner
int nTopRect, // y-coordinate of upper-left corner
int nRightRect, // x-coordinate of lower-right corner
int nBottomRect, // y-coordinate of lower-right corner
int nWidthEllipse, // width of ellipse
int nHeightEllipse); // height of ellipse
}
}

View File

@@ -0,0 +1,19 @@
// <copyright file="DeleteObject.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.Global.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
[DllImport("gdi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern int DeleteObject(IntPtr hIcon);
}
}

View File

@@ -0,0 +1,24 @@
// <copyright file="DestroyIcon.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace FSI.BT.Tools.Global.DllImports
{
using System;
using System.Runtime.InteropServices;
/// <summary>
/// wraps the methodcalls to native windows dll's.
/// </summary>
public static partial class NativeMethods
{
public static void User32DestroyIcon(IntPtr hIcon)
{
_ = DestroyIcon(hIcon);
}
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.UserDirectories)]
private static extern int DestroyIcon(IntPtr hIcon);
}
}

Some files were not shown because too many files have changed in this diff Show More