Text Validation and Combobox Display

Hi,

I have two issues that I was hoping you can help with. The two issues are:

  1. GoText Validation
  2. GoText configured as a Combobox

Regarding issue 1, GoText Validation, I was wondering if/when the DoEdit method will return True/False so that text validation can continue or terminate, as appropriate The link below gives more background on the subject:
http://www.nwoods.com/forum/forum_posts.asp?TID=930&KW=doedit

Like the previous poster, I am currently faced with validating text in a GoText field. Users are complaining that if the validation fails, the text field returns to it’s old text value and they have to retype the entire string, even though they may have only mis-typed one character. I’d like the editing session to continue until validation is successful.

Regarding issue 2, GoText configured as a Combobox, I’d like to configure a GoText as a combobox but without the down-arrow decoration on the right hand side of the field. The field should appear to the user as a regular text field, until the user clicks in the field, and then a drop down list of available/valid choices appear. I’ve tried overriding the CreateEditor method but couldn’t achieve the result I wanted. My previous post (and your replies) on this subject is here:
http://www.nwoods.com/forum/forum_posts.asp?TID=2404&KW=createeditor

In your reply, you suggested overriding DoBeginEdit, but I wasn’t able to get that to work. I was able to create my own windows.forms.combobox control and display that, but it didn’t have a consistent look and feel with the other controls in the GoView. I would prefer just to customize the combobox control already provided by GoText if that’s possible.

Your thoughts or suggestions on both issues would be greatly appreciated.

Thank you.

R. Houston

We didn’t want to make unnecessary incompatible changes before, but now that we’re coming out with version 3, maybe we should have made some changes here. We’ll have to consider this more carefully, since it’s pretty complex, as you may have already discovered.

Regarding your second issue, you could try something like:

[code] [Serializable]
public class LimitedNodeLabel : GoText {
public LimitedNodeLabel() {
this.EditorStyle = GoTextEditorStyle.ComboBox;
this.Choices = new System.Collections.ArrayList();
this.Choices.Add(“first”);
this.Choices.Add(“second”);
this.Choices.Add(“third”);
this.Choices.Add(“fourth”);
this.Choices.Add(“fifth”);
this.DropDownList = true;
}

//public override void DoBeginEdit(GoView view) {
//  base.DoBeginEdit(view);
//  if (this.Editor == null) return;  // failed to create editor
//  // get the Control for the Editor created in base method for this GoText
//  ComboBox ctrl = this.Editor.GetControl(view) as ComboBox;
//  if (ctrl != null) {
//    ctrl.DropDownStyle = ComboBoxStyle.Simple;  // causes re-creation of control, thus failure!!!
//    ctrl.AutoCompleteSource = AutoCompleteSource.ListItems;
//    ctrl.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
//    ctrl.MaxDropDownItems = 10;
//  }
//}

public override GoControl CreateEditor(GoView view) {
  if (this.EditorStyle == GoTextEditorStyle.ComboBox) {
    GoControl editor = new GoControl();
    editor.ControlType = typeof(ComboBoxControl);
    // fiddle with the size and position of the ComboBox
    RectangleF rect = this.Bounds;
    rect.X -= 4;
    rect.Y -= 2;
    rect.Width += 8;
    rect.Height += 4;
    editor.Bounds = rect;
    return editor;
  } else {
    return base.CreateEditor(view);
  }
}

// replacement for GoText.DoEdit, that returns a bool
public virtual bool DoEditEx(GoView view, string oldtext, string newtext) {
  String t = ComputeEdit(oldtext, newtext);
  bool found = t.IndexOf('e') >= 0;
  if (found) {
    view.DoCancelMouse();
    MessageBox.Show("found 'e'? " + found.ToString());
  }
  if (!found) this.Text = t;
  return !found;
}


// ComboBox subclass, for modal editing of ComboBox text
class ComboBoxControl : ComboBox, IGoControlObject {  // nested class
  public ComboBoxControl() { }

  [DllImport("uxtheme.dll")]
  public static extern int SetWindowTheme(IntPtr hWnd, String pszSubAppName, String pszSubIdList);

  protected override void OnHandleCreated(EventArgs e) {
    base.OnHandleCreated(e);
    if (System.Windows.Forms.VisualStyles.VisualStyleInformation.IsEnabledByUser) {
      SetWindowTheme(this.Handle, "", "");
    }
  }

