using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Controls.Primitives;
namespace WpfHelpers.Behaviors
{
///
/// A behavior to provide excel cell like functionality to TextBox
///
public static class ExcelCellBehavior
{
#region Fields
private static Brush _selectionBrush;
private static Brush _caretBrush;
#endregion
#region Active Dependency Property
///
/// Gets the active.
///
/// The @object.
[AttachedPropertyBrowsableForChildrenAttribute(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static bool GetActive(DependencyObject @object)
{
return (bool)@object.GetValue(ActiveProperty);
}
public static void SetActive(DependencyObject @object, bool value)
{
@object.SetValue(ActiveProperty, value);
}
public static readonly DependencyProperty ActiveProperty = DependencyProperty.RegisterAttached(
"Active", typeof(bool), typeof(ExcelCellBehavior), new PropertyMetadata(false, ActivePropertyChanged));
private static void ActivePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBox textBox = d as TextBox;
if (textBox != null)
{
// Save the initial state of textbox
_caretBrush = textBox.CaretBrush;
_selectionBrush = textBox.SelectionBrush;
if ((e.NewValue as bool?).GetValueOrDefault(false))
{
textBox.PreviewKeyDown += OnPreviewKeyDown;
textBox.PreviewMouseLeftButtonDown += OnMouseLeftButtonDown;
textBox.PreviewMouseDoubleClick += OnMouseDoubleClick;
textBox.GotFocus += HandleGotFocus;
}
else
{
textBox.PreviewKeyDown -= OnPreviewKeyDown;
textBox.PreviewMouseLeftButtonDown -= OnMouseLeftButtonDown;
textBox.PreviewMouseDoubleClick -= OnMouseDoubleClick;
textBox.GotFocus -= HandleGotFocus;
}
}
}
#endregion
#region EventHandlers
private static void OnPreviewKeyDown(object sender, KeyEventArgs e)
{
// No need to start editing if any modifier key(ctrl, Alt, Shift) Or
// navigation keys(Up/Down) is pressed Or it is a repeated key down event notification
if (e.KeyboardDevice.Modifiers != ModifierKeys.None || e.Key == Key.Down || e.Key == Key.Up || e.IsRepeat)
{
return;
}
TextBox textBox = sender as TextBox;
if (textBox != null)
{
if (e.Key == Key.Enter && IsTextBoxInExcelMode(textBox))
{
// No need to change the mode if Enter key is pressed while excel mode is active.
return;
}
if (e.Key == Key.Escape)
{
// change the state to initial editing state
SetSelectedState(textBox);
}
else
{
SetDefaultState(textBox);
}
}
}
private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox != null && textBox.IsKeyboardFocusWithin == false)
{
textBox.Focus();
SetSelectedState(textBox);
e.Handled = true;
}
else if (IsTextBoxInExcelMode(textBox))
{
// If textbox is in excel mode and left mouse button is pressed then nothing should happen
e.Handled = true;
}
}
private static void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox != null)
{
SetDefaultState(textBox);
textBox.Focus();
textBox.SelectAll();
e.Handled = true;
}
}
private static void HandleGotFocus(object sender, RoutedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox != null)
{
textBox.Focus();
SetSelectedState(textBox);
e.Handled = true;
}
}
#endregion
#region Methods
///
/// Set the default state to a TextBox.
///
/// The text box.
private static void SetDefaultState(TextBox textBox)
{
textBox.SelectionBrush = _selectionBrush;
textBox.CaretBrush = _caretBrush;
}
///
/// Set the selected state to a TextBox.
///
/// The text box.
private static void SetSelectedState(TextBox textBox)
{
textBox.CaretBrush = Brushes.Transparent;
textBox.SelectionBrush = Brushes.Transparent;
textBox.SelectAll();
}
///
/// Determines whether the specified text box is in excel mode or not .
///
/// The text box.
/// true if [the specified text box] [is in excel mode] ; otherwise, false.
public static bool IsTextBoxInExcelMode(TextBoxBase textBox)
{
return (textBox.CaretBrush == Brushes.Transparent && textBox.SelectionBrush == Brushes.Transparent);
}
#endregion
}
}