Skip to content

Commit 24b5250

Browse files
committed
2 parents 77b21d9 + 7f7826a commit 24b5250

File tree

6 files changed

+176
-8
lines changed

6 files changed

+176
-8
lines changed

MainDemo.Wpf/TextFields.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
MinWidth="280"
9191
AcceptsReturn="True"
9292
VerticalScrollBarVisibility="Auto"
93+
SpellCheck.IsEnabled="True"
9394
materialDesign:HintAssist.Hint="Multiline text"
9495
Height="80">Multiline. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. The quick brown fox jumps over the lazy dog. War and peace. Keep going. Go on. For how long? Not long. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</TextBox>
9596
<materialDesign:PackIcon Grid.Row="2" Grid.Column="0" Kind="Phone" Foreground="{Binding ElementName=PhoneTextBox, Path=BorderBrush}" />

MaterialDesignThemes.Wpf/MaterialDesignThemes.Wpf.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@
329329
<Compile Include="SnackbarMessageEventArgs.cs" />
330330
<Compile Include="SnackbarMessageQueue.cs" />
331331
<Compile Include="SnackbarMessageQueueItem.cs" />
332+
<Compile Include="Spelling.cs" />
332333
<Compile Include="Transitions\CircleWipe.cs" />
333334
<Compile Include="IHintProxy.cs" />
334335
<Compile Include="Transitions\FadeWipe.cs" />

MaterialDesignThemes.Wpf/Spelling.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.Windows;
2+
3+
namespace MaterialDesignThemes.Wpf
4+
{
5+
public static class Spelling
6+
{
7+
public static ResourceKey SpellingSuggestionMenuItemStyleKey { get; } = new ComponentResourceKey(typeof(Spelling), ResourceKeyId.SpellingSuggestionMenuItemStyle);
8+
public static ResourceKey SpellingIgnoreAllMenuItemStyleKey { get; } = new ComponentResourceKey(typeof(Spelling), ResourceKeyId.SpellingIgnoreAllMenuItemStyle);
9+
public static ResourceKey SpellingNoSuggestionsMenuItemStyleKey { get; } = new ComponentResourceKey(typeof(Spelling), ResourceKeyId.SpellingNoSuggestionsMenuItemStyle);
10+
public static ResourceKey SpellingSeparatorStyleKey { get; } = new ComponentResourceKey(typeof(Spelling), ResourceKeyId.SpellingSeparatorStyle);
11+
}
12+
13+
internal enum ResourceKeyId
14+
{
15+
SpellingSuggestionMenuItemStyle,
16+
SpellingIgnoreAllMenuItemStyle,
17+
SpellingNoSuggestionsMenuItemStyle,
18+
SpellingSeparatorStyle,
19+
}
20+
}

MaterialDesignThemes.Wpf/TextFieldAssist.cs

Lines changed: 139 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
using System;
1+
using System.Linq;
22
using System.Windows;
33
using System.Windows.Controls;
44
using System.Windows.Controls.Primitives;
5-
using System.Windows.Media;
5+
using System.Windows.Documents;
66

77
namespace MaterialDesignThemes.Wpf
88
{
@@ -47,7 +47,7 @@ public static Thickness GetTextBoxViewMargin(DependencyObject element)
4747
/// Controls the visibility of the underline decoration.
4848
/// </summary>
4949
public static readonly DependencyProperty DecorationVisibilityProperty = DependencyProperty.RegisterAttached(
50-
"DecorationVisibility", typeof (Visibility), typeof (TextFieldAssist), new PropertyMetadata(default(Visibility)));
50+
"DecorationVisibility", typeof(Visibility), typeof(TextFieldAssist), new PropertyMetadata(default(Visibility)));
5151

