Search code examples
c#.netwinformstextboxspell-checking

Trying to use the C# SpellCheck class


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


Solution

  • 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