Projektdateien hinzufügen.

This commit is contained in:
Kevin Krüger
2023-07-24 12:00:34 +02:00
parent 656751e10b
commit 0d00a90942
210 changed files with 45049 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
namespace VideoBrowser.Extensions
{
using System.Collections.Generic;
using System.Collections.Specialized;
/// <summary>
/// Defines the <see cref="DictionaryExtensions" />
/// </summary>
public static class DictionaryExtensions
{
#region Methods
/// <summary>
/// The Get
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="dictionary">The dictionary<see cref="Dictionary{TKey, TValue}"/></param>
/// <param name="key">The key<see cref="TKey"/></param>
/// <param name="defaultValue">The defaultValue<see cref="TValue"/></param>
/// <returns>The <see cref="TValue"/></returns>
public static TValue Get<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
{
if (!dictionary.ContainsKey(key))
{
dictionary.Add(key, defaultValue);
}
return dictionary[key];
}
/// <summary>
/// The Get
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="dictionary">The dictionary<see cref="OrderedDictionary"/></param>
/// <param name="key">The key<see cref="object"/></param>
/// <param name="defaultValue">The defaultValue<see cref="object"/></param>
/// <returns>The <see cref="TValue"/></returns>
public static TValue Get<TValue>(this OrderedDictionary dictionary, object key, object defaultValue)
{
if (!dictionary.Contains(key))
{
dictionary.Add(key, defaultValue);
}
return (TValue)dictionary[key];
}
/// <summary>
/// The Put
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="dictionary">The dictionary<see cref="Dictionary{TKey, TValue}"/></param>
/// <param name="key">The key<see cref="TKey"/></param>
/// <param name="value">The value<see cref="TValue"/></param>
public static void Put<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue value)
{
if (dictionary.ContainsKey(key))
{
dictionary[key] = value;
}
else
{
dictionary.Add(key, value);
}
}
/// <summary>
/// The Put
/// </summary>
/// <param name="dictionary">The dictionary<see cref="OrderedDictionary"/></param>
/// <param name="key">The key<see cref="object"/></param>
/// <param name="value">The value<see cref="object"/></param>
public static void Put(this OrderedDictionary dictionary, object key, object value)
{
if (dictionary.Contains(key))
{
dictionary[key] = value;
}
else
{
dictionary.Add(key, value);
}
}
#endregion Methods
}
}

View File

