Skip to content

Commit 7974452

Browse files
committed
Adopt SpellCheck.IsEnabled changes from MaterialDesignInXamlToolkit @ButchersBoy #650
Removes the extra hidden classes and enables flexible style changes, it's more WPF now
1 parent c70f39e commit 7974452

File tree

4 files changed

+115
-59
lines changed

4 files changed

+115
-59
lines changed

src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/TextExamples.xaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
Margin="{StaticResource ColumnMargin}">
3535
<Label Content="TextBox" Style="{DynamicResource DescriptionHeaderStyle}" />
3636
<TextBox Margin="{StaticResource ControlMargin}"
37-
Controls:TextBoxHelper.IsSpellCheckContextMenuEnabled="True"
37+
SpellCheck.IsEnabled="True"
3838
Text="Enabled">
3939
<TextBox.ContextMenu>
4040
<ContextMenu>
@@ -44,10 +44,10 @@
4444
</TextBox>
4545
<TextBox Margin="{StaticResource ControlMargin}"
4646
Controls:TextBoxHelper.ClearTextButton="True"
47-
Controls:TextBoxHelper.IsSpellCheckContextMenuEnabled="True"
4847
Controls:TextBoxHelper.IsWaitingForData="True"
4948
Controls:TextBoxHelper.UseFloatingWatermark="True"
5049
Controls:TextBoxHelper.Watermark="Watermark"
50+
SpellCheck.IsEnabled="True"
5151
ToolTip="Default alignment">
5252
<TextBox.ContextMenu>
5353
<ContextMenu>
@@ -143,8 +143,8 @@
143143
<Label Content="RichTextBox" Style="{DynamicResource DescriptionHeaderStyle}" />
144144
<RichTextBox Margin="{StaticResource ControlMargin}"
145145
Padding="5"
146-
Controls:TextBoxHelper.IsSpellCheckContextMenuEnabled="True"
147-
IsDocumentEnabled="True">
146+
IsDocumentEnabled="True"
147+
SpellCheck.IsEnabled="True">
148148
<FlowDocument>
149149
<Paragraph>
150150
<Hyperlink NavigateUri="https://github.com/MahApps/MahApps.Metro">

src/MahApps.Metro/MahApps.Metro.Shared/Controls/Helper/TextBoxHelper.cs

Lines changed: 81 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,20 @@
1515

1616
namespace MahApps.Metro.Controls
1717
{
18-
public interface ISpellCheckMenuItem
18+
internal enum SpellingResourceKeyId
1919
{
20+
SuggestionMenuItemStyle,
21+
IgnoreAllMenuItemStyle,
22+
NoSuggestionsMenuItemStyle,
23+
SeparatorStyle,
2024
}
2125

22-
public class SpellCheckMenuItem : MenuItem, ISpellCheckMenuItem
23-
{
24-
public SpellCheckMenuItem()
25-
{
26-
this.SetResourceReference(FrameworkElement.StyleProperty, "MetroMenuItem");
27-
}
28-
}
29-
30-
public class SpellCheckSeparator : Separator, ISpellCheckMenuItem
26+
public static class Spelling
3127
{
28+
public static ResourceKey SuggestionMenuItemStyleKey { get; } = new ComponentResourceKey(typeof(Spelling), SpellingResourceKeyId.SuggestionMenuItemStyle);
29+
public static ResourceKey IgnoreAllMenuItemStyleKey { get; } = new ComponentResourceKey(typeof(Spelling), SpellingResourceKeyId.IgnoreAllMenuItemStyle);
30+
public static ResourceKey NoSuggestionsMenuItemStyleKey { get; } = new ComponentResourceKey(typeof(Spelling), SpellingResourceKeyId.NoSuggestionsMenuItemStyle);
31+
public static ResourceKey SeparatorStyleKey { get; } = new ComponentResourceKey(typeof(Spelling), SpellingResourceKeyId.SeparatorStyle);
3232
}
3333

3434
/// <summary>
@@ -69,7 +69,7 @@ public class TextBoxHelper
6969

7070
public static readonly DependencyProperty HasTextProperty = DependencyProperty.RegisterAttached("HasText", typeof (bool), typeof (TextBoxHelper), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsRender));
7171

