Discussion:
SplitContainer failure caused by designer
(too old to reply)
Jakob Lithner
2007-10-22 15:07:02 UTC
Permalink
I have a usercontrol that I divide with a SplitContainer.
I set some specific positions and everything works fine.
The problem is that EVERY time I change anything in the control (code or
design) the designer moves around a couple of lines in the designer file
which means I get a runtime exception!

This is the section:
'
'mySplitContainer
'
Me.mySplitContainer.Anchor = CType((((System.Windows.Forms.AnchorStyles.Top
Or System.Windows.Forms.AnchorStyles.Bottom) _
Or System.Windows.Forms.AnchorStyles.Left) _
Or System.Windows.Forms.AnchorStyles.Right),
System.Windows.Forms.AnchorStyles)
Me.mySplitContainer.Location = New System.Drawing.Point(0, 0)
Me.mySplitContainer.Name = "mySplitContainer"
'
'mySplitContainer.Panel1
'
Me.mySplitContainer.Panel1.Controls.Add(Me.btnConfirmAll)
Me.mySplitContainer.Panel1.Controls.Add(Me.btnSkipTranslation)
Me.mySplitContainer.Panel1.Controls.Add(Me.lblTextCount)
Me.mySplitContainer.Panel1.Controls.Add(Me.btnConfirmEnglish)
Me.mySplitContainer.Panel1.Controls.Add(Me.lblTextSelectedCount)
Me.mySplitContainer.Panel1.Controls.Add(Me.btnFind)
Me.mySplitContainer.Panel1.Controls.Add(Me.grdText)
Me.mySplitContainer.Panel1.Controls.Add(Me.btnApproveNext)
Me.mySplitContainer.Panel1MinSize = 400
'
'mySplitContainer.Panel2
'
Me.mySplitContainer.Panel2.Controls.Add(Me.btnClose)
Me.mySplitContainer.Panel2.Controls.Add(Me.ctrlText)
Me.mySplitContainer.Panel2.Controls.Add(Me.grdTextRows)
Me.mySplitContainer.Panel2.Controls.Add(Me.btnSave)
Me.mySplitContainer.Panel2.Controls.Add(Me.btnAction)
Me.mySplitContainer.Panel2.Controls.Add(Me.lblTextRowCount)
Me.mySplitContainer.Panel2.Controls.Add(Me.btnCopyEnglish)
Me.mySplitContainer.Panel2MinSize = 369
Me.mySplitContainer.Size = New System.Drawing.Size(1020, 528)
Me.mySplitContainer.SplitterDistance = 490
Me.mySplitContainer.SplitterWidth = 8
Me.mySplitContainer.TabIndex = 0


Exception occurs on line (Me.mySplitContainer.Panel2MinSize = 369):

"SplitterDistance must be between Panel1MinSize and Width - Panel2MinSize"
At this time SplitterDistance has a value of 121.

In my mind all properties of the mySplitContainer should be set before all
properties of the sub panels. As you can see there are four properties of the
mySplitContainer that are moved to the end, AFTER all properties of the
Panel2!
When this happens I gently move the lines back where I think they should be
and quickly check in my code, compile, run and everything is fine.

But the next time I need to make and adjustment to this user control the
designer moves the same rows around again, and I get runtime error.

Any suggestions for this ghost behaviour?
Linda Liu[MSFT]
2007-10-24 05:25:02 UTC
Permalink
Hi,

I performed a test based on your description and did reproduce the problem
on my side.

If you set a break point on the line of code
'Me.mySplitContainer.Panel1MinSize = 400' and run the application by
pressing F5, you should observe the following values of properties when
this break point is hit:

SplitContainer.Width = 150 (this is the default value)
SplitContainer.SplitterWidth = 4 (this is the default value)
SplitContainer.Panel1MinSize = 25 (this is the default value)
SplitContainer.Panel2MinSize = 25 (this is the default value)
SplitContainer.SplitterDistance = 50 (this is the default value)

Press F10 and the values of these properties become:

SplitContainer.Width = 150 (this is the default value)
SplitContainer.SplitterWidth = 4 (this is the default value)
SplitContainer.Panel1MinSize = 400
SplitContainer.Panel2MinSize = 25 (this is the default value)
SplitContainer.SplitterDistance = 121

As we can see, the value of 121 for the SplitterDistance is calculated from
the formula below:

SpliterContainer.Width - SplitContainer.SplitterWidth -
SplitContainer.Panel2MinSize

that is, 150 - 4 - 25 = 121

