Trying to use the C# SpellCheck class

20,976

You have to use a WPF TextBox to make spell checking work. You can embed one in a Windows Forms form with the ElementHost control. It works pretty similar to a UserControl. Here's a control that you can drop straight from the toolbox. To get started, you need Project + Add Reference and select WindowsFormsIntegration, System.Design and the WPF assemblies PresentationCore, PresentationFramework and WindowsBase.

Add a new class to your project and paste the code shown below. Compile. Drop the SpellBox control from the top of the toolbox onto a form. It supports the TextChanged event and the Multiline and WordWrap properties. There's a nagging problem with the Font, there is no easy way to map a WF Font to the WPF font properties. The easiest workaround for that is to set the form's Font to "Segoe UI", the default for WPF.

using System;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms.Integration;
using System.Windows.Forms.Design;

[Designer(typeof(ControlDesigner))]
//[DesignerSerializer("System.Windows.Forms.Design.ControlCodeDomSerializer, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.ComponentModel.Design.Serialization.CodeDomSerializer, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
class SpellBox : ElementHost {
    public SpellBox() {
        box = new TextBox();
        base.Child = box;
        box.TextChanged += (s, e) => OnTextChanged(EventArgs.Empty);
        box.SpellCheck.IsEnabled = true;
        box.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
        this.Size = new System.Drawing.Size(100, 20);
    }
    public override string Text {
        get { return box.Text; }
        set { box.Text = value; }
    }
    [DefaultValue(false)]
    public bool Multiline {
        get { return box.AcceptsReturn; }
        set { box.AcceptsReturn = value; }
    }
    [DefaultValue(false)]
    public bool WordWrap {
        get { return box.TextWrapping != TextWrapping.NoWrap; }
        set { box.TextWrapping = value ? TextWrapping.Wrap : TextWrapping.NoWrap; }
    }
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public new System.Windows.UIElement Child {
        get { return base.Child; }
        set { /* Do nothing to solve a problem with the serializer !! */ }
    }
    private TextBox box;
}

By popular demand, a VB.NET version of this code that avoids the lambda:

Imports System
Imports System.ComponentModel
Imports System.ComponentModel.Design.Serialization
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Forms.Integration
Imports System.Windows.Forms.Design

<Designer(GetType(ControlDesigner))> _
Class SpellBox
    Inherits ElementHost

    Public Sub New()
        box = New TextBox()
        MyBase.Child = box
        AddHandler box.TextChanged, AddressOf box_TextChanged
        box.SpellCheck.IsEnabled = True
        box.VerticalScrollBarVisibility = ScrollBarVisibility.Auto
        Me.Size = New System.Drawing.Size(100, 20)
    End Sub

    Private Sub box_TextChanged(ByVal sender As Object, ByVal e As EventArgs)
        OnTextChanged(EventArgs.Empty)
    End Sub

    Public Overrides Property Text() As String
        Get
            Return box.Text
        End Get
        Set(ByVal value As String)
            box.Text = value
        End Set
    End Property

    <DefaultValue(False)> _
    Public Property MultiLine() As Boolean
        Get
            Return box.AcceptsReturn
        End Get
        Set(ByVal value As Boolean)
            box.AcceptsReturn = value
        End Set
    End Property

    <DefaultValue(False)> _
    Public Property WordWrap() As Boolean
        Get
            Return box.TextWrapping <> TextWrapping.NoWrap
        End Get
        Set(ByVal value As Boolean)
            If value Then
                box.TextWrapping = TextWrapping.Wrap
            Else
                box.TextWrapping = TextWrapping.NoWrap
            End If
        End Set
    End Property

    <DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
    Public Shadows Property Child() As System.Windows.UIElement
        Get
            Return MyBase.Child
        End Get
        Set(ByVal value As System.Windows.UIElement)
            '' Do nothing to solve a problem with the serializer !!
        End Set
    End Property
    Private box As TextBox