@@ -0,0 +1,229 @@
namespace VideoBrowser.Extensions
{
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Markup;
/// <summary>
/// Defines the <see cref="EventBindingExtension" />.
/// </summary>
[MarkupExtensionReturnType(typeof(Delegate))]
public class EventBindingExtension : MarkupExtension
{
#region Fields
/// <summary>
/// The command binder attached property.
/// </summary>
private static readonly DependencyProperty CommandBinderProperty =
DependencyProperty.RegisterAttached(nameof(CommandBinderProperty).Name(), typeof(ICommand), typeof(EventBindingExtension), new PropertyMetadata(null));
/// <summary>
/// The command parameter binder attached property.
/// </summary>
private static readonly DependencyProperty CommandParameterBinderProperty =
DependencyProperty.RegisterAttached(nameof(CommandParameterBinderProperty).Name(), typeof(object), typeof(EventBindingExtension), new PropertyMetadata(null));
/// <summary>
/// Name of the Command to be invoked when the event fires
/// </summary>
private readonly string _commandName;
#endregion Fields
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="EventBindingExtension"/> class.
/// </summary>
public EventBindingExtension()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="EventBindingExtension"/> class.
/// </summary>
/// <param name="command">The command<see cref="string"/>.</param>
public EventBindingExtension(string command)
{
this._commandName = command;
}
#endregion Constructors
#region Properties
/// <summary>
/// Gets or sets the Command.
/// </summary>
public Binding Command { get; set; }
/// <summary>
/// Gets or sets the CommandParameter.
/// </summary>
public Binding CommandParameter { get; set; }
/// <summary>
/// Gets or sets the Element.
/// </summary>
private DependencyObject Element { get; set; }
#endregion Properties
#region Methods
/// <summary>
/// The GetCommandBinder.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <returns>The <see cref="ICommand"/>.</returns>
public static ICommand GetCommandBinder(DependencyObject obj)
{
return (ICommand)obj.GetValue(CommandBinderProperty);
}
/// <summary>
/// The GetCommandParameterBinder.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <returns>The <see cref="object"/>.</returns>
public static object GetCommandParameterBinder(DependencyObject obj)
{
return obj.GetValue(CommandParameterBinderProperty);
}
/// <summary>
/// The SetCommandBinder.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <param name="value">The value<see cref="ICommand"/>.</param>
public static void SetCommandBinder(DependencyObject obj, ICommand value)
{
obj.SetValue(CommandBinderProperty, value);
}
/// <summary>
/// The SetCommandParameterBinder.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <param name="value">The value<see cref="object"/>.</param>
public static void SetCommandParameterBinder(DependencyObject obj, object value)
{
obj.SetValue(CommandParameterBinderProperty, value);
}
/// <summary>
/// The ProvideValue.
/// </summary>
/// <param name="serviceProvider">.</param>
/// <returns>.</returns>
public override object ProvideValue(IServiceProvider serviceProvider)
{
// Retrieve a reference to the InvokeCommand helper method declared below, using reflection
MethodInfo invokeCommand = GetType().GetMethod(nameof(InvokeCommand), BindingFlags.Instance | BindingFlags.NonPublic);
if (invokeCommand != null)
{
// Check if the current context is an event or a method call with two parameters
var target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
if (target != null)
{
this.Element = target.TargetObject as DependencyObject;
var property = target.TargetProperty;
if (property is EventInfo)
{
// If the context is an event, simply return the helper method as delegate
// (this delegate will be invoked when the event fires)
var eventHandlerType = (property as EventInfo).EventHandlerType;
return invokeCommand.CreateDelegate(eventHandlerType, this);
}
else if (property is MethodInfo)
{
// Some events are represented as method calls with 2 parameters:
// The first parameter is the control that acts as the event's sender,
// the second parameter is the actual event handler
var methodParameters = (property as MethodInfo).GetParameters();
if (methodParameters.Length == 2)
{
var eventHandlerType = methodParameters[1].ParameterType;
return invokeCommand.CreateDelegate(eventHandlerType, this);
}
}
}
}
throw new InvalidOperationException("The EventBinding markup extension is valid only in the context of events.");
}
/// <summary>
/// The GetDataContext.
/// </summary>
/// <param name="sender">The sender<see cref="object"/>.</param>
/// <returns>The <see cref="object"/>.</returns>
private object GetDataContext(object sender)
{
if (sender is FrameworkContentElement control)
{
return control.DataContext;
}
return sender is FrameworkElement element ? element.DataContext : null;
}
/// <summary>
/// The InvokeCommand.
/// </summary>
/// <param name="sender">.</param>
/// <param name="args">.</param>
private void InvokeCommand(object sender, EventArgs args)
{
var dataContext = this.GetDataContext(sender);
if (dataContext == null)
{
throw new NullReferenceException($"DataContext is null.");
}
object commandParameter = null;
if (this.CommandParameter != null)
{
BindingOperations.SetBinding(this.Element, CommandParameterBinderProperty, this.CommandParameter);
commandParameter = this.Element.GetValue(CommandParameterBinderProperty);
BindingOperations.ClearBinding(this.Element, CommandParameterBinderProperty);
}
var executeParameters = (sender, args, commandParameter);
if (!string.IsNullOrEmpty(_commandName) && dataContext != null)
{
// Find control's ViewModel
var viewmodel = dataContext;
if (viewmodel != null)
{
// Command must be declared as public property within ViewModel
var commandProperty = viewmodel.GetType().GetProperty(_commandName);
if (commandProperty != null && commandProperty.GetValue(viewmodel) is ICommand constructorCommand && constructorCommand.CanExecute(args))
{
// Execute Command and pass event arguments as parameter
constructorCommand.Execute(executeParameters);
return;
}
}
}
// Get the binding values.
BindingOperations.SetBinding(this.Element, CommandBinderProperty, this.Command);
var command = this.Element.GetValue(CommandBinderProperty);
BindingOperations.ClearBinding(this.Element, CommandBinderProperty);
// Execute the command.
if ((command is ICommand relayCommand) && relayCommand.CanExecute(commandParameter))
{
relayCommand.Execute(executeParameters);
}
}
#endregion Methods
}
}

