I have got spell checking issues with the custom dictionary in a Wpf application in that it does not recognize I∆n.
If I add a behavior to try and deal with I∆n, DoSpellCheck() works when you type or paste text into the Textbox but does not work when textBox_Loaded(object sender, RoutedEventArgs e) is called.
Any help would appreciated.
public class TextBoxExtendedSpellCheckBehavior : Behavior
{
private static Key[] _nonInputKeys = new Key[] { Key.Left, Key.Up, Key.Right, Key.Down, Key.Tab, Key.Delete, Key.Back, Key.Escape, Key.Enter };
protected override void OnAttached()
{
if (AssociatedObject is TextBox)
{
TextBox textBox = AssociatedObject as TextBox;
textBox.PreviewKeyUp += OnTextBox_PreviewKeyUp;
textBox.LostFocus += OnTextBox_LostFocus;
textBox.TextChanged += OnTextChanged;
textBox.Loaded += textBox_Loaded;
}
base.OnAttached();
}
void textBox_Loaded(object sender, RoutedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox != null)
{
DoSpellCheck(textBox);
}
}
protected override void OnDetaching()
{
if (AssociatedObject is TextBox)
{
TextBox textBox = AssociatedObject as TextBox;
textBox.PreviewKeyUp -= OnTextBox_PreviewKeyUp;
textBox.LostFocus -= OnTextBox_LostFocus;
textBox.Loaded -= textBox_Loaded;
}
base.OnDetaching();
}
private static void OnTextChanged(object sender, TextChangedEventArgs e)
{
if (sender is TextBox)
{
TextBox textBox = sender as TextBox;
if (textBox != null && textBox.IsLoaded == true)
{
DoSpellCheck(textBox);
}
}
}
private bool IsInputKey(Key key)
{
return !_nonInputKeys.Contains(key);
}
private void OnTextBox_PreviewKeyUp(object sender, KeyEventArgs e)
{
if (sender is TextBox && IsInputKey(e.Key))
{
TextBox textBox = sender as TextBox;
DoSpellCheck(textBox);
}
}
private void OnTextBox_LostFocus(object sender, RoutedEventArgs e)
{
if (sender is TextBox)
{
TextBox textBox = sender as TextBox;
DoSpellCheck(textBox);
}
}
public static void DoSpellCheck(TextBox textBox)
{
const string iDelta = "I∆n";
int index = textBox.Text.IndexOf(iDelta);
if (index > 0)
{
int iStart = textBox.GetSpellingErrorStart(index);
if (iStart > -1)
{
SpellingError spellingError = textBox.GetSpellingError(iStart);
if (spellingError != null)
{
spellingError.IgnoreAll();
}
}
}
}
}
Related
I would like to operate a project planned for windows phone to be used in WPF.
Here is the link :
Loading Data when the User Scrolls to the End
By repeating the code , I perceived, that WPF does not know DependencyPropertyListener() in this method :
static void element_Loaded(object sender, RoutedEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
element.Loaded -= element_Loaded;
ScrollViewer scrollViewer = FindChildOfType<ScrollViewer>(element);
if (scrollViewer == null)
{
throw new InvalidOperationException("ScrollViewer not found.");
}
var listener = new DependencyPropertyListener();
listener.Changed
+= delegate
{
bool atBottom = scrollViewer.VerticalOffset
>= scrollViewer.ScrollableHeight;
if (atBottom)
{
var atEnd = GetAtEndCommand(element);
if (atEnd != null)
{
atEnd.Execute(null);
}
}
};
Binding binding = new Binding("VerticalOffset") { Source = scrollViewer };
listener.Attach(scrollViewer, binding);
}
Would there be a way around this object ?
You can listen to dependency property value change using a DependencyPropertyDescriptor.
static void element_Loaded(object sender, RoutedEventArgs e)
{
FrameworkElement element = (FrameworkElement)sender;
element.Loaded -= element_Loaded;
ScrollViewer scrollViewer = FindChildOfType<ScrollViewer>(element);
if (scrollViewer == null)
{
throw new InvalidOperationException("ScrollViewer not found.");
}
var dpd = DependencyPropertyDescriptor.FromProperty(ScrollViewer.VerticalOffsetProperty, typeof(ScrollViewer));
dpd.AddValueChanged(scrollViewer, delegate(object o, EventArgs args)
{
bool atBottom = scrollViewer.VerticalOffset
>= scrollViewer.ScrollableHeight;
if (atBottom)
{
var atEnd = GetAtEndCommand(element);
if (atEnd != null)
{
atEnd.Execute(null);
}
}
});
}
public class TextBoxSelectionBehavior : Behavior<TextBox>
{
public static bool GetSelectAllTextOnFocus(TextBox textBox)
{
return (bool)textBox.GetValue(SelectAllTextOnFocusProperty);
}
public static void SetSelectAllTextOnFocus(TextBox textBox, bool value)
{
textBox.SetValue(SelectAllTextOnFocusProperty, value);
}
public static readonly DependencyProperty SelectAllTextOnFocusProperty =
DependencyProperty.RegisterAttached(
"SelectAllTextOnFocus",
typeof(bool),
typeof(TextBoxSelectionBehavior),
new UIPropertyMetadata(false, OnSelectAllTextOnFocusChanged));
private static void OnSelectAllTextOnFocusChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var textBox = d as TextBox;
if (textBox == null) return;
if (e.NewValue is bool == false) return;
if ((bool)e.NewValue)
{
textBox.GotFocus += SelectAll;
textBox.PreviewMouseDown += IgnoreMouseButton;
}
else
{
textBox.GotFocus -= SelectAll;
textBox.PreviewMouseDown -= IgnoreMouseButton;
}
}
private static void SelectAll(object sender, RoutedEventArgs e)
{
var textBox = e.OriginalSource as TextBox;
if (textBox == null) return;
textBox.SelectAll();
textBox.CaretIndex = textBox.Text.Length;
}
private static void IgnoreMouseButton(object sender,
System.Windows.Input.MouseButtonEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null || textBox.IsKeyboardFocusWithin) return;
textBox.Focus();
e.Handled = true;
}
The textbox in question is an editable cell.
Once the cell is double clicked, i want a selectall of the text as well as a caret blink at the end of the text, on getfocus.
The text is highlighted correctly.
But setting the caret at the end is deselecting the highlighted text.
i cant do both at once. how to accomplish this?
I have tried selection start,length and other approaches.nothing works.
I have a WPF UserControl with a certain dependency property DepProp.
I would like this property to be modified when I press Shift or Alt, and to return to the previous value when releasing the keys.
What I want is similar to a trigger, but I don't know if it's possible to set the condition to be something like "Shift key is pressed".
I know that it's possible to specify KeyBindings for the control, as far as I understood they can execute a command when a key is pressed, but don't restore the previous vlaue when the key is released.
Any idea on how to do this?
You could create an attached behavior that you can affix to some "scope" element (e.g., your UserControl) that will maintain an attached read-only property that gets inherited down the tree. Then you can simply add a Trigger on the attached property.
public sealed class AltShiftHotKeyBehavior : Behavior<FrameworkElement>
{
private const ModifierKeys AltShift = ModifierKeys.Alt | ModifierKeys.Shift;
private static readonly DependencyPropertyKey IsAltShiftPressedPropertyKey =
DependencyProperty.RegisterAttachedReadOnly(
"IsAltShiftPressed",
typeof(bool),
typeof(AltShiftHotKeyBehavior),
new FrameworkPropertyMetadata(
false,
FrameworkPropertyMetadataOptions.Inherits));
public static readonly DependencyProperty IsAltShiftPressedProperty =
IsAltShiftPressedPropertyKey.DependencyProperty;
public static bool GetIsAltShiftPressed(DependencyObject element)
{
return (bool)element.GetValue(IsAltShiftPressedProperty);
}
protected override void OnAttached()
{
base.OnAttached();
var element = this.AssociatedObject;
element.AddHandler(
FrameworkElement.LoadedEvent,
(RoutedEventHandler)OnLoaded,
handledEventsToo: true);
element.AddHandler(
FrameworkElement.UnloadedEvent,
(RoutedEventHandler)OnUnloaded,
handledEventsToo: true);
element.AddHandler(
UIElement.PreviewKeyDownEvent,
(KeyEventHandler)OnKey,
handledEventsToo: true);
element.AddHandler(
UIElement.PreviewKeyUpEvent,
(KeyEventHandler)OnKey,
handledEventsToo: true);
element.AddHandler(
UIElement.LostKeyboardFocusEvent,
(KeyboardFocusChangedEventHandler)OnLostKeyboardFocus,
handledEventsToo: true);
var window = element as Window;
if (window != null)
{
window.Activated += OnWindowActivated;
window.Deactivated += OnWindowDeactivated;
}
CheckToggledState();
}
protected override void OnDetaching()
{
ClearToggledState();
base.OnDetaching();
var element = this.AssociatedObject;
element.RemoveHandler(
FrameworkElement.LoadedEvent,
(RoutedEventHandler)OnLoaded);
element.RemoveHandler(
FrameworkElement.UnloadedEvent,
(RoutedEventHandler)OnUnloaded);
element.RemoveHandler(
UIElement.PreviewKeyDownEvent,
(KeyEventHandler)OnKey);
element.RemoveHandler(
UIElement.PreviewKeyUpEvent,
(KeyEventHandler)OnKey);
element.RemoveHandler(
UIElement.LostKeyboardFocusEvent,
(KeyboardFocusChangedEventHandler)OnLostKeyboardFocus);
var window = element as Window;
if (window != null)
{
window.Activated -= OnWindowActivated;
window.Deactivated -= OnWindowDeactivated;
}
}
private void CheckToggledState()
{
var element = this.AssociatedObject;
if (element.IsLoaded &&
element.IsKeyboardFocusWithin &&
Keyboard.PrimaryDevice.Modifiers == AltShift)
{
element.SetValue(IsAltShiftPressedPropertyKey, true);
}
else
{
element.ClearValue(IsAltShiftPressedPropertyKey);
}
}
private void ClearToggledState()
{
this.AssociatedObject.ClearValue(IsAltShiftPressedPropertyKey);
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
CheckToggledState();
}
private void OnUnloaded(object sender, RoutedEventArgs e)
{
ClearToggledState();
}
private void OnWindowActivated(object sender, EventArgs e)
{
CheckToggledState();
}
private void OnWindowDeactivated(object sender, EventArgs e)
{
ClearToggledState();
}
private void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
CheckToggledState();
}
private void OnKey(object sender, KeyEventArgs e)
{
CheckToggledState();
}
}
I have the following code:
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.RegisterAttached("ItemsSource", typeof (ObservableCollection<BaseViewModel>),
typeof (MultiSelectComboBoxUserControl),
new FrameworkPropertyMetadata(null, OnItemsSourceChanged));
public static ObservableCollection<BaseViewModel> GetItemsSource(DependencyObject obj)
{
return (ObservableCollection<BaseViewModel>) obj.GetValue(ItemsSourceProperty);
}
public static void SetItemsSource(DependencyObject obj, ObservableCollection<BaseViewModel> value)
{
obj.SetValue(ItemsSourceProperty, value);
}
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.OldValue != null)
{
var coll = (INotifyCollectionChanged) e.OldValue;
coll.CollectionChanged -= ItemsSource_CollectionChanged;
}
if (e.NewValue != null)
{
var coll = (ObservableCollection<BaseViewModel>) e.NewValue;
coll.CollectionChanged += ItemsSource_CollectionChanged;
}
}
private static void ItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
//Here I'd like to update my ObservableCollection - ItemsSource
}
How can I achieve this (updating ItemsSource)? I can't access it because it's a dependency property and event handler is a static method. Any tips very welcome.
The object that you receive as the sender parameter is the ObservableCollection. If you plan on changing the collection (such as adding or removing items) you may also need to detach the event handler before making changes.
private static void ItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
ObservableCollection collection = sender as ObservableCollection<BaseViewModel>;
if (collection != null)
{
collection.CollectionChanged -= ItemsSource_CollectionChanged;
//Update ObservableCollection
collection.CollectionChanged += ItemsSource_CollectionChanged;
}
}
I wouldn't change my ItemsSource instance at all. I would simply create my ObservableCollection instance and clear, add items when updating.
Ok, it simple!
Old code:
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgse)
{
if (e.OldValue != null)
{
var coll = (INotifyCollectionChanged) e.OldValue;
coll.CollectionChanged -= ItemsSource_CollectionChanged;
}
if (e.NewValue != null)
{
var coll = (ObservableCollection<BaseViewModel>) e.NewValue;
coll.CollectionChanged += ItemsSource_CollectionChanged;
}
}
New Code:
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgse)
{
(YouCustomControl) control = (YouCustomControl)d;
if (e.OldValue != null)
{
var coll = (INotifyCollectionChanged) e.OldValue;
coll.CollectionChanged -= control.ItemsSource_CollectionChanged;
}
if (e.NewValue != null)
{
var coll = (ObservableCollection<BaseViewModel>) e.NewValue;
coll.CollectionChanged += control.ItemsSource_CollectionChanged;
}
}
private void ItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
}
I have an attached property called "SelectAllOnFocus". Values of true/false.
public static class TextBoxProps
{
private static void MyTextBoxKeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
((TextBox)sender).Text = string.Empty;
}
}
public static void SetSelectAllOnFocus(DependencyObject dependencyObject, bool selectAllOnFocus)
{
if (!ReferenceEquals(null, dependencyObject))
{
dependencyObject.SetValue(SelectAllOnFocus, selectAllOnFocus);
}
}
public static bool GetSelectAllOnFocus(DependencyObject dependencyObject)
{
if (!ReferenceEquals(null, dependencyObject))
{
return (bool)dependencyObject.GetValue(SelectAllOnFocus);
}
else
{
return false;
}
}
private static void OnSelectAllOnFocus(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
bool selectAllOnFocus = (bool)e.NewValue == true;
var theTextBox = d as TextBox;
if (selectAllOnFocus && theTextBox != null)
{
theTextBox.PreviewMouseDown -= MyTextBoxMouseEnter; theTextBox.PreviewMouseDown += MyTextBoxMouseEnter;
}
}
private static void MyTextBoxMouseEnter(object sender, MouseEventArgs e)
{
((TextBox)sender).SelectAll();
e.Handled = false;
}
public static readonly DependencyProperty SelectAllOnFocus
= DependencyProperty.RegisterAttached("SelectAllOnFocus", typeof(bool), typeof(TextBoxEscapeProperty),
new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnSelectAllOnFocus)));
}
What happens is the following:
The PreviewMouseDown event gets triggered.
The MyTextBoxMouseEnter method gets called.
The SelectAll() Method gets called.
When I do a "watch" on ((TextBox)sender).SelectedText, the value is correct (meaning whatever is in the textbox is showing up as selectedText).
The textbox itself is unchanged. No text is selected.
This is part of a general WPF style. All textboxes in the application should receive this property and it's associated behavior.
I'm stumped. Any ideas?
Thanks
What happens if you call ((TextBox)sender).UpdateLayout(); immediately after the SelectAll command? Or maybe you need to set the Keyboard focus to the text box.
It might be a better option to use something like this, which works if the text box is being selected with the mouse or the keyboard. (You'll need to modify it to check your "SelectAllOnFocus" property)
In your App.xaml.cs
protected override void OnStartup(StartupEventArgs e)
{
// Select the text in a TextBox when it receives focus.
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(SelectivelyIgnoreMouseButton));
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.GotKeyboardFocusEvent, new RoutedEventHandler(SelectAllText));
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.MouseDoubleClickEvent, new RoutedEventHandler(SelectAllText));
base.OnStartup(e);
}
void SelectivelyIgnoreMouseButton(object sender, MouseButtonEventArgs e)
{
// Find the TextBox
DependencyObject parent = e.OriginalSource as UIElement;
while (parent != null && !(parent is TextBox))
parent = VisualTreeHelper.GetParent(parent);
if (parent != null)
{
var textBox = (TextBox)parent;
if (!textBox.IsKeyboardFocusWithin)
{
// If the text box is not yet focused, give it the focus and
// stop further processing of this click event.
textBox.Focus();
e.Handled = true;
}
}
}
void SelectAllText(object sender, RoutedEventArgs e)
{
var textBox = e.OriginalSource as TextBox;
if (textBox != null)
textBox.SelectAll();
}