End Class
Share:
20,976

Related videos on Youtube

Assaf
Author by

Assaf

Software Engineer

Updated on July 09, 2022

Comments

  • Assaf
    Assaf almost 2 years

    I am trying to use the SpellCheck class C# provides (in PresentationFramework.dll). But, I am experiencing problems when trying to bind the spelling to my textbox:

    SpellCheck.SetIsEnabled(txtWhatever, true);
    

    The problem is that my txtWhatever is of type System.Windows.Forms and the parameter this function is looking for is System.Windows.Controls, and simple converting failed. I also tried to make my TextBox of this type, but... couldn't. Does anyone know how to use this SpellCheck object? (MSDN wasn't that helpful...)

    Thanks

  • Assaf
    Assaf over 13 years
    Yes, i tried. System.Windows.Forms doesn't have this property probably. This is exactly my problem...
  • Assaf
    Assaf over 13 years
    I'm trying to implement your solution: What is the (s,e) part of the code means? Because I am getting a compiler error for it?
  • user1703401
    user1703401 over 13 years
    It is a lambda expression, VS2008 required. Just delete it and let intellisense add a regular method instead.
  • user1703401
    user1703401 over 13 years
    Erm, come to think of it, you have to have VS2008 if you use WPF?
  • Assaf
    Assaf over 13 years
    I'm using VS2005 and the WPF thing works - it is just not yet called WPF... and thanks for the help - the intellisense did its job.
  • Crag
    Crag over 13 years
    Thanks for posting this code. I converted it to VB.Net and it is working almost perfectly (still can't get the lambda/text changed event line to work at all, but I'm going to keep at it and get it eventually!).
  • Tuxmentat
    Tuxmentat almost 13 years
    Thank you for posting this sir, you have doubtlessly saved me many hours. :)
  • MDL
    MDL about 12 years
    Thank You! I'm voting this up for sure, you saved me money and wasted hours. Great Post!
  • Austin Henley
    Austin Henley over 11 years
    This is more of a comment than an answer. Did you read the accepted answer?
  • Jack
    Jack about 9 years
    This isn't working for me and I have no idea why. The wrong word doesn't get underlined. At first the compiler claimed about an assembly reference not found but just adding System.Xaml referenced solved. But the spell still isn't working for me: prntscr.com/6rvwwk what am I missing? of course that textBox is your SpellBox.
  • Jack
    Jack about 9 years
    Ok, I got it working. :) I set the language explicitly: box.Language = System.Windows.Markup.XmlLanguage.GetLanguage("en-US");. You also need to have the .NET language pack installed (but I had already). I'm not sure but this issue is probably due the fact the English isn't my OS' language. It working: prntscr.com/6rw50x
  • TripVoltage
    TripVoltage almost 9 years
    @Hans great example many thanks. Just a quick question are we able to add custom words to the dictionary for the example you gave?
  • rrirower
    rrirower over 6 years
    @HansPassant - This is exactly what I need. However, I can't seem to figure out how to implement the TextChanged event. Do I code it in the SpellCheck class or my form?
  • rrirower
    rrirower over 6 years
    @HansPassant- Figured it out. I needed to dynamically add the events to my form. Thanks for your work.
  • OmarL
    OmarL over 5 years
    @Jack, did you ever figure out how that works exactly? en-GB doesn't work for me: it accepts "color" but marks "colour" as wrong. I'm expecting the opposite behaviour, which is what MS Word does on my system.
  • Jack
    Jack over 5 years
    @Wilson My experience with this wasn't good. I don't know the reason for this specific behavior, but from what I remember, it look up the words (the dictionary) from the files provided by the Windows/.NET framework but it support few languages. For example, installing the chinese pack language doesn't add Support for it. I think you're better off using some other implementation. I don't remember now the library I've used but I'm sure there are alot of good ones over internet. Pick one and anything ask here on SO.