View File

@@ -0,0 +1,136 @@
namespace VideoBrowser.Extensions
{
using System.Windows;
/// <summary>
/// Defines the <see cref="FocusExtension" />.
/// </summary>
public static class FocusExtension
{
#region Fields
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached(nameof(IsFocusedProperty).Name(), typeof(bool), typeof(FocusExtension), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsFocusedChanged));
public static readonly DependencyProperty TrackFocusProperty =
DependencyProperty.RegisterAttached(nameof(TrackFocusProperty).Name(), typeof(bool), typeof(FocusExtension), new PropertyMetadata(false, OnTrackFocusChanged));
#endregion Fields
#region Methods
/// <summary>
/// The GetIsFocused.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <returns>The <see cref="bool"/>.</returns>
public static bool GetIsFocused(DependencyObject obj) => (bool)obj.GetValue(IsFocusedProperty);
/// <summary>
/// The GetTrackFocus.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <returns>The <see cref="bool"/>.</returns>
public static bool GetTrackFocus(DependencyObject obj)
{
return (bool)obj.GetValue(TrackFocusProperty);
}
/// <summary>
/// The SetIsFocused.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <param name="value">The value<see cref="bool"/>.</param>
public static void SetIsFocused(DependencyObject obj, bool value) => obj.SetValue(IsFocusedProperty, value);
/// <summary>
/// The SetTrackFocus.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <param name="value">The value<see cref="bool"/>.</param>
public static void SetTrackFocus(DependencyObject obj, bool value)
{
obj.SetValue(TrackFocusProperty, value);
}
/// <summary>
/// The OnGotFocus.
/// </summary>
/// <param name="sender">The sender<see cref="object"/>.</param>
/// <param name="e">The e<see cref="RoutedEventArgs"/>.</param>
private static void OnGotFocus(object sender, RoutedEventArgs e)
{
if (!(sender is FrameworkElement element))
{
return;
}
if (!GetIsFocused(element))
{
SetIsFocused(element, true);
}
}
/// <summary>
/// The OnIsFocusedChanged.
/// </summary>
/// <param name="d">The d<see cref="DependencyObject"/>.</param>
/// <param name="e">The e<see cref="DependencyPropertyChangedEventArgs"/>.</param>
private static void OnIsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var element = (FrameworkElement)d;
var isFocused = (bool)e.NewValue;
if (isFocused)
{
element.Focus();
}
}
/// <summary>
/// The OnLostFocus.
/// </summary>
/// <param name="sender">The sender<see cref="object"/>.</param>
/// <param name="e">The e<see cref="RoutedEventArgs"/>.</param>
private static void OnLostFocus(object sender, RoutedEventArgs e)
{
if (!(sender is FrameworkElement element))
{
return;
}
if (GetIsFocused(element))
{
SetIsFocused(element, false);
}
}
/// <summary>
/// The OnTrackFocusChanged.
/// </summary>
/// <param name="d">The d<see cref="DependencyObject"/>.</param>
/// <param name="e">The e<see cref="DependencyPropertyChangedEventArgs"/>.</param>
private static void OnTrackFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is FrameworkElement element))
{
return;
}
var oldValue = (bool)e.OldValue;
var newValue = (bool)e.NewValue;
if (!oldValue && newValue) // If changed from false to true
{
element.GotFocus += OnGotFocus;
element.LostFocus += OnLostFocus;
}
else if (oldValue && !newValue) // If changed from true to false
{
element.GotFocus -= OnGotFocus;
element.LostFocus -= OnLostFocus;
}
}
#endregion Methods
}
}

