GoText label can only be modified 1 time

Hello,

I have a weird problems and this problems is only reproducible when i create my GoView in a WindowPane of a VSPackage, my GoText can only edited once in the WindowPane (vs the GoText can always be edited in a normal window Form). All i want is the default behavior at all time when user click on the GoText part of my Gogroup derived object.
the GoDiagram code:
In the class derived from WindowPane:
private GoView _editorView;
public GoView EditorView
{
get
{
return _editorView;
}
set
{
_editorView = value;
}
}
void CreateDocumentView()
{
_editorView = new GoView();
ISwEditBox2 box1 = new ISwEditBox2();
box1.Position = new PointF(50, 50);
box1.Text = "Test";
_editorView.Document.Add(box1);
}
In the same vspackage if i create a Form instead, my GoText work like expectation:
TestView t = new TestView();
t.Show();
public class TestView : Form
{
public TestView()
{
GoView myView = new GoView();
myView.Dock = DockStyle.Fill;
this.Controls.Add(myView);
ISwEditBox2 box1 = new ISwEditBox2();
box1.Position = new PointF(50, 50);
box1.Text = "Test";
myView.Document.Add(box1);
}
}
My GoDiagram object (you can use others but i want an object derived from GoGroup and containing GoText), this object is like BoxArea in the "demo1" sample:
[Serializable]
class ISwEditBox2 : GoGroup {
// a ISwEditBox2 initially has just an "empty" box shape, shown by a GoRoundedRectangle,
// and a label (a GoText)
public ISwEditBox2()
{
this.Initializing = true;
myBorder = new GoRoundedRectangle();
myBorder.Selectable = false;
if (myBorderPen == null)
{
Pen p = new Pen(Color.Blue, 2);
//p.DashStyle = DashStyle.Dash;
myBorderPen = p;
}
myBorder.Pen = myBorderPen;
myBorder.Size = new SizeF(100,100);
Add(myBorder);
myLabel = new GoText();
//myLabel.Bordered = true;
myLabel.Text = "KB";
myLabel.Selectable = false;
myLabel.Editable = true;
Add(myLabel);
this.Initializing = false;
LayoutChildren(myBorder);
}
private static Pen myBorderPen;
// override to keep fields up-to-date
protected override void CopyChildren(GoGroup newgroup, GoCopyDictionary env) {
base.CopyChildren(newgroup, env);
ISwEditBox2 newobj = (ISwEditBox2)newgroup;
newobj.myBorder = (GoShape)env[myBorder];
newobj.myLabel = (GoText)env[myLabel];
}
// override to keep fields up-to-date
public override void Remove(GoObject obj) {
base.Remove(obj);
if (obj == myBorder)
myBorder = null;
else if (obj == myLabel)
myLabel = null;
}
// Determine the smallest rectangle that encloses all of the other children of this area.
// This might return null, if there are no other objects besides the Border.
public RectangleF ComputeBorder() {
RectangleF rect = RectangleF.Empty;
bool first = true;
foreach (GoObject obj in this) {
if (obj == this.Border) continue;
if (obj == this.myLabel) continue;
if (first) {
first = false;
rect = obj.Bounds;
} else {
// add the object's bounding rect to this one
rect = RectangleF.Union(rect, obj.Bounds);
}
}
if (!first) {
// leave some room as a margin
rect.Inflate(4, 4);
}
return rect;
}
// override to keep myBorder surrounding the other child objects
public override void LayoutChildren(GoObject childchanged) {
if (this.Initializing) return;
GoObject border = this.Border;
GoObject label = this.myLabel;
if (childchanged == border && border != null && label != null) {
RectangleF rect = border.Bounds;
label.SetSpotLocation(BottomLeft, new PointF(rect.X, rect.Y-2));
} else if (!this.AllowDragInOut) {
// compute the minimum rectangle needed to enclose the children except for the Border
RectangleF rect = ComputeBorder();
if (rect != RectangleF.Empty) {
// but don't have the box shrink to minimum size continuously
rect = RectangleF.Union(rect, border.Bounds);
border.Bounds = rect;
if (label != null) {
this.myLabel.SetSpotLocation(BottomLeft, new PointF(rect.X, rect.Y - 2));
}
}
}
}
//
// When this property is false, there should not be a BackgroundSelectionDropped event
// handler, and this node will not support reparenting of its children -- the border
// will always surround its children.
public bool AllowDragInOut {
get { return true; }
}
public override bool OnSelectionDropped(GoObjectEventArgs evt, GoView view) {
if (this.AllowDragInOut) {
// add all selected objects to this ISwEditBox2
view.Selection.AddRange(AddCollection(view.Selection, true));
// update the border to include all selected objects in case the selection crosses the border
GoObject border = this.Border;
if (border != null) {
RectangleF rect = ComputeBorder();
if (rect != RectangleF.Empty) {
// but don't have the box shrink to minimum size continuously
rect = RectangleF.Union(rect, border.Bounds);
border.Bounds = rect;
}
}
return true;
} else {
return false;
}
}
// Allow the user to interactively resize the border;
// this ensures that the border surrounds all of the children.
public override void DoResize(GoView view, RectangleF origRect, PointF newPoint, int whichHandle, GoInputState evttype, SizeF min, SizeF max) {
// compute rectangle for normal resizing
RectangleF newRect = ComputeResize(origRect, newPoint, whichHandle, min, max, true);
// account for the height of the Label
newRect.Y += this.myLabel.Height + 2;
newRect.Height -= this.myLabel.Height + 2;
// compute rectangle required by the child objects
RectangleF minRect = ComputeBorder();
if (minRect != RectangleF.Empty) {
newRect = RectangleF.Union(newRect, minRect);
}
// update the bounding rect of the Border
this.Border.Bounds = newRect;
}
public GoShape Border {
get { return myBorder; }
}
public string Text
{
get { return myLabel.Text; }
set { myLabel.Text = value;}
}
private GoShape myBorder = null;
private GoText myLabel = null;
}