5252
/// <summary>
5353
/// Controls the visibility of the underline decoration.
@@ -64,9 +64,140 @@ public static void SetDecorationVisibility(DependencyObject element, Visibility
6464
/// <returns></returns>
6565
public static Visibility GetDecorationVisibility(DependencyObject element)
6666
{
67-
return (Visibility) element.GetValue(DecorationVisibilityProperty);
67+
return (Visibility)element.GetValue(DecorationVisibilityProperty);
6868
}
69-
69+
70+
/// <summary>
71+
/// Automatially inserts spelling suggestions into the text box context menu.
72+
/// </summary>
73+
public static readonly DependencyProperty IncludeSpellingSuggestionsProperty = DependencyProperty.RegisterAttached(
74+
"IncludeSpellingSuggestions", typeof(bool), typeof(TextFieldAssist), new PropertyMetadata(default(bool), IncludeSpellingSuggestionsChanged));
75+
76+
public static void SetIncludeSpellingSuggestions(TextBoxBase element, bool value)
77+
{
78+
element.SetValue(IncludeSpellingSuggestionsProperty, value);
79+
}
80+
81+
public static bool GetIncludeSpellingSuggestions(TextBoxBase element)
82+
{
83+
return (bool)element.GetValue(IncludeSpellingSuggestionsProperty);
84+
}
85+
86+
private static void IncludeSpellingSuggestionsChanged(DependencyObject element, DependencyPropertyChangedEventArgs e)
87+
{
88+
var textBox = element as TextBoxBase;
89+
if (textBox != null)
90+
{
91+
if ((bool)e.NewValue)
92+
{
93+
textBox.ContextMenuOpening += TextBoxOnContextMenuOpening;
94+
textBox.ContextMenuClosing += TextBoxOnContextMenuClosing;
95+
}
96+
else
97+
{
98+
textBox.ContextMenuOpening -= TextBoxOnContextMenuOpening;
99+
textBox.ContextMenuClosing -= TextBoxOnContextMenuClosing;
100+
}
101+
}
102+
}
103+
104+
private static void TextBoxOnContextMenuOpening(object sender, ContextMenuEventArgs e)
105+
{
106+
var textBoxBase = sender as TextBoxBase;
107+
108+
ContextMenu contextMenu = textBoxBase?.ContextMenu;
109+
if (contextMenu == null) return;
110+
111+
RemoveSpellingSuggestions(contextMenu);
112+
113+
if (!SpellCheck.GetIsEnabled(textBoxBase)) return;
114+
115+
SpellingError spellingError = GetSpellingError(textBoxBase);
116+
if (spellingError != null)
117+
{
118+
Style spellingSuggestionStyle =
119+
contextMenu.TryFindResource(Spelling.SpellingSuggestionMenuItemStyleKey) as Style;
120+
121+
int insertionIndex = 0;
122+
bool hasSuggestion = false;
123+
foreach (string suggestion in spellingError.Suggestions)
124+
{
125+
hasSuggestion = true;
126+
var menuItem = new MenuItem
127+
{
128+
CommandTarget = textBoxBase,
129+
Command = EditingCommands.CorrectSpellingError,
130+
CommandParameter = suggestion,
131+
Style = spellingSuggestionStyle,
132+
Tag = typeof(Spelling)
133+
};
134+
contextMenu.Items.Insert(insertionIndex++, menuItem);
135+
}
136+
if (!hasSuggestion)
137+
{
138+
contextMenu.Items.Insert(insertionIndex++, new MenuItem
139+
{
140+
Style = contextMenu.TryFindResource(Spelling.SpellingNoSuggestionsMenuItemStyleKey) as Style,
141+
Tag = typeof(Spelling)
142+
});
143+
}
144+
145+
contextMenu.Items.Insert(insertionIndex++, new Separator
146+
{
147+
Style = contextMenu.TryFindResource(Spelling.SpellingSeparatorStyleKey) as Style,
148+
Tag = typeof(Spelling)
149+
});
150+
151+
contextMenu.Items.Insert(insertionIndex++, new MenuItem
152+
{
153+
Command = EditingCommands.IgnoreSpellingError,
154+
CommandTarget = textBoxBase,
155+
Style = contextMenu.TryFindResource(Spelling.SpellingIgnoreAllMenuItemStyleKey) as Style,
156+
Tag = typeof(Spelling)
157+
});
158+
159+
contextMenu.Items.Insert(insertionIndex, new Separator
160+
{
161+
Style = contextMenu.TryFindResource(Spelling.SpellingSeparatorStyleKey) as Style,
162+
Tag = typeof(Spelling)
163+
});
164+
}
165+
}
166+
167+
private static SpellingError GetSpellingError(TextBoxBase textBoxBase)
168+
{
169+
var textBox = textBoxBase as TextBox;
170+
if (textBox != null)
171+
{
172+
return textBox.GetSpellingError(textBox.CaretIndex);
173+
}
174+
var richTextBox = textBoxBase as RichTextBox;
175+
if (richTextBox != null)
176+
{
177+
return richTextBox.GetSpellingError(richTextBox.CaretPosition);
178+
}
179+
return null;
180+
}
181+
182+
private static void TextBoxOnContextMenuClosing(object sender, ContextMenuEventArgs e)
183+
{
184+
var contextMenu = (sender as TextBoxBase)?.ContextMenu;
185+
if (contextMenu != null)
186+
{
187+
RemoveSpellingSuggestions(contextMenu);
188+
}
189+
}
190+
191+
private static void RemoveSpellingSuggestions(ContextMenu menu)
192+
{
193+
foreach (FrameworkElement item in (from item in menu.Items.OfType<FrameworkElement>()
194+
where ReferenceEquals(item.Tag, typeof(Spelling))
195+
select item).ToList())
196+
{
197+
menu.Items.Remove(item);
198+
}
199+
}
200+
70201
#region Methods
71202

72203
/// <summary>
@@ -84,7 +215,7 @@ private static void ApplyTextBoxViewMargin(Control textBox, Thickness margin)
84215
var frameworkElement = (textBox.Template.FindName("PART_ContentHost", textBox) as ScrollViewer)?.Content as FrameworkElement;
85216
if (frameworkElement != null)
86217
{
87-
frameworkElement.Margin = margin;
218+
frameworkElement.Margin = margin;
88219
}
89220
}
90221

