diff --git a/Src/Common/Controls/DetailControls/ChooserCommand.cs b/Src/Common/Controls/DetailControls/ChooserCommand.cs
index 16f0a3bf57..c58625d5e3 100644
--- a/Src/Common/Controls/DetailControls/ChooserCommand.cs
+++ b/Src/Common/Controls/DetailControls/ChooserCommand.cs
@@ -33,6 +33,15 @@ public MakeInflAffixEntryChooserCommand(LcmCache cache, bool fCloseBeforeExecuti
m_slot = slot;
}
+ ///
+ /// This command opens the modal New Entry dialog, so have the chooser keep the main window
+ /// active as it hides, to avoid another application flashing in front first.
+ ///
+ public override bool KeepOwnerActiveWhenHiding
+ {
+ get { return true; }
+ }
+
//methods
public override ObjectLabel Execute()
diff --git a/Src/Common/Controls/DetailControls/DetailControlsTests/ChooserCommandKeepOwnerActiveWhenHidingTests.cs b/Src/Common/Controls/DetailControls/DetailControlsTests/ChooserCommandKeepOwnerActiveWhenHidingTests.cs
new file mode 100644
index 0000000000..e50328ea69
--- /dev/null
+++ b/Src/Common/Controls/DetailControls/DetailControlsTests/ChooserCommandKeepOwnerActiveWhenHidingTests.cs
@@ -0,0 +1,44 @@
+// Copyright (c) 2026 SIL International
+// This software is licensed under the LGPL, version 2.1 or later
+// (http://www.gnu.org/licenses/lgpl-2.1.html)
+
+using NUnit.Framework;
+
+namespace SIL.FieldWorks.Common.Framework.DetailControls
+{
+ ///
+ /// Guards the KeepOwnerActiveWhenHiding opt-in contract for the affix chooser commands
+ /// (LT-22578). A chooser command whose Execute() opens another modal dialog must return true
+ /// so ReallySimpleListChooser.HideForCommand re-activates the FLEx main window as the chooser
+ /// hides; without it an unrelated application can flash in front while the new dialog loads. A
+ /// command that opens no dialog must stay false (the base default). The flag is the only part
+ /// of the fix that is deterministic and UI-free; the actual owner activation and window
+ /// Z-order require a live message pump and are verified manually.
+ ///
+ [TestFixture]
+ public class ChooserCommandKeepOwnerActiveWhenHidingTests
+ {
+ ///
+ /// Opens the modal New Entry dialog (InsertEntryDlg), so it must opt in.
+ ///
+ [Test]
+ public void MakeInflAffixEntryChooserCommand_OptsIn()
+ {
+ var command = new MakeInflAffixEntryChooserCommand(
+ null, true, "label", true, null, null, null);
+ Assert.That(command.KeepOwnerActiveWhenHiding, Is.True);
+ }
+
+ ///
+ /// Creates a slot without opening a dialog, so it keeps the base default of false. This
+ /// also exercises the base ChooserCommand default (this command does not override it).
+ ///
+ [Test]
+ public void MakeInflAffixSlotChooserCommand_DoesNotOptIn()
+ {
+ var command = new MakeInflAffixSlotChooserCommand(
+ null, true, "label", 0, false, null, null);
+ Assert.That(command.KeepOwnerActiveWhenHiding, Is.False);
+ }
+ }
+}
diff --git a/Src/Common/Controls/XMLViews/ChooserCommandBase.cs b/Src/Common/Controls/XMLViews/ChooserCommandBase.cs
index 49d7273f19..90cb7d7894 100644
--- a/Src/Common/Controls/XMLViews/ChooserCommandBase.cs
+++ b/Src/Common/Controls/XMLViews/ChooserCommandBase.cs
@@ -97,6 +97,20 @@ public bool ShouldCloseBeforeExecuting
m_fShouldCloseBeforeExecuting = value;
}
}
+
+ ///
+ /// When true, the chooser re-enables its owner window just before hiding itself to run this
+ /// command. Execute() for such a command opens another modal dialog, which re-disables the
+ /// owner; re-enabling it first makes the OS return activation to the FLEx main window when
+ /// the chooser hides, instead of momentarily revealing an unrelated application's window.
+ /// Defaults to false so behavior is unchanged for every command that does not opt in. See
+ /// the "Create new inflectional affix" flow (LT-22578).
+ ///
+ public virtual bool KeepOwnerActiveWhenHiding
+ {
+ get { return false; }
+ }
+
///
/// The entire text of the label that will appear in the chooser
///
diff --git a/Src/Common/Controls/XMLViews/ReallySimpleListChooser.cs b/Src/Common/Controls/XMLViews/ReallySimpleListChooser.cs
index 797acc7745..0e00b335da 100644
--- a/Src/Common/Controls/XMLViews/ReallySimpleListChooser.cs
+++ b/Src/Common/Controls/XMLViews/ReallySimpleListChooser.cs
@@ -2281,6 +2281,27 @@ private void InitializeComponent()
}
#endregion
+ ///
+ /// Hide the chooser before running . When the command opts in via
+ /// KeepOwnerActiveWhenHiding (its Execute() opens another modal dialog), re-enable and then
+ /// re-activate our owner around the hide. While the chooser is modal the OS has disabled the
+ /// owner, so hiding alone would hand the foreground to another application (the next window
+ /// by z-order) instead of back to the FLEx main window, causing a brief flash. Re-enabling is
+ /// not enough on its own; the Activate() is what pulls FLEx forward, and it is not blocked by
+ /// the foreground lock because we are still the foreground process here (LT-22578).
+ ///
+ private void HideForCommand(ChooserCommand cmd)
+ {
+ if (cmd != null && cmd.KeepOwnerActiveWhenHiding && Owner != null)
+ {
+ Owner.Enabled = true;
+ Visible = false;
+ Owner.Activate();
+ return;
+ }
+ Visible = false;
+ }
+
private void HandleCommmandChoice(ChooserCommandNode node)
{
if (node != null)
@@ -2289,7 +2310,7 @@ private void HandleCommmandChoice(ChooserCommandNode node)
if (cmd != null)
{
if (cmd.ShouldCloseBeforeExecuting)
- Visible = false;
+ HideForCommand(cmd);
m_chosenLabel = cmd.Execute();
}
}
@@ -2300,7 +2321,7 @@ private void OnOKClick(object sender, EventArgs e)
Persist();
if (m_linkCmd != null)
{
- Visible = false;
+ HideForCommand(m_linkCmd);
m_chosenLabel = m_linkCmd.Execute();
m_fLinkExecuted = true;
}
diff --git a/Src/LexText/Lexicon/EntrySequenceReferenceLauncher.cs b/Src/LexText/Lexicon/EntrySequenceReferenceLauncher.cs
index 4ac6a6f80c..763c77d072 100644
--- a/Src/LexText/Lexicon/EntrySequenceReferenceLauncher.cs
+++ b/Src/LexText/Lexicon/EntrySequenceReferenceLauncher.cs
@@ -126,7 +126,7 @@ protected override void HandleChooser()
chooser.InitializeExtras(null, Mediator, m_propertyTable);
chooser.AddLink(LexEdStrings.ksAddAComponent, ReallySimpleListChooser.LinkType.kDialogLink,
new AddPrimaryLexemeChooserCommand(m_cache, false, null, m_mediator, m_propertyTable, m_obj, FindForm()));
- DialogResult res = chooser.ShowDialog();
+ DialogResult res = chooser.ShowDialog(FindForm());
if (DialogResult.Cancel == res)
return;
if (chooser.ChosenObjects != null)
@@ -204,7 +204,7 @@ private void HandleChooserForBackRefs(string fieldName, bool fPropContainsEntryR
// Step 3 of LT-11155:
chooser.AddLink(LexEdStrings.ksAddAComplexForm, ReallySimpleListChooser.LinkType.kDialogLink,
new AddComplexFormChooserCommand(m_cache, false, null, m_mediator, m_propertyTable, m_obj, FindForm()));
- DialogResult res = chooser.ShowDialog();
+ DialogResult res = chooser.ShowDialog(FindForm());
if (DialogResult.Cancel == res)
return;
var chosenObjects = chooser.ChosenObjects;
@@ -353,6 +353,15 @@ public AddPrimaryLexemeChooserCommand(LcmCache cache, bool fCloseBeforeExecuting
m_parentWindow = parentWindow;
}
+ ///
+ /// This command opens the modal LinkEntryOrSenseDlg, so have the chooser keep the main
+ /// window active as it hides, to avoid another application flashing in front first.
+ ///
+ public override bool KeepOwnerActiveWhenHiding
+ {
+ get { return true; }
+ }
+
public override ObjectLabel Execute()
{
ObjectLabel result = null;
@@ -426,6 +435,15 @@ public AddComplexFormChooserCommand(LcmCache cache, bool fCloseBeforeExecuting,
m_parentWindow = parentWindow;
}
+ ///
+ /// This command opens the modal EntryGoDlg, so have the chooser keep the main window
+ /// active as it hides, to avoid another application flashing in front first.
+ ///
+ public override bool KeepOwnerActiveWhenHiding
+ {
+ get { return true; }
+ }
+
public override ObjectLabel Execute()
{
ObjectLabel result = null;
diff --git a/Src/LexText/Lexicon/LexEdDllTests/EntrySequenceChooserCommandKeepOwnerActiveWhenHidingTests.cs b/Src/LexText/Lexicon/LexEdDllTests/EntrySequenceChooserCommandKeepOwnerActiveWhenHidingTests.cs
new file mode 100644
index 0000000000..8435dc19c7
--- /dev/null
+++ b/Src/LexText/Lexicon/LexEdDllTests/EntrySequenceChooserCommandKeepOwnerActiveWhenHidingTests.cs
@@ -0,0 +1,43 @@
+// Copyright (c) 2026 SIL International
+// This software is licensed under the LGPL, version 2.1 or later
+// (http://www.gnu.org/licenses/lgpl-2.1.html)
+
+using NUnit.Framework;
+using SIL.FieldWorks.XWorks.LexEd;
+
+namespace LexEdDllTests
+{
+ ///
+ /// Guards the KeepOwnerActiveWhenHiding opt-in contract for the Lexicon "Add a Component" and
+ /// "Add a Complex Form" chooser commands (LT-22578). Both are launched from a chooser that
+ /// hides itself and then open a modal dialog (LinkEntryOrSenseDlg / EntryGoDlg), so both must
+ /// opt in to keep an unrelated application from flashing in front while the dialog loads. See
+ /// ChooserCommandKeepOwnerActiveWhenHidingTests (DetailControls) for the affix equivalents and
+ /// the rationale for why only the opt-in flag is unit-tested.
+ ///
+ [TestFixture]
+ public class EntrySequenceChooserCommandKeepOwnerActiveWhenHidingTests
+ {
+ ///
+ /// "Add a Component" opens the modal LinkEntryOrSenseDlg, so it must opt in.
+ ///
+ [Test]
+ public void AddPrimaryLexemeChooserCommand_OptsIn()
+ {
+ var command = new AddPrimaryLexemeChooserCommand(
+ null, false, "label", null, null, null, null);
+ Assert.That(command.KeepOwnerActiveWhenHiding, Is.True);
+ }
+
+ ///
+ /// "Add a Complex Form" opens the modal EntryGoDlg, so it must opt in.
+ ///
+ [Test]
+ public void AddComplexFormChooserCommand_OptsIn()
+ {
+ var command = new AddComplexFormChooserCommand(
+ null, false, "label", null, null, null, null);
+ Assert.That(command.KeepOwnerActiveWhenHiding, Is.True);
+ }
+ }
+}
diff --git a/Src/LexText/Morphology/InflAffixTemplateControl.cs b/Src/LexText/Morphology/InflAffixTemplateControl.cs
index d6bdce81a8..41d1da865e 100644
--- a/Src/LexText/Morphology/InflAffixTemplateControl.cs
+++ b/Src/LexText/Morphology/InflAffixTemplateControl.cs
@@ -412,7 +412,8 @@ public bool OnInflTemplateAddInflAffixMsa(object cmd)
using (var chooser = MakeChooserWithExtantMsas(m_slot, cmd as XCore.Command))
{
- chooser.ShowDialog(this);
+ // Own the chooser to the top-level main window, not `this` child control.
+ chooser.ShowDialog(m_propertyTable.GetValue