Avevo in qualche modo un problema simile. Quindi, la finestra di dialogo modale, ma in quella finestra di dialogo è presente il pulsante "Seleziona" che deve passare alla forma principale (preferibilmente senza chiudere la finestra di dialogo modale), selezionare un'area da lì e quindi tornare alla finestra di dialogo modale con le informazioni di selezione. Ho provato a giocare un po 'con dialoghi non modali/show/hide e dopo non ho trovato nessuna buona soluzione (facile da codificare), codificata in qualche modo l'approccio hacky usando le chiamate di funzione native win32. Quello che ho testato - funziona bene con winforms e anche con xaml.
Il problema in sé non è nemmeno semplice: l'utente preme "Seleziona", quindi può dimenticare che stava selezionando qualcosa e tornare alla stessa finestra di selezione, che può comportare due o più istanze della stessa finestra di dialogo.
Sto provando ad affrontare questo problema utilizzando variabili statiche (istanza/genitore) - se si dispone di winform puro o pura tecnologia wpf, è possibile ottenere il genitore da instance.Parent o instance.Owner.
public partial class MeasureModalDialog : Window
{
// Dialog has "Select area" button, need special launch mechanism. (showDialog/SwitchParentChildWindows)
public static MeasureModalDialog instance = null;
public static object parent = null;
static public void showDialog(object _parent)
{
parent = _parent;
if (instance == null)
{
instance = new MeasureModalDialog();
// Parent is winforms, child is xaml, this is just glue to get correct window owner to child dialog.
if (parent != null && parent is System.Windows.Forms.IWin32Window)
new System.Windows.Interop.WindowInteropHelper(instance).Owner = (parent as System.Windows.Forms.IWin32Window).Handle;
// Enable parent window if it was disabled.
instance.Closed += (_sender, _e) => { instance.SwitchParentChildWindows(true); };
instance.ShowDialog();
instance = null;
parent = null;
}
else
{
// Try to switch to child dialog.
instance.SwitchParentChildWindows(false);
}
} //showDialog
public void SwitchParentChildWindows(bool bParentActive)
{
View3d.SwitchParentChildWindows(bParentActive, parent, this);
}
public void AreaSelected(String selectedAreaInfo)
{
if(selectedAreaInfo != null) // Not cancelled
textAreaInfo.Text = selectedAreaInfo;
SwitchParentChildWindows(false);
}
private void buttonAreaSelect_Click(object sender, RoutedEventArgs e)
{
SwitchParentChildWindows(true);
View3d.SelectArea(AreaSelected);
}
...
public static class View3d
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnableWindow(IntPtr hWnd, bool bEnable);
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindowEnabled(IntPtr hWnd);
/// <summary>
/// Extracts window handle in technology independent wise.
/// </summary>
/// <param name="formOrWindow">form or window</param>
/// <returns>window handle</returns>
static public IntPtr getHandle(object formOrWindow)
{
System.Windows.Window window = formOrWindow as System.Windows.Window;
if(window != null)
return new System.Windows.Interop.WindowInteropHelper(window).Handle;
System.Windows.Forms.IWin32Window form = formOrWindow as System.Windows.Forms.IWin32Window;
if (form != null)
return form.Handle;
return IntPtr.Zero;
}
/// <summary>
/// Switches between modal sub dialog and parent form, when sub dialog does not needs to be destroyed (e.g. selecting
/// something from parent form)
/// </summary>
/// <param name="bParentActive">true to set parent form active, false - child dialog.</param>
/// <param name="parent">parent form or window</param>
/// <param name="dlg">sub dialog form or window</param>
static public void SwitchParentChildWindows(bool bParentActive, object parent, object dlg)
{
if(parent == null || dlg == null)
return;
IntPtr hParent = getHandle(parent);
IntPtr hDlg = getHandle(dlg);
if(!bParentActive)
{
//
// Prevent recursive loops which can be triggered from UI. (Main form => sub dialog => select (sub dialog hidden) => sub dialog in again.
// We try to end measuring here - if parent window becomes inactive -
// means that we returned to dialog from where we launched measuring. Meaning nothing special needs to be done.
//
bool bEnabled = IsWindowEnabled(hParent);
View3d.EndMeasuring(true); // Potentially can trigger SwitchParentChildWindows(false,...) call.
bool bEnabled2 = IsWindowEnabled(hParent);
if(bEnabled != bEnabled2)
return;
}
if(bParentActive)
{
EnableWindow(hDlg, false); // Disable so won't eat parent keyboard presses.
ShowWindow(hDlg, 0); //SW_HIDE
}
EnableWindow(hParent, bParentActive);
if(bParentActive)
{
SetForegroundWindow(hParent);
BringWindowToTop(hParent);
} else {
ShowWindow(hDlg, 5); //SW_SHOW
EnableWindow(hDlg, true);
SetForegroundWindow(hDlg);
}
} //SwitchParentChildWindows
...
stesso paradigma potrebbe avere problemi di dialogo non modale, dal momento che ogni selezione catena chiamata di funzione mangia pila e alla fine si potrebbe ottenere overflow dello stack, o si potrebbe ottenere anche problemi con la gestione di finestra padre di stato (abilitare/disabilitare).
Quindi penso che questa soluzione sia piuttosto leggera a un problema, anche se sembra piuttosto complessa.
Esiste un motivo specifico per cui non è possibile creare un'istanza nuova ogni volta? Secondo me è comunque più sicuro e migliore. –
@Alex La radice del problema sta in un thrid party control che sto usando. Diventa ancora più complesso quando si lancia in Prisma e Unità. Credo sinceramente che una forma a singleton come nei giorni della winform sarebbe più facile da implementare. Quando si prova Show/Hide su una finestra di dialogo non modale, le prestazioni sono eccezionali. Tuttavia, il requisito stabilisce che la finestra di dialogo debba essere modale. –
Il metodo Show della finestra di dialogo accetta un parametro? Ho trovato questo http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/f3565f01-f972-4aaf-80cc-986488d25261 che potrebbe essere di aiuto. –