View File

@@ -0,0 +1,134 @@
namespace VideoBrowser.Extensions
{
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using VideoBrowser.Common;
/// <summary>
/// Defines the <see cref="INotifyPropertyChangedExtension" />
/// </summary>
public static class INotifyPropertyChangedExtension
{
#region Delegates
/// <summary>
/// The PropertyChangedInvokerEventHandler
/// </summary>
/// <param name="propertyName">The <see cref="string"/></param>
public delegate void PropertyChangedInvokerEventHandler(string propertyName);
#endregion Delegates
#region Methods
/// <summary>
/// Invokes the properties changed.
/// </summary>
/// <param name="instance">The INotifyPropertyChanged implementation.</param>
/// <param name="invoker">The invoker.</param>
/// <param name="propertyNames">The property name list.</param>
public static void InvokePropertiesChanged(this INotifyPropertyChanged instance, PropertyChangedInvokerEventHandler invoker, params string[] propertyNames)
{
foreach (var propertyName in propertyNames)
{
invoker?.Invoke(propertyName);
}
}
/// <summary>
/// The IsMatch
/// </summary>
/// <param name="e">The <see cref="PropertyChangedEventArgs"/></param>
/// <param name="propertyNames">The <see cref="string"/></param>
/// <returns>The <see cref="bool"/></returns>
public static bool IsMatch(this PropertyChangedEventArgs e, params string[] propertyNames)
{
var propertyName = e.PropertyName;
foreach (var name in propertyNames)
{
if (propertyName == name)
{
return true;
}
}
return false;
}
/// <summary>
/// Sets the specified invoker.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance">The instance.</param>
/// <param name="invoker">The invoker.</param>
/// <param name="field">The field.</param>
/// <param name="value">The value.</param>
/// <param name="propertyName">Name of the property.</param>
/// <param name="propertyNames">The other optional property names to notify.</param>
/// <returns> True if old value and new value are different. </returns>
public static bool Set<T>(this INotifyPropertyChanged instance, PropertyChangedInvokerEventHandler invoker, ref T field, T value, [CallerMemberName] string propertyName = null, params string[] propertyNames)
{
if (EqualityComparer<T>.Default.Equals(field, value))
{
return false;
}
field = value;
invoker?.Invoke(propertyName);
return true;
}
/// <summary>
/// The Set
/// </summary>
/// <param name="sender">The sender<see cref="INotifyPropertyChanged"/></param>
/// <param name="propertyChanged">The propertyChanged<see cref="PropertyChangedEventHandler"/></param>
/// <param name="field">The field<see cref="double"/></param>
/// <param name="value">The value<see cref="double"/></param>
/// <param name="range">The range<see cref="RangeDouble"/></param>
/// <param name="propertyName">The propertyName<see cref="string"/></param>
/// <param name="propertyNames">The propertyNames<see cref="string[]"/></param>
/// <returns>The <see cref="bool"/></returns>
public static bool Set(this INotifyPropertyChanged sender, PropertyChangedEventHandler propertyChanged, ref double field, double value, RangeDouble range, [CallerMemberName] string propertyName = null, params string[] propertyNames)
{
if (field.IsEqualTo(value))
{
return false;
}
if (value.IsInRange(range.Start, range.End))
{
field = value;
}
propertyChanged?.Invoke(sender, new PropertyChangedEventArgs(propertyName));
return true;
}
/// <summary>
/// The Set
/// </summary>
/// <typeparam name="T">The property type.</typeparam>
/// <param name="sender">The sender.</param>
/// <param name="propertyChanged">The property changed.</param>
/// <param name="field">The field.</param>
/// <param name="value">The value.</param>
/// <param name="propertyName">Name of the property.</param>
/// <param name="propertyNames">The property names.</param>
/// <returns> True if old value and new value are different. </returns>
public static bool Set<T>(this INotifyPropertyChanged sender, PropertyChangedEventHandler propertyChanged, ref T field, T value, [CallerMemberName] string propertyName = null, params string[] propertyNames)
{
if (EqualityComparer<T>.Default.Equals(field, value))
{
return false;
}
field = value;
propertyChanged?.Invoke(sender, new PropertyChangedEventArgs(propertyName));
return true;
}
#endregion Methods
}
}

