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 dotnet#6093

Fix the regression introduced in dotnet#2262.
  • Loading branch information
RussKie committed Nov 4, 2021
1 parent 4fd743e commit cca5560
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 6 deletions.
13 changes: 8 additions & 5 deletions src/System.Windows.Forms/src/System/Windows/Forms/Control.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1483,7 +1483,7 @@ public ControlCollection Controls
[EditorBrowsable(EditorBrowsableState.Advanced)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[SRDescription(nameof(SR.ControlCreatedDescr))]
public bool Created => (_state & States.Created) != 0;
public bool Created => GetState(States.Created);

/// <summary>
/// Returns the CreateParams used to create the handle for this control.
Expand Down Expand Up @@ -3032,7 +3032,7 @@ internal virtual Control ParentInternal
[EditorBrowsable(EditorBrowsableState.Advanced)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[SRDescription(nameof(SR.ControlRecreatingHandleDescr))]
public bool RecreatingHandle => (_state & States.Recreate) != 0;
public bool RecreatingHandle => GetState(States.Recreate);

internal virtual void AddReflectChild()
{
Expand Down Expand Up @@ -4989,7 +4989,7 @@ public void CreateControl()
/// </summary>
internal void CreateControl(bool fIgnoreVisible)
{
bool ready = (_state & States.Created) == 0;
bool ready = !GetState(States.Created);

// PERF: Only "create" the control if it is
// : visible. This has the effect of delayed handle creation of
Expand All @@ -4998,7 +4998,7 @@ internal void CreateControl(bool fIgnoreVisible)

if (ready || fIgnoreVisible)
{
_state |= States.Created;
SetState(States.Created, true);
bool createdOK = false;
try
{
Expand Down Expand Up @@ -5033,7 +5033,7 @@ internal void CreateControl(bool fIgnoreVisible)
{
if (!createdOK)
{
_state &= (~States.Created);
SetState(States.Created, false);
}
}

Expand Down Expand Up @@ -9827,6 +9827,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 @@ -730,7 +730,7 @@ public void Control_GetNextItem_Buttons_CycleForwardExpected(RightToLeft rightTo
using Button button1 = new();
using Button button2 = new();
using Button button3 = new();
control.Controls.AddRange(new Button[] { button1, button2, button3});
control.Controls.AddRange(new Button[] { button1, button2, button3 });
Control nextControl1 = control.GetNextControl(button1, forward: true);
Control nextControl2 = control.GetNextControl(button2, forward: true);
Control nextControl3 = control.GetNextControl(button3, forward: true);
Expand Down Expand Up @@ -974,6 +974,62 @@ public void Control_SelectNextControl_ToolStrips_CycleBackwardExpected(RightToLe
Assert.True(toolStrip2.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 @@ -1301,5 +1357,83 @@ public Control GetNextSelectableControl(Control ctl, bool forward, bool tabStopO

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 cca5560

Please sign in to comment.