@@ -105,12 +236,12 @@ private static void TextBoxViewMarginPropertyChangedCallback(
105236

106237
if (box.IsLoaded)
107238
{
108-
ApplyTextBoxViewMargin(box, (Thickness) dependencyPropertyChangedEventArgs.NewValue);
239+
ApplyTextBoxViewMargin(box, (Thickness)dependencyPropertyChangedEventArgs.NewValue);
109240
}
110241

111242
box.Loaded += (sender, args) =>
112243
{
113-
var textBox = (Control) sender;
244+
var textBox = (Control)sender;
114245
ApplyTextBoxViewMargin(textBox, GetTextBoxViewMargin(textBox));
115246
};
116247
}

MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.Menu.xaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,4 +274,18 @@
274274
</Setter.Value>
275275
</Setter>
276276
</Style>
277+
278+
<Style x:Key="{x:Static wpf:Spelling.SpellingSuggestionMenuItemStyleKey}" TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
279+
<Setter Property="FontWeight" Value="Bold" />
280+
<Setter Property="Header" Value="{Binding RelativeSource={RelativeSource Self}, Path=CommandParameter}" />
281+
</Style>
282+
283+
<Style x:Key="{x:Static wpf:Spelling.SpellingIgnoreAllMenuItemStyleKey}" TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
284+
<Setter Property="Header" Value="Ignore All" />
285+
</Style>
286+
287+
<Style x:Key="{x:Static wpf:Spelling.SpellingNoSuggestionsMenuItemStyleKey}" TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
288+
<Setter Property="Header" Value="(no spelling suggestions)" />
289+
<Setter Property="IsEnabled" Value="False" />
290+
</Style>
277291
</ResourceDictionary>

MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.TextBox.xaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
2525
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
2626
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource MaterialDesignValidationErrorTemplate}"/>
27+
<Setter Property="wpf:TextFieldAssist.IncludeSpellingSuggestions" Value="{Binding RelativeSource={RelativeSource Self}, Path=(SpellCheck.IsEnabled)}" />
2728
<!-- cludge the default context menu -->
2829
<Setter Property="ContextMenu">
2930
<Setter.Value>

0 commit comments

Comments
 (0)