I guess the first thing to do would be to override OnSingleClick (and call base.) in your GoText to see if get a breakpoint on the click.



Another thing to do would be to wire in some way (like a button) to force a call DoBeginEdit(view) to see if that works.



and look for Trace messages as well.

Thanks for your click reply,

-The OnSingleClick is always called when the user click on the GoText part of my group, but seems to "really" works only the first time like before.
-No strange Trace, everything seems to be ok.
- since the OnSingleClick is always called i also try to force the DoBeginEdit in this function without luck:
public override bool OnSingleClick(GoInputEventArgs evt, GoView view)
{
bool retValue = base.OnSingleClick(evt, view);
DoBeginEdit(view);
return retValue;
}
-So, i made the button which call DoBeginEdit(...)
...
GoButton but = new GoButton();
but.Position = new PointF(200, 50);
but.Action += new GoInputEventHandler(button_Action);
but.Text = "Test me";
_editorView.Document.Add(but);
...
void button_Action(object sender, GoInputEventArgs e)
{
box1.TextPart.DoBeginEdit(_editorView);
}
Still no change, the button activate normally my GoText in Edit mode in the "Form" version of my test but the button only activate 1 time the GoText in the "Microsoft.VisualStudio.Shell.WindowPane" version (and only if the user not activate the GoText directly first, so it seems DoBeginEdit can only be called 1 time, we can still try to call it afterward but nothing appends even if we try)

In OnSingleClick, check to see if this.Editor is null. If it isn’t, GoDiagram thinks the GoText is already in edit mode and won’t start the edit.

In fact, this.Editor is null only the first time, why is not at null :) ? or how to make sure this Editor is null…

It is cleared in DoEndEdit, and the same time the edit control is removed.

This is my problems, DoEndEdit() is never called, i do not know why, maybe i can try to force the call, but seems strange to me…

i try in the parent of my GoText (the GoGroup) to force it:
public override void OnLostSelection(GoSelection sel)
{
myLabel.DoEndEdit(sel.View);
base.OnLostSelection(sel);
}
This work fine when the user deselect the GoGroup the GoText can be reactivate more than one time. But it is not perfect since the user can click on this GoGroup (which close GoText) and try to re-edit GoText which do not work in that case because "DoEndEdit" was never called.

There are 2 main ways a edit control is closed.



first is in HandleKey, either for an Esc or Enter or Tab key.

second is if the edit control gets an OnLeave event.



Both of these call DoEndEdit.



Do you see the edit control go away on all of these events?



At this point, I think we have to ask “what is different about the events delivered in VS WindowPanes?”

true, the edit control go away on all of these events…but DoEndEdit never called (when HandleKey or OnLeave).

"What is different about the events delivered in VS WindowPanes?" good question, i will check if i can answer that...

Can you send me a minimal vspackage project that reproduces this?

The problems seems Microsoft which handle event different in a "Shell.WindowPane" vs a normal "Form".

I use this workaround to force the call to DoEndEdit of my control (good to know if you use GoDiagram in VSPackage):
In the GoView:
protected override void OnGotFocus(EventArgs evt)
{
// Call manually NotifyLeave because it is not called
// Resolve the bug about the textbox
var list = this.Controls.OfType().ToArray();
foreach (Control control in list)
if (_notifyLeaveMethod != null)
_notifyLeaveMethod.Invoke(control, null);
base.OnGotFocus(evt);
}
static readonly MethodInfo _notifyLeaveMethod = typeof(Control).GetMethod("NotifyLeave", BindingFlags.NonPublic | BindingFlags.Instance);

I’m a little hesitant to put a “if you are running in this weird environment” kind of a fix into the mainline of our code, so I guess for now this is a good workaround. If you have any issues with it, please let us know.

it’s not a “weird environment”, it standard environment with VSPackage, but true not many development was made with the visual studio shell for now (you can reproduce it in 5min when you made a VSPackage with wizard and add it a few line to add minimal GoDiagram).

I know the code is not clean at all and it is only a workaround if i have any issues, i will update this post ASAP. Maybe, Visual Studio 2010 Shell fix this issue is we are lucky (i can only test it with VS 2008 Shell).

By weird, I did have a couple of things in mind… (1) not very common with our customers and (2) standard events don’t behave like they “should”. But we do try to support as many environments as possible… I’ll come back to this after 4.1 ships.

Ok thanks,

PS: Welcome to the "weird" environments of VSPackage in a couple of weeks :).