我正在寻找一个WPF拼写检查控件(类似于内置功能,但支持更多字典)。我需要它具有你的类型功能(红色下划线)。它还应该支持超过4种语言而不是内置的.NET 4.0拼写检查(例如英语,西班牙语,德语,意大利语和俄语语言支持会很棒)。
我更喜欢控件具有可在商业Windows应用程序中使用的MIT或BSD许可证。源代码很棒,因为我想将拼写建议集成到我的自定义右键单击上下文菜单中。
答案 0 :(得分:1)
我通过添加自己的SpellCheckerBehavior将AvalonEdit与NHunspell合并。可以在github找到此示例项目。它实现如下:
<avalonEdit:TextEditor
xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"
Name="editor">
<avalonEdit:TextEditor.ContextMenu>
<ContextMenu>
<MenuItem Command="Undo" />
<MenuItem Command="Redo" />
<Separator/>
<MenuItem Command="Cut" />
<MenuItem Command="Copy" />
<MenuItem Command="Paste" />
</ContextMenu>
</avalonEdit:TextEditor.ContextMenu>
<i:Interaction.Behaviors>
<local:SpellCheckerBehavior />
</i:Interaction.Behaviors>
</avalonEdit:TextEditor>
...像这样修改我的MainWindow构造函数:
public MainWindow()
{
SpellChecker.Default.HunspellInstance = new Hunspell("German.aff", "German.dic");
editor.TextArea.TextView.LineTransformers.Add(new SpellCheckerColorizer());
}
...并将以下类添加到我的项目中以进行集成:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Rendering;
using NHunspell;
namespace Martin
{
public class SpellChecker
{
static Lazy<SpellChecker> defaultInstance = new Lazy<SpellChecker>(() => new SpellChecker());
public static SpellChecker Default { get { return defaultInstance.Value; } }
public Hunspell HunspellInstance { get; set; }
public class Word
{
public int Index { get; set; }
public string Value { get; set; }
}
static IEnumerable<Word> FindWords(string text)
{
foreach (Match m in new Regex(@"\w+").Matches(text))
{
yield return new Word() { Index = m.Index, Value = m.Value };
}
}
public IEnumerable<Word> FindSpellingErrors(string text)
{
foreach (var word in FindWords(text))
{
if (!Spell(word.Value))
{
yield return word;
}
}
}
public bool Spell(string word)
{
return HunspellInstance.Spell(word);
}
public List<string> Suggest(string word)
{
return HunspellInstance.Suggest(word);
}
}
public class SpellCheckerBehavior : Behavior<TextEditor>
{
TextEditor textEditor;
List<Control> originalItems;
protected override void OnAttached()
{
textEditor = AssociatedObject;
if (textEditor != null)
{
textEditor.ContextMenuOpening += new ContextMenuEventHandler(TextEditorContextMenuOpening);
textEditor.TextArea.MouseRightButtonDown += new System.Windows.Input.MouseButtonEventHandler(TextAreaMouseRightButtonDown);
originalItems = textEditor.ContextMenu.Items.OfType<Control>().ToList();
}
base.OnAttached();
}
protected override void OnDetaching()
{
if (textEditor != null)
{
textEditor.ContextMenuOpening -= new ContextMenuEventHandler(TextEditorContextMenuOpening);
textEditor.TextArea.MouseRightButtonDown -= new System.Windows.Input.MouseButtonEventHandler(TextAreaMouseRightButtonDown);
originalItems = null;
textEditor = null;
}
base.OnDetaching();
}
void TextAreaMouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var position = textEditor.GetPositionFromPoint(e.GetPosition(textEditor));
if (position.HasValue)
{
textEditor.TextArea.Caret.Position = position.Value;
}
}
void TextEditorContextMenuOpening(object sender, ContextMenuEventArgs e)
{
foreach (Control item in textEditor.ContextMenu.Items.OfType<Control>().ToList())
{
if (originalItems.Contains(item)) { continue; }
textEditor.ContextMenu.Items.Remove(item);
}
var position = textEditor.TextArea.Caret.Position;
Match word = null;
Regex r = new Regex(@"\w+");
var line = textEditor.Document.GetText(textEditor.Document.GetLineByNumber(position.Line));
foreach (Match m in r.Matches(line))
{
if (m.Index >= position.VisualColumn) { break; }
word = m;
}
if (null == word ||
position.Column > word.Index + word.Value.Length ||
SpellChecker.Default.Spell(word.Value))
{
return;
}
textEditor.ContextMenu.Items.Insert(0, new Separator());
var suggestions = SpellChecker.Default.Suggest(word.Value);
if (0 == suggestions.Count)
{
textEditor.ContextMenu.Items.Insert(0,
new MenuItem() { Header = "<No suggestions found>", IsEnabled = false });
return;
}
foreach (string suggestion in suggestions)
{
var item = new MenuItem { Header = suggestion, FontWeight = FontWeights.Bold };
item.Tag =
new Tuple<int, int>(
textEditor.Document.GetOffset(position.Line, word.Index + 1),
word.Value.Length);
item.Click += ItemClick;
textEditor.ContextMenu.Items.Insert(0, item);
}
}
private void ItemClick(object sender, RoutedEventArgs e)
{
var item = sender as MenuItem;
if (null == item) { return; }
var segment = item.Tag as Tuple<int, int>;
if (null == segment) { return; }
textEditor.Document.Replace(segment.Item1, segment.Item2, item.Header.ToString());
}
}
public class SpellCheckerColorizer : DocumentColorizingTransformer
{
private readonly TextDecorationCollection textDecorationCollection;
public SpellCheckerColorizer()
{
textDecorationCollection = new TextDecorationCollection();
textDecorationCollection.Add(new TextDecoration()
{
Pen = new Pen { Thickness = 1, DashStyle = DashStyles.Dot, Brush = new SolidColorBrush(Colors.Red) },
PenThicknessUnit = TextDecorationUnit.FontRecommended
});
}
protected override void ColorizeLine(DocumentLine line)
{
var lineText = CurrentContext.Document.Text
.Substring(line.Offset, line.Length);
foreach (var error in SpellChecker.Default.FindSpellingErrors(lineText))
{
base.ChangeLinePart(line.Offset + error.Index, line.Offset + error.Index + error.Value.Length,
(VisualLineElement element) => element.TextRunProperties.SetTextDecorations(textDecorationCollection));
}
}
}
}
答案 1 :(得分:0)
AvalonEdit(http://www.codeproject.com/KB/edit/AvalonEdit.aspx)是在WPF中为SharpDevelop从头开始编写的。哦,快速谷歌的奇迹。
如果您一次只使用一种语言(但可以切换),则可以使用默认的WPF功能(http://joshsmithonwpf.wordpress.com/2007/02/17/spellchecking-and-suggested-spellings-in-a-textbox/)