  public GoControl GoControl {
    get { return myGoControl; }
    set {
      GoControl old = myGoControl;
      if (old != value) {
        myGoControl = value;
        if (value != null) {
          GoText gotext = value.EditedObject as GoText;
          if (gotext != null) {
            Font objfont = gotext.Font;
            float fsize = objfont.Size;
            if (this.GoView != null)
              fsize *= this.GoView.DocScale;
            this.Font = new Font(objfont.Name, fsize, objfont.Style);

            foreach (Object x in gotext.Choices) {
              this.Items.Add(x);
            }

            if (!gotext.Multiline) {
              int newline = gotext.Text.IndexOf("\r\n");
              if (newline >= 0)
                this.Text = gotext.Text.Substring(0, newline);
              else
                this.Text = gotext.Text;
            } else {
              this.Text = gotext.Text;
            }

            this.DropDownStyle = ComboBoxStyle.Simple;
            this.AutoCompleteSource = AutoCompleteSource.ListItems;
            this.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
            this.MaxDropDownItems = 10;
          }
        }
      }
    }
  }

  public GoView GoView {
    get { return myGoView; }
    set { myGoView = value; }
  }

  protected override bool ProcessDialogKey(System.Windows.Forms.Keys key) {
    if (HandleKey(key))
      return true;
    else
      return base.ProcessDialogKey(key);
  }
  protected override void OnLeave(EventArgs evt) {
    AcceptText(true);
    base.OnLeave(evt);
  }

  private bool HandleKey(System.Windows.Forms.Keys key) {
    if (key == System.Windows.Forms.Keys.Escape) {
      GoControl ctrl = this.GoControl;
      if (ctrl != null)
        ctrl.DoEndEdit(this.GoView);
      this.GoView.RequestFocus();
      return true;
    } else if (key == System.Windows.Forms.Keys.Enter || key == System.Windows.Forms.Keys.Tab) {
      if (AcceptText(false)) this.GoView.RequestFocus();
      return true;
    } else {
      return false;
    }
  }

  private bool AcceptText(bool force) {
    GoControl ctrl = this.GoControl;
    if (ctrl != null) {
      LimitedNodeLabel gotext = ctrl.EditedObject as LimitedNodeLabel;
      if (gotext == null || gotext.DoEditEx(this.GoView, gotext.Text, this.Text) || force) {
        ctrl.DoEndEdit(this.GoView);
        return true;
      }
    }
    return false;
  }

  // ComboBoxControl state
  private GoControl myGoControl;
  private GoView myGoView;
}  // end ComboBoxControl

}[/code]

However, I notice that the HandleKey method is not being called, so Escape and Return aren’t being handled in the way I would expect. You’ll need to figure this out, since I believe that’s just an issue with the ComboBox control that has nothing to do with GoDiagram.

This code also defines a replacement for DoEdit, called DoEditEx, that does return a bool, true meaning to accept the edit and finish editing.

You could also implement your own TextBoxControl in a similar manner.

I think it works fine when the user types Return or Tab to try to enter a new value – the DoEdit[Ex] method notices a validation error, brings up a MessageBox after calling GoView.DoCancelMouse(), and returns false. Or if there’s no validation error, it just sets the GoText.Text and returns true.

(It also works fine typing Escape to cancel the editing, even if there would have been a validation error in the text at the time of Escaping.)

However, when the user clicks in the view or some other control, focus is lost and it’s too late to try to stay in the TextBox or ComboBox. If there’s no validation error, it works the way it always has. But if there is a validation error, there can be MessageBox, but the editing will definitely end without having set GoText.Text. It will basically be an editing cancellation.

At this time I don’t know of a good way to do what you want when focus is lost due to a mouse event in another control, or any other call to Control.Focus. If you investigate this further, perhaps you can tell us how to resolve this focus problem.

Hi,



Sorry to resurrect an old post, but I had the same problem here. I tried different approaches and finally found a quite simple solution that fits my needs. Might be helpful to some (would have been for me at least).



What I ended up doing is overriding the GoText.DoEdit() to call BeginInvoke with a delegate function which restarts an Edit cycle.



Something like this:

[quote]

private delegate void BeginEditDelegate(GoText ctl, GoView view);



public override bool DoEdit(GoView view, string oldtext, string newtext)

{

if (validationFct(newtext) == false)

{

view.DoCancelMouse();

view.BeginInvoke(new BeginEditDelegate(callBeginEditDelegate), this, view);

}



return base.DoEdit(view, oldtext, newtext);

}



private void callBeginEditDelegate(GoText ctl, GoView view)

{

ctl.DoBeginEdit(view);

}

[/quote]



Not usable as such of course, needs polishing, it’s just to show the basic idea. Note that it’s not ideal since it does not prevent the loss of focus, it merely brings back the edition mode, so some external code is needed to keep the previous value between editions. It’s almost invisible to the user.



Hope it helps.



B.