Hi all,
Since I'm new here, let me introduce myself. I'm Tim and I'm working on a custom forms designer based on framework 2.0.
So far the new framework has been making this project a lot easier than if I still had to use 1.1, but now I ran into some weird behavior. Not that it is lethal to my application, but I thought let's just discuss it here and if we all agree it must be a bug report it with MS.
On my main form I'm hosting a DesignSurface and a PropertyGrid. The PropertyGrid is configured to show all properties of the selected component(s) on the DesignSurface. When a component is changed on the DesignSurface (f.i. resized), the corresponding property in the PropertyGrid should be updated simultaneously. In order to achieve this, I handle the IComponentChangeService.ComponentChanged event and refresh the PropertyGrid. This approach works perfectly fine... except for one scenario (as far as I can see now): in every resize operation you'll notice the PropertyGrid is refreshed twice. The first time after you resized the first few pixels (while still dragging!) and the second time, as desired, after the mousebutton is released and the resize is done.
It's this first refresh (caused by a ComponentChanged event that is raised by the control that is in a resize operation) I'm interested in. The Visual Studio 2005 forms designer does not show similar behavior, neither do forms designers (both VS and custom) in framework 1.1. Since the event is coming from the inner circles of the DesignSurface, I have strong suspicions that we're dealing with a bug here. It would definitely not be the first bug in the 2.0 design libraries.
Below I'll give the code that reproduces the behavior. Set a breakpoint on Me.PropertyGrid1.Refresh() to observe the undesired event.
Public Class Form1
Private _surface As DesignSurface
Private _host As IDesignerHost
Private _root As Control
Private WithEvents _selection As ISelectionService
Private WithEvents _change As IComponentChangeService
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me._surface = New DesignSurface(GetType(Form))
Me._host = CType(Me._surface.GetService(GetType(IDesignerHost)), IDesignerHost)
Me._root = CType(Me._host.RootComponent, Control)
Me._selection = CType(Me._surface.GetService(GetType(ISelectionService)), ISelectionService)
Me._change = CType(Me._surface.GetService(GetType(IComponentChangeService)), IComponentChangeService)
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim bto As Button = CType(Me._host.CreateComponent(GetType(Button)), Button)
bto.Text = "Replace Me!"
Me._root.Controls.Add(bto)
Me.OnSelectionChanged(Me._selection.GetSelectedComponents)
Dim view As Control = CType(Me._surface.View, Control)
view.Dock = DockStyle.Fill
Me.SplitContainer1.Panel1.Controls.Add(view)
Me._host.Activate()
End Sub
Private Sub _selection_SelectionChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles _selection.SelectionChanged
Me.OnSelectionChanged(Me._selection.GetSelectedComponents)
End Sub
Protected Overridable Sub OnSelectionChanged(ByVal newSelection As ICollection)
Dim s(newSelection.Count - 1) As Object
newSelection.CopyTo(s, 0)
Me.PropertyGrid1.SelectedObjects = s
End Sub
Private Sub _change_ComponentChanged(ByVal sender As Object, ByVal e As System.ComponentModel.Design.ComponentChangedEventArgs) Handles _change.ComponentChanged
Me.PropertyGrid1.Refresh()
End Sub
End Class
Partial Class Form1
Inherits System.Windows.Forms.Form
'Form overrides dispose to clean up the component list.
_
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
_
Private Sub InitializeComponent()
Me.SplitContainer1 = New System.Windows.Forms.SplitContainer
Me.PropertyGrid1 = New System.Windows.Forms.PropertyGrid
Me.SplitContainer1.Panel2.SuspendLayout()
Me.SplitContainer1.SuspendLayout()
Me.SuspendLayout()
'
'SplitContainer1
'
Me.SplitContainer1.Dock = System.Windows.Forms.DockStyle.Fill
Me.SplitContainer1.Location = New System.Drawing.Point(0, 0)
Me.SplitContainer1.Name = "SplitContainer1"
'
'SplitContainer1.Panel1
'
Me.SplitContainer1.Panel1.BackColor = System.Drawing.SystemColors.Window
'
'SplitContainer1.Panel2
'
Me.SplitContainer1.Panel2.Controls.Add(Me.PropertyGrid1)
Me.SplitContainer1.Size = New System.Drawing.Size(614, 405)
Me.SplitContainer1.SplitterDistance = 436
Me.SplitContainer1.TabIndex = 0
'
'PropertyGrid1
'
Me.PropertyGrid1.Dock = System.Windows.Forms.DockStyle.Fill
Me.PropertyGrid1.Location = New System.Drawing.Point(0, 0)
Me.PropertyGrid1.Name = "PropertyGrid1"
Me.PropertyGrid1.Size = New System.Drawing.Size(174, 405)
Me.PropertyGrid1.TabIndex = 0
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(614, 405)
Me.Controls.Add(Me.SplitContainer1)
Me.Name = "Form1"
Me.Text = "My First Custom Designer"
Me.SplitContainer1.Panel2.ResumeLayout(False)
Me.SplitContainer1.ResumeLayout(False)
Me.ResumeLayout(False)
End Sub
Friend WithEvents SplitContainer1 As System.Windows.Forms.SplitContainer
Friend WithEvents PropertyGrid1 As System.Windows.Forms.PropertyGrid
End Class