Keep pressing F10 until the line of code 'Me.mySplitContainer.Panel2MinSize
= 369' is hit. You should see the values of the properties remain the same
as before.
Press F10 and this line of code is executed and then you get an
InvalidOperationException.

This is because when the new value set to the Panel2MinSize property is
bigger than the Panel2.Width, the SplitContainer tries to adjust the value
of the SplitterDistance property according to the new Panel2MinSize
property value. However, at this time, the value of the
SplitContainer.Width is still the default value 150, but that of the
Panel2MinSize property becomes 369. According to the formula
"SpliterContainer.Width - SplitContainer.SplitterWidth -
SplitContainer.Panel2MinSize", the calculation result is a negative value
which is not valid, so the InvalidOperationException is thrown.

The workaround of this problem is simple, i.e. reset the value of the
Panel2MinSize property (i.e. set its value to 25), or set the Panel2MinSize
property to a value less than or equal to 146.

Hope this helps.
If you have any question, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
Jakob Lithner
2007-10-24 07:02:01 UTC
Permalink
Thanks Linda for explicit answer!
Your workaround works, and I understand the manual stepping.

BUT, I actually want the Panel2MinZize property to be set to 400!
It was set by purpose as lower value will make the panel look awkward.

Is the designer not able to handle this?
Why is it rearranging the designer code in this strange order at all?
Linda Liu[MSFT]
2007-10-25 08:55:22 UTC
Permalink
Hi Jakob,

Thank you for your feedback! I understand your concern.

A more complicated and better solution to this problem is to move the line
of code that sets the Panel2MinSize property to the last. To do this, we
could implement a custom CodeDomSerializer for the SplitContainer control.

The following is a sample to do this:

using System.ComponentModel.Design.Serialization;
using System.CodeDom;

[DesignerSerializer(typeof(MyCodeDomSerializer),typeof(CodeDomSerializer))]
public class MySplitContainer:SplitContainer
{
}

public class MyCodeDomSerializer : CodeDomSerializer
{
public override object Serialize(IDesignerSerializationManager
manager, object value)
{
CodeDomSerializer baseClassSerializer =
(CodeDomSerializer)manager.GetSerializer(typeof(SplitContainer),
typeof(CodeDomSerializer));
object codeObject = baseClassSerializer.Serialize(manager,
value);

if (codeObject is CodeStatementCollection)
{
CodeStatementCollection statements =
(CodeStatementCollection)codeObject;
CodeStatement setPanel2MinSize = null;
foreach (CodeStatement state in statements)
{
if (state.GetType() == typeof(CodeAssignStatement))
{
if ((state as CodeAssignStatement).Left.GetType()
== typeof(CodePropertyReferenceExpression))
{
if
(((CodePropertyReferenceExpression)((CodeAssignStatement)state).Left).Proper
tyName == "Panel2MinSize")
{
setPanel2MinSize = state;
break;
}
}
}
}
if (setPanel2MinSize != null)
{
statements.Remove(setPanel2MinSize);
statements.Add(setPanel2MinSize);
}
}
return codeObject;
}
}

Build the project and use the derived SplitContainer on your form instead
of the standard SplitContainer.

I have tested the above derived SplitContainer and it works well on my
side. Please try it on your machine to see if the problem is solved and let
me know the result.

Sincerely,
Linda Liu
Microsoft Online Community Support
Jakob Lithner
2007-10-25 12:36:01 UTC
Permalink
Thanks for your effort Linda.
I tried the suggested solution and it works fine.
But I am not sure I will use it every time I need a SplitContainer .....
Setting some properties in Load Event will also do the job.

Lessons learned:
- Current implementation of SplitContainer has a problem for certain
settings of panelsize.
- It is possible to do your own "designer implementation" of components
inheriting from the CodeDomSerializer
Linda Liu[MSFT]
2007-10-26 08:22:18 UTC
Permalink
Hi Jakob,

Thank you for your prompt reply!

Yes, we could set the properties of the SplitContainer in the form's Load
event handler to detour this problem. This is another workaround : )

You also do a good job in summarizing this issue : )

If you have any other question in the future, please don't hesitate to
contact us. It's always our pleasure to be of assistance!

Have a nice weekend!

Sincerely,
Linda Liu
Microsoft Online Community Support
Jakob Lithner
2007-10-26 09:00:02 UTC
Permalink
My pleasure!
Your detailed and devoted answers are very helpful.
Marcin Kosobudzki
2008-05-15 10:11:57 UTC
Permalink
You can set

SplitContainer.Panel2MinSize = 369;

at form Load() event.

*** Sent via Developersdex http://www.developersdex.com ***

Loading...