using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
namespace MaterialDesignThemes.Wpf
{
///
/// Helper properties for working with text fields.
///
public static class TextFieldAssist
{
///
/// The text box view margin property
///
public static readonly DependencyProperty TextBoxViewMarginProperty = DependencyProperty.RegisterAttached(
"TextBoxViewMargin",
typeof(Thickness),
typeof(TextFieldAssist),
new FrameworkPropertyMetadata(new Thickness(double.NegativeInfinity), FrameworkPropertyMetadataOptions.Inherits, TextBoxViewMarginPropertyChangedCallback));
///
/// Sets the text box view margin.
///
/// The element.
/// The value.
public static void SetTextBoxViewMargin(DependencyObject element, Thickness value)
{
element.SetValue(TextBoxViewMarginProperty, value);
}
///
/// Gets the text box view margin.
///
/// The element.
///
/// The .
///
public static Thickness GetTextBoxViewMargin(DependencyObject element)
{
return (Thickness)element.GetValue(TextBoxViewMarginProperty);
}
///
/// Controls the visibility of the underline decoration.
///
public static readonly DependencyProperty DecorationVisibilityProperty = DependencyProperty.RegisterAttached(
"DecorationVisibility", typeof(Visibility), typeof(TextFieldAssist), new PropertyMetadata(default(Visibility)));
///
/// Controls the visibility of the underline decoration.
///
public static void SetDecorationVisibility(DependencyObject element, Visibility value)
{
element.SetValue(DecorationVisibilityProperty, value);
}
///
/// Controls the visibility of the underline decoration.
///
///
///
public static Visibility GetDecorationVisibility(DependencyObject element)
{
return (Visibility)element.GetValue(DecorationVisibilityProperty);
}
///
/// Controls the visbility of the text field box.
///
public static readonly DependencyProperty HasTextFieldBoxProperty = DependencyProperty.RegisterAttached(
"HasTextFieldBox", typeof(bool), typeof(TextFieldAssist), new PropertyMetadata(false));
public static void SetHasTextFieldBox(DependencyObject element, bool value)
{
element.SetValue(HasTextFieldBoxProperty, value);
}
public static bool GetHasTextFieldBox(DependencyObject element)
{
return (bool)element.GetValue(HasTextFieldBoxProperty);
}
///
/// Controls the visibility of the text field area box.
///
public static readonly DependencyProperty HasTextAreaBoxProperty = DependencyProperty.RegisterAttached(
"HasTextAreaBox", typeof(bool), typeof(TextFieldAssist), new PropertyMetadata(false));
public static void SetHasTextAreaBox(DependencyObject element, bool value)
{
element.SetValue(HasTextAreaBoxProperty, value);
}
public static bool GetHasTextAreaBox(DependencyObject element)
{
return (bool)element.GetValue(HasTextAreaBoxProperty);
}
///
/// Automatially inserts spelling suggestions into the text box context menu.
///
public static readonly DependencyProperty IncludeSpellingSuggestionsProperty = DependencyProperty.RegisterAttached(
"IncludeSpellingSuggestions", typeof(bool), typeof(TextFieldAssist), new PropertyMetadata(default(bool), IncludeSpellingSuggestionsChanged));
public static void SetIncludeSpellingSuggestions(TextBoxBase element, bool value)
{
element.SetValue(IncludeSpellingSuggestionsProperty, value);
}
public static bool GetIncludeSpellingSuggestions(TextBoxBase element)
{
return (bool)element.GetValue(IncludeSpellingSuggestionsProperty);
}
private static void IncludeSpellingSuggestionsChanged(DependencyObject element, DependencyPropertyChangedEventArgs e)
{
var textBox = element as TextBoxBase;
if (textBox != null)
{
if ((bool)e.NewValue)
{
textBox.ContextMenuOpening += TextBoxOnContextMenuOpening;
textBox.ContextMenuClosing += TextBoxOnContextMenuClosing;
}
else
{
textBox.ContextMenuOpening -= TextBoxOnContextMenuOpening;
textBox.ContextMenuClosing -= TextBoxOnContextMenuClosing;
}
}
}
private static void TextBoxOnContextMenuOpening(object sender, ContextMenuEventArgs e)
{
var textBoxBase = sender as TextBoxBase;
ContextMenu contextMenu = textBoxBase?.ContextMenu;
if (contextMenu == null) return;
RemoveSpellingSuggestions(contextMenu);
if (!SpellCheck.GetIsEnabled(textBoxBase)) return;
SpellingError spellingError = GetSpellingError(textBoxBase);
if (spellingError != null)
{
Style spellingSuggestionStyle =
contextMenu.TryFindResource(Spelling.SuggestionMenuItemStyleKey) as Style;
int insertionIndex = 0;
bool hasSuggestion = false;
foreach (string suggestion in spellingError.Suggestions)
{
hasSuggestion = true;
var menuItem = new MenuItem
{
CommandTarget = textBoxBase,
Command = EditingCommands.CorrectSpellingError,
CommandParameter = suggestion,
Style = spellingSuggestionStyle,
Tag = typeof(Spelling)
};
contextMenu.Items.Insert(insertionIndex++, menuItem);
}
if (!hasSuggestion)
{
contextMenu.Items.Insert(insertionIndex++, new MenuItem
{
Style = contextMenu.TryFindResource(Spelling.NoSuggestionsMenuItemStyleKey) as Style,
Tag = typeof(Spelling)
});
}
contextMenu.Items.Insert(insertionIndex++, new Separator
{
Style = contextMenu.TryFindResource(Spelling.SeparatorStyleKey) as Style,
Tag = typeof(Spelling)
});
contextMenu.Items.Insert(insertionIndex++, new MenuItem
{
Command = EditingCommands.IgnoreSpellingError,
CommandTarget = textBoxBase,
Style = contextMenu.TryFindResource(Spelling.IgnoreAllMenuItemStyleKey) as Style,
Tag = typeof(Spelling)
});
contextMenu.Items.Insert(insertionIndex, new Separator
{
Style = contextMenu.TryFindResource(Spelling.SeparatorStyleKey) as Style,
Tag = typeof(Spelling)
});
}
}
private static SpellingError GetSpellingError(TextBoxBase textBoxBase)
{
var textBox = textBoxBase as TextBox;
if (textBox != null)
{
return textBox.GetSpellingError(textBox.CaretIndex);
}
var richTextBox = textBoxBase as RichTextBox;
if (richTextBox != null)
{
return richTextBox.GetSpellingError(richTextBox.CaretPosition);
}
return null;
}
private static void TextBoxOnContextMenuClosing(object sender, ContextMenuEventArgs e)
{
var contextMenu = (sender as TextBoxBase)?.ContextMenu;
if (contextMenu != null)
{
RemoveSpellingSuggestions(contextMenu);
}
}
private static void RemoveSpellingSuggestions(ContextMenu menu)
{
foreach (FrameworkElement item in (from item in menu.Items.OfType()
where ReferenceEquals(item.Tag, typeof(Spelling))
select item).ToList())
{
menu.Items.Remove(item);
}
}
#region Methods
///
/// Applies the text box view margin.
///
/// The text box.
/// The margin.
private static void ApplyTextBoxViewMargin(Control textBox, Thickness margin)
{
if (margin.Equals(new Thickness(double.NegativeInfinity)))
{
return;
}
var frameworkElement = (textBox.Template.FindName("PART_ContentHost", textBox) as ScrollViewer)?.Content as FrameworkElement;
if (frameworkElement != null)
{
frameworkElement.Margin = margin;
}
}
///
/// The text box view margin property changed callback.
///
/// The dependency object.
/// The dependency property changed event args.
private static void TextBoxViewMarginPropertyChangedCallback(
DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var box = dependencyObject as Control; //could be a text box or password box
if (box == null)
{
return;
}
if (box.IsLoaded)
{
ApplyTextBoxViewMargin(box, (Thickness)dependencyPropertyChangedEventArgs.NewValue);
}
box.Loaded += (sender, args) =>
{
var textBox = (Control)sender;
ApplyTextBoxViewMargin(textBox, GetTextBoxViewMargin(textBox));
};
}
#endregion
}
}