Skip to content

Commit

Permalink
Resume invocation of OnParentHandleRecreated for child control when f…
Browse files Browse the repository at this point in the history
…orm recreates handle

Fixes #6093

Fix the regression introduced in #2262, which added a check to the method
handling recreation of a control handle to verify that the control is
created before any child controls can be re-parented on to it.

However it was missed that DestroyHandle() method resets the state (i.e.
removes Created state), but CreateHandle() method doesn't set the state
back.
  • Loading branch information
RussKie committed Nov 4, 2021
1 parent a672369 commit 3a203b5
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/System.Windows.Forms/src/System/Windows/Forms/Control.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9629,6 +9629,9 @@ internal virtual void RecreateHandleCore()
// the call shouldn't fail.
// However, it could fail if this.CreateParams.Parent is changed outside our control.
CreateHandle();

// DestroyHandle resets the state, but CreateHandle doesn't set the state back.
SetState(States.Created, true);
}
catch (Exception)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,62 @@ public void Control_CreateParams_GetVisible_ReturnsExpected(bool visible, int ex
Assert.False(control.IsHandleCreated);
}

[WinFormsFact]
public void Control_RecreateHandleCore_invokes_OnParentHandleRecreated_for_children()
{
using Form form = new();
SubCheckedListBox checkedListBox1 = new();
SubButton button1 = new();
SubListBox listBox1 = new();
SubListView listView1 = new();

checkedListBox1.Items.AddRange(new object[] { "Foo", "Foo", "Foo" });
checkedListBox1.Location = new Point(10, 10);
checkedListBox1.Size = new Size(103, 64);

button1.Location = new Point(12, 166);
button1.Size = new Size(213, 20);

listBox1.Items.AddRange(new object[] { "Foo", "Foo", "Foo" });
listBox1.Location = new Point(12, 80);
listBox1.Size = new Size(101, 69);

listView1.Items.AddRange(new ListViewItem[] { new("Foo"), new("Foo"), new("Foo") });
listView1.Location = new Point(130, 10);
listView1.Size = new Size(121, 64);
listView1.View = View.List;

form.Controls.Add(checkedListBox1);
form.Controls.Add(button1);
form.Controls.Add(listBox1);
form.Controls.Add(listView1);

form.Show();

// This will recreate the handle.
form.ShowInTaskbar = false;

try
{
AssertHandler(button1);
AssertHandler(listView1);
AssertHandler(checkedListBox1);
AssertHandler(listBox1);
}
finally
{
form.Close();
}

return;

static void AssertHandler(IParentHandleRecreationHandler handler)
{
Assert.Equal(1, handler.OnParentHandleRecreatedCalled);
Assert.Equal(1, handler.OnParentHandleRecreatingCalled);
}
}

private class SubControl : Control
{
public SubControl() : base()
Expand Down Expand Up @@ -1046,5 +1102,83 @@ public SubControl(Control parent, string text, int left, int top, int width, int

public new void WndProc(ref Message m) => base.WndProc(ref m);
}

private class SubCheckedListBox : CheckedListBox, IParentHandleRecreationHandler
{
public int OnParentHandleRecreatedCalled { get; private set; }
public int OnParentHandleRecreatingCalled { get; private set; }

internal override void OnParentHandleRecreated()
{
OnParentHandleRecreatedCalled++;
base.OnParentHandleRecreated();
}

internal override void OnParentHandleRecreating()
{
OnParentHandleRecreatingCalled++;
base.OnParentHandleRecreating();
}
}

private class SubListBox : ListBox, IParentHandleRecreationHandler
{
public int OnParentHandleRecreatedCalled { get; private set; }
public int OnParentHandleRecreatingCalled { get; private set; }

internal override void OnParentHandleRecreated()
{
OnParentHandleRecreatedCalled++;
base.OnParentHandleRecreated();
}

internal override void OnParentHandleRecreating()
{
OnParentHandleRecreatingCalled++;
base.OnParentHandleRecreating();
}
}

private class SubButton : Button, IParentHandleRecreationHandler
{
public int OnParentHandleRecreatedCalled { get; private set; }
public int OnParentHandleRecreatingCalled { get; private set; }

internal override void OnParentHandleRecreated()
{
OnParentHandleRecreatedCalled++;
base.OnParentHandleRecreated();
}

internal override void OnParentHandleRecreating()
{
OnParentHandleRecreatingCalled++;
base.OnParentHandleRecreating();
}
}

private class SubListView : ListView, IParentHandleRecreationHandler
{
public int OnParentHandleRecreatedCalled { get; private set; }
public int OnParentHandleRecreatingCalled { get; private set; }

internal override void OnParentHandleRecreated()
{
OnParentHandleRecreatedCalled++;
base.OnParentHandleRecreated();
}

internal override void OnParentHandleRecreating()
{
OnParentHandleRecreatingCalled++;
base.OnParentHandleRecreating();
}
}

private interface IParentHandleRecreationHandler
{
int OnParentHandleRecreatedCalled { get; }
int OnParentHandleRecreatingCalled { get; }
}
}
}

0 comments on commit 3a203b5

Please sign in to comment.