View File

@@ -0,0 +1,31 @@
namespace VideoBrowser.Extensions
{
using System;
using System.Collections.Generic;
/// <summary>
/// Defines the <see cref="ListExtension" />.
/// </summary>
public static class ListExtension
{
#region Methods
/// <summary>
/// The ClearAndDispose.
/// </summary>
/// <typeparam name="T">.</typeparam>
/// <param name="list">The list<see cref="ICollection{T}"/>.</param>
public static void ClearAndDispose<T>(this ICollection<T> list)
{
foreach (var item in list)
{
var disposableItem = item as IDisposable;
disposableItem?.Dispose();
}
list.Clear();
}
#endregion Methods
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,155 @@
namespace VideoBrowser.Extensions
{
using VideoBrowser.Common;
/// <summary>
/// Defines the <see cref="RangeExtension" />
/// </summary>
public static class RangeExtension
{
#region Methods
/// <summary>
/// The Center
/// </summary>
/// <param name="range">The range<see cref="RangeDouble"/></param>
/// <returns>The <see cref="double"/></returns>
public static double Center(this RangeDouble range)
{
var center = range.Start + range.Length() * 0.5;
return center;
}
/// <summary>
/// The Contains
/// </summary>
/// <param name="container">The container<see cref="RangeDouble"/></param>
/// <param name="range">The range<see cref="RangeDouble"/></param>
/// <returns>The <see cref="bool"/></returns>
public static bool Contains(this RangeDouble container, RangeDouble range)
{
var contains = range.Start.IsInRange(container.Start, container.End) && range.End.IsInRange(container.Start, container.End);
return contains;
}
/// <summary>
/// The Contains
/// </summary>
/// <param name="container">The container<see cref="RangeInt"/></param>
/// <param name="range">The range<see cref="RangeInt"/></param>
/// <returns>The <see cref="bool"/></returns>
public static bool Contains(this RangeInt container, RangeInt range)
{
var contains = range.Start.IsInRange(container.Start, container.End) && range.End.IsInRange(container.Start, container.End);
return contains;
}
/// <summary>
/// The IsEmpty
/// </summary>
/// <param name="range">The range<see cref="RangeDouble"/></param>
/// <returns>The <see cref="bool"/></returns>
public static bool IsEmpty(this RangeDouble range)
{
var isEmpty = range.Start.IsZero() && range.End.IsZero();
return isEmpty;
}
/// <summary>
/// Determines whether [is in range] [the specified minimum].
/// </summary>
/// <param name="value">The value.</param>
/// <param name="min">The minimum.</param>
/// <param name="max">The maximum.</param>
/// <returns>The <see cref="bool"/></returns>
public static bool IsInRange(this double value, double min, double max)
{
return (min < max) ? value >= min && value <= max : value >= max && value <= min;
}
/// <summary>
/// The IsInRange
/// </summary>
/// <param name="value">The value<see cref="int"/></param>
/// <param name="min">The min<see cref="int"/></param>
/// <param name="max">The max<see cref="int"/></param>
/// <returns>The <see cref="bool"/></returns>
public static bool IsInRange(this int value, int min, int max)
{
return (min < max) ? value >= min && value <= max : value >= max && value <= min;
}
/// <summary>
/// Lengthes the specified range.
/// </summary>
/// <param name="range">The range.</param>
/// <returns>The length in double.</returns>
public static double Length(this RangeDouble range)
{
return range.End - range.Start;
}
/// <summary>
/// The Length
/// </summary>
/// <param name="range">The range<see cref="RangeInt"/></param>
/// <returns>The <see cref="int"/></returns>
public static int Length(this RangeInt range)
{
return range.End - range.Start;
}
/// <summary>
/// The MoveInsideContainer
/// </summary>
/// <param name="range">The range<see cref="RangeDouble"/></param>
/// <param name="container">The container<see cref="RangeDouble"/></param>
/// <returns>The <see cref="RangeDouble"/></returns>
public static RangeDouble MoveInsideContainer(this RangeDouble range, RangeDouble container)
{
if (container.Contains(range))
{
return range;
}
var length = range.Length();
if (length > container.Length())
{
length = container.Length();
}
var rangeInside = range.Start < container.Start ? new RangeDouble(container.Start, container.Start + length) : new RangeDouble(container.End - length, container.End);
return rangeInside;
}
/// <summary>
/// The Offset the range to the specified distance.
/// </summary>
/// <param name="range">The range<see cref="RangeDouble"/></param>
/// <param name="distance">The distance<see cref="double"/></param>
/// <param name="extentRange">The extentRange<see cref="RangeDouble"/></param>
/// <returns>The <see cref="RangeDouble"/></returns>
public static RangeDouble Offset(this RangeDouble range, double distance, RangeDouble extentRange)
{
var length = range.Length();
if (extentRange.Length() < length)
{
length = extentRange.Length();
}
var start = range.Start + distance;
var end = start + length;
var newRange = new RangeDouble(start, end);
if (extentRange.Contains(newRange))
{
return newRange;
}
return start < extentRange.Start
? new RangeDouble(extentRange.Start, extentRange.Start + length)
: new RangeDouble(extentRange.End - length, extentRange.End);
}
#endregion Methods
}
}

View File

@@ -0,0 +1,56 @@
namespace VideoBrowser.Extensions
{
using VideoBrowser.Common;
/// <summary>
/// Defines the <see cref="StringExtension" />
/// </summary>
public static class StringExtension
{
#region Properties
/// <summary>
/// Gets the ByteSizeFormatProvider
/// </summary>
private static ByteFormatProvider ByteSizeFormatProvider { get; } = new ByteFormatProvider();
#endregion Properties
#region Methods
/// <summary>
/// Replace dependency property name to property name.
/// </summary>
/// <param name="propertyName">The propertyName<see cref="string"/></param>
/// <returns>The <see cref="string"/></returns>
public static string Name(this string propertyName)
{
var name = propertyName.Replace("Property", string.Empty);
return name;
}
/// <summary>
/// The ToFormatedByte
/// </summary>
/// <param name="byteSize">The byteSize<see cref="int"/></param>
/// <returns>The <see cref="string"/></returns>
public static string ToFormatedByte(int byteSize)
{
var formated = string.Format(ByteSizeFormatProvider, "{0:fs}", byteSize);
return formated;
}
/// <summary>
/// The ToFormatedSpeed
/// </summary>
/// <param name="speed">The speed<see cref="int"/></param>
/// <returns>The <see cref="string"/></returns>
public static string ToFormatedSpeed(int speed)
{
var formated = string.Format(ByteSizeFormatProvider, "{0:s}", speed);
return formated;
}
#endregion Methods
}
}

View File

@@ -0,0 +1,271 @@
namespace VideoBrowser.Extensions
{
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using VideoBrowser.Helpers;
/// <summary>
/// Defines the <see cref="TextBoxExtension" />.
/// </summary>
public static class TextBoxExtension
{
#region Fields
public static readonly DependencyProperty CaretIndexProperty =
DependencyProperty.RegisterAttached(nameof(CaretIndexProperty).Name(), typeof(int), typeof(TextBoxExtension), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnCaretIndexChanged));
public static readonly DependencyProperty IsClickToSelectAllProperty =
DependencyProperty.RegisterAttached(nameof(IsClickToSelectAllProperty).Name(), typeof(bool), typeof(TextBoxExtension), new PropertyMetadata(false, OnIsClickToSelectAllChanged));
public static readonly DependencyProperty SelectionLengthProperty =
DependencyProperty.RegisterAttached(nameof(SelectionLengthProperty).Name(), typeof(int), typeof(TextBoxExtension), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectionLengthChanged));
public static readonly DependencyProperty SelectionStartProperty =
DependencyProperty.RegisterAttached(nameof(SelectionStartProperty).Name(), typeof(int), typeof(TextBoxExtension), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectionStartChanged));
public static readonly DependencyProperty TrackCaretIndexProperty =
DependencyProperty.RegisterAttached(nameof(TrackCaretIndexProperty).Name(), typeof(bool), typeof(TextBoxExtension), new PropertyMetadata(false, OnTrackCaretIndexChanged));
#endregion Fields
#region Methods
/// <summary>
/// The GetCaretIndex.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <returns>The <see cref="int"/>.</returns>
public static int GetCaretIndex(DependencyObject obj) => (int)obj.GetValue(CaretIndexProperty);
/// <summary>
/// The GetIsClickToSelectAll.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <returns>The <see cref="bool"/>.</returns>
public static bool GetIsClickToSelectAll(DependencyObject obj) => (bool)obj.GetValue(IsClickToSelectAllProperty);
/// <summary>
/// The GetSelectionLength.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <returns>The <see cref="int"/>.</returns>
public static int GetSelectionLength(DependencyObject obj) => (int)obj.GetValue(SelectionLengthProperty);
/// <summary>
/// The GetSelectionStart.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <returns>The <see cref="int"/>.</returns>
public static int GetSelectionStart(DependencyObject obj) => (int)obj.GetValue(SelectionStartProperty);
/// <summary>
/// The GetTrackCaretIndex.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <returns>The <see cref="bool"/>.</returns>
public static bool GetTrackCaretIndex(DependencyObject obj) => (bool)obj.GetValue(TrackCaretIndexProperty);
/// <summary>
/// The SetCaretIndex.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <param name="value">The value<see cref="int"/>.</param>
public static void SetCaretIndex(DependencyObject obj, int value) => obj.SetValue(CaretIndexProperty, value);
/// <summary>
/// The SetIsClickToSelectAll.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <param name="value">The value<see cref="bool"/>.</param>
public static void SetIsClickToSelectAll(DependencyObject obj, bool value) => obj.SetValue(IsClickToSelectAllProperty, value);
/// <summary>
/// The SetSelectionLength.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <param name="value">The value<see cref="int"/>.</param>
public static void SetSelectionLength(DependencyObject obj, int value) => obj.SetValue(SelectionLengthProperty, value);
/// <summary>
/// The SetSelectionStart.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <param name="value">The value<see cref="int"/>.</param>
public static void SetSelectionStart(DependencyObject obj, int value) => obj.SetValue(SelectionStartProperty, value);
/// <summary>
/// The SetTrackCaretIndex.
/// </summary>
/// <param name="obj">The obj<see cref="DependencyObject"/>.</param>
/// <param name="value">The value<see cref="bool"/>.</param>
public static void SetTrackCaretIndex(DependencyObject obj, bool value) => obj.SetValue(TrackCaretIndexProperty, value);
/// <summary>
/// The OnCaretIndexChanged.
/// </summary>
/// <param name="d">The d<see cref="DependencyObject"/>.</param>
/// <param name="e">The e<see cref="DependencyPropertyChangedEventArgs"/>.</param>
private static void OnCaretIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is TextBox textbox))
{
return;
}
var caretIndex = (int)e.NewValue;
if (textbox.CaretIndex != caretIndex)
{
textbox.CaretIndex = caretIndex;
}
}
/// <summary>
/// The OnIsClickToSelectAllChanged.
/// </summary>
/// <param name="d">The d<see cref="DependencyObject"/>.</param>
/// <param name="e">The e<see cref="DependencyPropertyChangedEventArgs"/>.</param>
private static void OnIsClickToSelectAllChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is TextBox textbox))
{
return;
}
var oldValue = (bool)e.OldValue;
var newValue = (bool)e.NewValue;
if (!oldValue && newValue) // If changed from false to true
{
textbox.PreviewMouseLeftButtonDown += OnTextbox_PreviewMouseLeftButtonDown;
textbox.MouseDoubleClick += OnTextbox_MouseDoubleClick;
}
else if (oldValue && !newValue) // If changed from true to false
{
textbox.PreviewMouseLeftButtonDown -= OnTextbox_PreviewMouseLeftButtonDown;
textbox.MouseDoubleClick -= OnTextbox_MouseDoubleClick;
}
}
/// <summary>
/// The OnSelectionChanged.
/// </summary>
/// <param name="sender">The sender<see cref="object"/>.</param>
/// <param name="e">The e<see cref="RoutedEventArgs"/>.</param>
private static void OnSelectionChanged(object sender, RoutedEventArgs e)
{
if (sender is TextBox textbox)
{
SetCaretIndex(textbox, textbox.CaretIndex);
SetSelectionStart(textbox, textbox.SelectionStart);
SetSelectionLength(textbox, textbox.SelectionLength);
}
}
/// <summary>
/// The OnSelectionLengthChanged.
/// </summary>
/// <param name="d">The d<see cref="DependencyObject"/>.</param>
/// <param name="e">The e<see cref="DependencyPropertyChangedEventArgs"/>.</param>
private static void OnSelectionLengthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is TextBox textbox))
{
return;
}
var selectionLength = (int)e.NewValue;
if (textbox.SelectionLength != selectionLength)
{
textbox.SelectionLength = selectionLength;
}
}
/// <summary>
/// The OnSelectionStartChanged.
/// </summary>
/// <param name="d">The d<see cref="DependencyObject"/>.</param>
/// <param name="e">The e<see cref="DependencyPropertyChangedEventArgs"/>.</param>
private static void OnSelectionStartChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is TextBox textbox))
{
return;
}
var selectionStart = (int)e.NewValue;
if (textbox.SelectionStart != selectionStart)
{
textbox.SelectionStart = selectionStart;
}
}
/// <summary>
/// The OnTextbox_MouseDoubleClick.
/// </summary>
/// <param name="sender">The sender<see cref="object"/>.</param>
/// <param name="e">The e<see cref="MouseButtonEventArgs"/>.</param>
private static void OnTextbox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (!(sender is TextBox textbox))
{
return;
}
UIThreadHelper.DelayedInvokeAsync(() =>
{
textbox.Focus();
textbox.SelectAll();
}, 200);
}
/// <summary>
/// The OnTextbox_PreviewMouseLeftButtonDown.
/// </summary>
/// <param name="sender">The sender<see cref="object"/>.</param>
/// <param name="e">The e<see cref="MouseButtonEventArgs"/>.</param>
private static void OnTextbox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!(sender is TextBox textbox))
{
return;
}
if (!textbox.IsFocused)
{
UIThreadHelper.DelayedInvokeAsync(() =>
{
textbox.Focus();
textbox.SelectAll();
}, 200);
}
}
/// <summary>
/// The OnTrackCaretIndexChanged.
/// </summary>
/// <param name="d">The d<see cref="DependencyObject"/>.</param>
/// <param name="e">The e<see cref="DependencyPropertyChangedEventArgs"/>.</param>
private static void OnTrackCaretIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is TextBox textbox))
{
return;
}
var oldValue = (bool)e.OldValue;
var newValue = (bool)e.NewValue;
if (!oldValue && newValue) // If changed from false to true
{
textbox.SelectionChanged += OnSelectionChanged;
}
else if (oldValue && !newValue) // If changed from true to false
{
textbox.SelectionChanged -= OnSelectionChanged;
}
}
#endregion Methods
}
}