2009-08-13 14 views
14

La ChildWindow è una finestra modale, ma non blocca. C'è un modo per bloccarlo? Fondamentalmente voglio un metodo ShowDialog() che chiamerà ChildWindow.Show() ma non restituirà fino a quando l'utente non avrà chiuso ChildWindow. Ho provato a utilizzare Monitor.Enter() per bloccare dopo ChildWindow.Show(), ma ChildWindow non ha mai eseguito il rendering e il browser è stato appena bloccato. Qualcuno ha qualche idea?Come rendere il blocco ChildWindow

+0

Ci può spiegare che cosa stai cercando di raggiungere ? – Ray

+0

Solo una semplice finestra di blocco modale simile a MessageBox.Show() o Form.ShowDialog() –

+0

Ho provato tutto e non ho mai trovato una soluzione. Stavo cercando di creare il mio MessageBox.Ho anche provato asincrono ma è sempre stato bloccato. Ho rinunciato dopo aver letto che Tim Heuer diceva che non era possibile avere il vero Modal. – Paully

risposta

5

Non è possibile eseguire ciò che si sta tentando di fare in Silverlight. Qualsiasi modifica apportata all'interfaccia utente verrà eseguita sul thread dell'interfaccia utente. Se blocchi il thread dell'interfaccia utente, l'utente non può interagire con il browser, quindi non c'è alcuna azione da intraprendere per sbloccare il thread.

Se si desidera veramente creare una finestra di dialogo di blocco, l'unico modo per farlo è da un thread non dell'interfaccia utente. Per esempio. si potrebbe creare un metodo che sembra qualcosa di simile:

private void ShowModalDialog() 
    { 
     AutoResetEvent waitHandle = new AutoResetEvent(false); 
     Dispatcher.BeginInvoke(() => 
     { 
      ChildWindow cw = new ChildWindow(); 
      cw.Content = "Modal Dialog"; 
      cw.Closed += (s, e) => waitHandle.Set(); 
      cw.Show(); 
     }); 
     waitHandle.WaitOne(); 
    } 

Questo metodo mostrerà una finestra di dialogo e non tornerà fino a quando la finestra viene chiusa. Ma questo metodo può essere chiamato solo da una non-UI-thread. Chiamarlo dal thread dell'interfaccia utente causerà un deadlock (poiché il thread dell'interfaccia utente è in attesa di un evento che può essere attivato solo sul thread dell'interfaccia utente).

In alternativa, è consigliabile prendere in considerazione la logica asincrona piuttosto che forzarla in sincronia.

+0

Mi piace questa soluzione e sembra che dovrebbe funzionare, ma dal momento che non può essere chiamata sul thread dell'interfaccia utente, non sono sicuro di poterlo usare (anche se in realtà non l'ho specificato nella mia domanda (dal Non ci ho nemmeno pensato allora)). Ad ogni modo, ottima soluzione. –

-1

Ho eliminato la creazione di una finestra di dialogo modale "bloccante", avendo un controllo personalizzato che ha un allineamento verticale e orizzontale come tratto, e quindi lo aggiungo come figlio del layout del controllo corrente.

ad es.

<Grid x:Name="LayoutRoot" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> 
     <Rectangle Fill="LightBlue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Opacity="0.3" /> 
    </Grid> 

e poi nel controllo personalizzato

Utilities.UITools.MessageBox x = new Utilities.UITools.MessageBox(); 
x.SetError(e.Result); 
this.LayoutRoot.Children.Add(x); 

A seconda di ciò che deve essere visualizzato nella modale, ho aggiungere dinamicamente controlli per il layout modale. Chiaramente, non è una soluzione elegante, ma almeno funziona.

+0

Ciò lo renderebbe modale in un modo, ma non sembra che si bloccherebbe in quanto non vi è alcuna chiamata di funzione che bloccherebbe fino a quando l'utente non chiuderà la finestra del messaggio. –

+0

L'ho bloccato bloccando un evento nella casella del messaggio. Quindi, blocca il resto del programma fino a quando l'evento si attiva – Johannes

3

Se si desidera eseguire un'azione sulla finestra secondaria, utilizzare il seguente codice. Nascondere i controlli indesiderati prima invocano e mostrano sulla chiusura della finestra secondaria, semplice :)

ChildWindow cw = new ChildWindow(); 
cw.Closed += new EventHandler(cw_Closed); 
cw.Show(); 
0

Si potrebbe provare ad annullare sempre la chiusura dell'evento e impostare il DialogResult tardi.

void ConfigTemplatePopup_Closing(object sender, System.ComponentModel.CancelEventArgs e) 
    { 
     if (tmpDialogResult != null || DialogResult == true) return; 
     tmpDialogResult = DialogResult; //this is a field 
     e.Cancel = true; 
     var myMessageBox = new WspMessageBox("Are you sure you want to close?", true); 
     myMessageBox.Closed += (s, e2) => 
            { 
             if (wspMessageBox.DialogResult == true) 
             { 
              DialogResult = tmpDialogResult; 
             }else 
             { 
              tmpDialogResult = null; 
             } 
            }; 
     myMessageBox.Show(); 
    } 
0

Usando async and await in Silverlight 5 si può facilmente creare un metodo Show statica che può essere bloccando, come

public partial class MyDialog { 
    MyResultType result; 
    readonly AutoResetEvent waitHandle; 

    MyDialog() { 
    InitializeComponent(); 
    waitHandle = new AutoResetEvent(false); 
    } 

    public static Task<MyResultType> Show() { 
    var dialog = new MyDialog(); 
    dialog.Show(); 
    dialog.Closed += (s, e) => dialog.waitHandle.Set(); 
    return Task<MyResultType>.Factory.StartNew(() => { 
     dialog.waitHandle.WaitOne(); return dialog.result; }); 
    } 

    void OkButton_Click(object sender, RoutedEventArgs e) { 
     result = new MyResultType(); 
     // Initialize result... 

     Close(); 
    } 
} 

e chiamare la finestra di dialogo come

public async void TestDialog() { 
    var result = await ConfirmBox.Show(); 

    // This code will be performed after the Dialog is closed. 
    // use result... 
} 
+0

-1 Ho paura, perché questo frammento non viene compilato. L'output di 'Task .Factory.StartNew()' non è attendibile. Inoltre, mentre questa risposta introduce il pattern async/await nel mix, non risolve il problema fondamentale che non è possibile bloccare il thread dell'interfaccia utente senza bloccare il browser, quindi questo approccio non offre alcun valore reale oltre alla soluzione di Keith Mahoney. –

+0

Questo snippet proviene dal mio progetto di lavoro. Lo uso come soluzione comune per i dialoghi. Per compilarlo è necessario il "pacchetto di targeting asincrono", che puoi aggiungere al tuo progetto usando il nuget. Si prega di leggere l'articolo utilizzando il link nella mia risposta. –

Problemi correlati