72-
public static readonly DependencyProperty IsSpellCheckContextMenuEnabledProperty = DependencyProperty.RegisterAttached("IsSpellCheckContextMenuEnabled", typeof(bool), typeof(TextBoxHelper), new FrameworkPropertyMetadata(false, UseSpellCheckContextMenuChanged));
72+
public static readonly DependencyProperty IsSpellCheckContextMenuEnabledProperty = DependencyProperty.RegisterAttached("IsSpellCheckContextMenuEnabled", typeof(bool), typeof(TextBoxHelper), new FrameworkPropertyMetadata(default(bool), IsSpellCheckContextMenuEnabledChanged));
7373

7474
/// <summary>
7575
/// This property can be used to retrieve the watermark using the <see cref="DisplayAttribute"/> of bound property.
@@ -252,7 +252,7 @@ private static Type ResolveBinding(Type type, string[] paths)
252252
}
253253
#endif
254254

255-
private static void UseSpellCheckContextMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
255+
private static void IsSpellCheckContextMenuEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
256256
{
257257
var tb = d as TextBoxBase;
258258
if (null == tb)
@@ -262,16 +262,15 @@ private static void UseSpellCheckContextMenuChanged(DependencyObject d, Dependen
262262

263263
if (e.OldValue != e.NewValue)
264264
{
265+
tb.SetValue(SpellCheck.IsEnabledProperty, (bool)e.NewValue);
265266
if ((bool)e.NewValue)
266267
{
267-
tb.SetValue(SpellCheck.IsEnabledProperty, true);
268268
tb.ContextMenuOpening += TextBoxBaseContextMenuOpening;
269269
tb.LostFocus += TextBoxBaseLostFocus;
270270
tb.ContextMenuClosing += TextBoxBaseContextMenuClosing;
271271
}
272272
else
273273
{
274-
tb.SetValue(SpellCheck.IsEnabledProperty, false);
275274
tb.ContextMenuOpening -= TextBoxBaseContextMenuOpening;
276275
tb.LostFocus -= TextBoxBaseLostFocus;
277276
tb.ContextMenuClosing -= TextBoxBaseContextMenuClosing;
@@ -281,70 +280,99 @@ private static void UseSpellCheckContextMenuChanged(DependencyObject d, Dependen
281280

282281
private static void TextBoxBaseLostFocus(object sender, RoutedEventArgs e)
283282
{
284-
RemoveSpellCheckMenuItems((FrameworkElement)sender);
283+
RemoveSpellCheckMenuItems(((FrameworkElement)sender).ContextMenu);
285284
}
286285

287286
private static void TextBoxBaseContextMenuClosing(object sender, ContextMenuEventArgs e)
288287
{
289-
RemoveSpellCheckMenuItems((FrameworkElement)sender);
288+
RemoveSpellCheckMenuItems(((FrameworkElement)sender).ContextMenu);
290289
}
291290

292291
private static void TextBoxBaseContextMenuOpening(object sender, ContextMenuEventArgs e)
293292
{
294293
var tbBase = (TextBoxBase)sender;
295-
var textBox = tbBase as TextBox;
296-
var richTextBox = tbBase as RichTextBox;
294+
var contextMenu = tbBase.ContextMenu;
295+
if (contextMenu == null)
296+
{
297+
return;
298+
}
297299

298-
RemoveSpellCheckMenuItems((FrameworkElement)sender);
300+
RemoveSpellCheckMenuItems(contextMenu);
299301

300-
// the default item comes normally through the styles, so I think we don't need to do this
301-
/*if (tbBase.ContextMenu == null)
302+
if (!SpellCheck.GetIsEnabled(tbBase))
302303
{
303-
tbBase.ContextMenu = GetDefaultTextBoxBaseContextMenu();
304-
}*/
304+
return;
305+
}
305306

306307
var cmdIndex = 0;
308+
var textBox = tbBase as TextBox;
309+
var richTextBox = tbBase as RichTextBox;
307310
var spellingError = textBox != null
308311
? textBox.GetSpellingError(textBox.CaretIndex)
309312
: richTextBox?.GetSpellingError(richTextBox.CaretPosition);
310-
if (spellingError != null) {
313+
if (spellingError != null)
314+
{
315+
var spellingSuggestionStyle = contextMenu.TryFindResource(Spelling.SuggestionMenuItemStyleKey) as Style;
311316
var suggestions = spellingError.Suggestions.ToList();
312-
if (suggestions.Any()) {
313-
foreach (var suggestion in suggestions) {
314-
var mi = new SpellCheckMenuItem();
315-
mi.Header = suggestion;
316-
mi.FontWeight = FontWeights.Bold;
317-
mi.Command = EditingCommands.CorrectSpellingError;
318-
mi.CommandParameter = suggestion;
319-
mi.CommandTarget = tbBase;
320-
tbBase.ContextMenu.Items.Insert(cmdIndex, mi);
321-
cmdIndex++;
317+
if (suggestions.Any())
318+
{
319+
foreach (var suggestion in suggestions)
320+
{
321+
var mi = new MenuItem
322+
{
323+
Command = EditingCommands.CorrectSpellingError,
324+
CommandParameter = suggestion,
325+
CommandTarget = tbBase,
326+
Style = spellingSuggestionStyle,
327+
Tag = typeof(Spelling)
328+
};
329+
contextMenu.Items.Insert(cmdIndex++, mi);
322330
}
323-
// add a separator
324-
tbBase.ContextMenu.Items.Insert(cmdIndex, new SpellCheckSeparator());
325-
cmdIndex++;
326-
}
327-
var ignoreAllMI = new SpellCheckMenuItem();
328-
ignoreAllMI.Header = "Ignore All";
329-
ignoreAllMI.Command = EditingCommands.IgnoreSpellingError;
330-
ignoreAllMI.CommandTarget = tbBase;
331-
tbBase.ContextMenu.Items.Insert(cmdIndex, ignoreAllMI);
332-
cmdIndex++;
331+
}
332+
else
333+
{
334+
contextMenu.Items.Insert(cmdIndex++, new MenuItem
335+
{
336+
Style = contextMenu.TryFindResource(Spelling.NoSuggestionsMenuItemStyleKey) as Style,
337+
Tag = typeof(Spelling)
338+
});
339+
}
340+
341+
// add a separator
342+
contextMenu.Items.Insert(cmdIndex++, new Separator
343+
{
344+
Style = contextMenu.TryFindResource(Spelling.SeparatorStyleKey) as Style,
345+
Tag = typeof(Spelling)
346+
});
347+
348+
// ignore all
349+
var ignoreAllMI = new MenuItem
350+
{
351+
Command = EditingCommands.IgnoreSpellingError,
352+
CommandTarget = tbBase,
353+
Style = contextMenu.TryFindResource(Spelling.IgnoreAllMenuItemStyleKey) as Style,
354+
Tag = typeof(Spelling)
355+
};
356+
contextMenu.Items.Insert(cmdIndex++, ignoreAllMI);
357+
333358
// add another separator
334-
tbBase.ContextMenu.Items.Insert(cmdIndex, new SpellCheckSeparator());
359+
contextMenu.Items.Insert(cmdIndex, new Separator
360+
{
361+
Style = contextMenu.TryFindResource(Spelling.SeparatorStyleKey) as Style,
362+
Tag = typeof(Spelling)
363+
});
335364
}
336365
}
337366

338-
private static void RemoveSpellCheckMenuItems([CanBeNull] FrameworkElement tbBase)
367+
private static void RemoveSpellCheckMenuItems([CanBeNull] ContextMenu contextMenu)
339368
{
340-
if (tbBase?.ContextMenu == null)
369+
if (contextMenu != null)
341370
{
342-
return;
343-
}
344-
var spellCheckItems = tbBase.ContextMenu.Items.OfType<ISpellCheckMenuItem>().ToList();
345-
foreach (var item in spellCheckItems)
346-
{
347-
tbBase.ContextMenu.Items.Remove(item);
371+
var spellCheckItems = contextMenu.Items.OfType<FrameworkElement>().Where(item => ReferenceEquals(item.Tag, typeof(Spelling))).ToList();
372+
foreach (var item in spellCheckItems)
373+
{
374+
contextMenu.Items.Remove(item);
375+
}
348376
}
349377
}
350378

src/MahApps.Metro/MahApps.Metro/Styles/Controls.ContextMenu.xaml

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
1+
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:controls="clr-namespace:MahApps.Metro.Controls">
24

35
<MenuScrollingVisibilityConverter x:Key="MenuScrollingVisibilityConverter" />
46

@@ -14,7 +16,7 @@
1416
<Setter Property="Template">
1517
<Setter.Value>
1618
<ControlTemplate TargetType="{x:Type Separator}">
17-
<Grid Margin="0 6 0 4" SnapsToDevicePixels="true">
19+
<Grid Margin="0 6 0 4" SnapsToDevicePixels="True">
1820
<Rectangle Height="1"
1921
Margin="20 0 1 1"
2022
Fill="{DynamicResource GrayBrush7}" />
@@ -139,6 +141,30 @@
139141
</Style.Triggers>
140142
</Style>
141143

144+
<Style x:Key="{x:Static controls:Spelling.SuggestionMenuItemStyleKey}"
145+
BasedOn="{StaticResource MetroMenuItem}"
146+
TargetType="{x:Type MenuItem}">
147+
<Setter Property="FontWeight" Value="Bold" />
148+
<Setter Property="Header" Value="{Binding RelativeSource={RelativeSource Self}, Path=CommandParameter}" />
149+
</Style>
150+
151+
<Style x:Key="{x:Static controls:Spelling.IgnoreAllMenuItemStyleKey}"
152+
BasedOn="{StaticResource MetroMenuItem}"
153+
TargetType="{x:Type MenuItem}">
154+
<Setter Property="Header" Value="Ignore All" />
155+
</Style>
156+
157+
<Style x:Key="{x:Static controls:Spelling.NoSuggestionsMenuItemStyleKey}"
158+
BasedOn="{StaticResource MetroMenuItem}"
159+
TargetType="{x:Type MenuItem}">
160+
<Setter Property="Header" Value="(no spelling suggestions)" />
161+
<Setter Property="IsEnabled" Value="False" />
162+
</Style>
163+
164+
<Style x:Key="{x:Static controls:Spelling.SeparatorStyleKey}"
165+
BasedOn="{StaticResource {x:Static MenuItem.SeparatorStyleKey}}"
166+
TargetType="{x:Type Separator}" />
167+
142168
<ContextMenu x:Key="TextBoxMetroContextMenu" Style="{StaticResource MetroContextMenu}">
143169
<MenuItem Command="ApplicationCommands.Cut" Style="{DynamicResource MetroMenuItem}" />
144170
<MenuItem Command="ApplicationCommands.Copy" Style="{DynamicResource MetroMenuItem}" />

src/MahApps.Metro/MahApps.Metro/Styles/Controls.TextBox.xaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<Setter Property="Controls:TextBoxHelper.ButtonFontSize" Value="{DynamicResource ClearTextButtonFontSize}" />
2323
<Setter Property="Controls:TextBoxHelper.ButtonWidth" Value="22" />
2424
<Setter Property="Controls:TextBoxHelper.IsMonitoring" Value="True" />
25+
<Setter Property="Controls:TextBoxHelper.IsSpellCheckContextMenuEnabled" Value="{Binding RelativeSource={RelativeSource Self}, Path=(SpellCheck.IsEnabled)}" />
2526
<Setter Property="FontFamily" Value="{DynamicResource ContentFontFamily}" />
2627
<Setter Property="FontSize" Value="{DynamicResource ContentFontSize}" />
2728
<Setter Property="Foreground" Value="{DynamicResource TextBrush}" />
@@ -503,6 +504,7 @@
503504
<Setter Property="ContextMenu" Value="{DynamicResource TextBoxMetroContextMenu}" />
504505
<Setter Property="Controls:ControlsHelper.FocusBorderBrush" Value="{DynamicResource TextBoxFocusBorderBrush}" />
505506
<Setter Property="Controls:ControlsHelper.MouseOverBorderBrush" Value="{DynamicResource TextBoxMouseOverBorderBrush}" />
507+
<Setter Property="Controls:TextBoxHelper.IsSpellCheckContextMenuEnabled" Value="{Binding RelativeSource={RelativeSource Self}, Path=(SpellCheck.IsEnabled)}" />
506508
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
507509
<Setter Property="FontFamily" Value="{DynamicResource ContentFontFamily}" />
508510
<Setter Property="FontSize" Value="{DynamicResource ContentFontSize}" />

0 commit comments

Comments
 (0)