views:

124

answers:

3

I am trying to Refactor this code as it is repeated ad nauseum throughout my program.

My problem has to do with the fact that on any given page(tabpage,panel,uc,etc) there are controls at multiple levels to spellcheck.
i.e. -->

            foreach (Control control in tpgSystems.Controls)
            {
                if (control.GetType() == typeof(MemoExEdit))
                {
                    if (control.Text != String.Empty)
                    {
                        control.BackColor = Color.FromArgb(180, 215, 195);
                        control.Text = HUD.Spelling.CheckSpelling(control.Text);
                        control.ResetBackColor();
                    }
                }
            }
            foreach (Control control in grpCogestiveHeartFailure.Controls)
            {
                if (control.GetType() == typeof(MemoExEdit))
                {
                    if (control.Text != String.Empty)
                    {
                        control.BackColor = Color.FromArgb(180, 215, 195);
                        control.Text = HUD.Spelling.CheckSpelling(control.Text);
                        control.ResetBackColor();
                    }
                }
            }
            foreach (Control control in grpDiabetes.Controls)
            {
                if (control.GetType() == typeof(MemoExEdit))
                {
                    if (control.Text != String.Empty)
                    {
                        control.BackColor = Color.FromArgb(180, 215, 195);
                        control.Text = HUD.Spelling.CheckSpelling(control.Text);
                        control.ResetBackColor();
                    }
                }
            }

As you can see in the example, tpgSystems has some controls directly on it and then there are two Group Boxes that have controls in them as well.

Part of my goal in this was to only check controls that had a possibility of needing Spell Checking, as in Text Boxes and there relatives.

I know there is the control.HasChildren() that I can use but what is escaping me is how to use that and tell how deep to go. I would assume that two levels is the deepest I would ever go but that seems short sighted to hard code that in.

Ideally I would figure out how to pass a control to my CheckSpelling() and then have the logic in there to figure out how deep to go. Probably using Reflection.

For completeness here is CheckSpelling() which is in a seperate library I created.

public string CheckSpelling(string text)
    {
        Word.Application app = new Word.Application();
        object nullobj = Missing.Value;
        object template = Missing.Value;
        object newTemplate = Missing.Value;
        object documentType = Missing.Value;
        object visible = false;
        object optional = Missing.Value;
        object savechanges = false;
        app.ShowMe();

        Word._Document doc = app.Documents.Add(ref template, ref newTemplate, ref documentType, ref visible);

        doc.Words.First.InsertBefore(text);
        Word.ProofreadingErrors errors = doc.SpellingErrors;

        var ecount = errors.Count;
        doc.CheckSpelling(ref optional, ref optional, ref optional, ref optional, 
            ref optional, ref optional, ref optional, ref optional, ref optional, 
            ref optional, ref optional, ref optional);
        object first = 0;
        object last = doc.Characters.Count - 1;
        var results = doc.Range(ref first, ref last).Text;
        doc.Close(ref savechanges, ref nullobj, ref nullobj);
        app.Quit(ref savechanges, ref nullobj, ref nullobj);

        return results;
    }
+3  A: 

I'd take a slightly different approach. I'd create an interface, let's say ISpellCheckable which has a single method called SpellCheck.

Then, I'd extend the TextBox control to create a new SpellCheckedTextBox, which implements ISpellCheckable.

Then, replace the relevant TextBoxes on your page with a SpellCheckedTextBox (simple change).

Then you could simply write a single method that recursively descends through all controls on the page, checking whether or not they implement ISpellCheckable, and if so calling the SpellCheck method eg:

void WalkControls(Control root)
        {
            if (root == null ) return;
            foreach (Control control in root.Controls)
            {
                if (control is ISpellCheckable)
                {
                    if (((ISpellCheckable)control).SpellCheck())
                    {
                        // do stuff
                    }
                }
                WalkControls(control);
            }
        }
Winston Smith
Thank you for a different way to look at this. I am still fairly green and, as yet, have not implemented my own interface. Your example actually makes sense to me.
Refracted Paladin
+2  A: 

you can create a function that will 'SpellCheck' for a Control and each of its children recursivly...

public void SpellCheckControl(Control control, int depth)
{
    if(depth != 0)
    {
        if(Control.HasChildren())
        {
            foreach (Control ctrl in control.Controls)
            {
                SpellCheckControl(ctrl, depth - 1);
            }
        }
    }

    if (control.GetType() == typeof(MemoExEdit))
    {
        if (control.Text != String.Empty)
        {
            control.BackColor = Color.FromArgb(180, 215, 195);
            control.Text = HUD.Spelling.CheckSpelling(control.Text);
            control.ResetBackColor();
        }
    }
}

now, you can use this function like this:

SpellCheckControl(form1, 2); //form1 is your main form for example

will apply the SpellCheck to form1 children's children, form1 children & form1 (which of course is not a MemoExEdit, so will not be checked) .

SpellCheckControl(form1, -1); //form1 is your main form for example

and it will apply the SpellCheck to form1 children at any level as long as it can go deeper.

najmeddine
This will work as long as I never need to go more then two levels, correct? If I wrap the `foreach loop` in a `if(control.HasChildren())` then it would be more efficient???? No?
Refracted Paladin
this will work for any level you want, (in fact as long as there are 'children', this function will go one step down to check spell them and their children etc..). Adding if(control.HasChildren()) is better. I'll add also a depth level to tell the function to stop at.
najmeddine
A: 

You need to use recursion to check control hierarchies - the simplest thing to do is to check every single control under a given root control:

public void CheckSpellingRec(IEnumerable<Control> controls)
{
    foreach(var c in controls)
    {
     if(c is MemoExEdit && c.Text != String.Empty)
     {
      //check spelling
      control.BackColor = Color.FromArgb(180, 215, 195);
      control.Text = HUD.Spelling.CheckSpelling(control.Text);
      control.ResetBackColor();
     }

     //check spelling of child controls
     CheckSpellingRec(c.Controls.Cast<Control>());
    }
}

public void CheckSpelling(Control parent)
{
    CheckSpellingRec(new[] { parent });
}
Lee