2009-07-10 9 views
26

Je dois créer deux (ou plus) fenêtres WPF à partir du même processus. Mais les fenêtres doivent être traitées par des threads séparés car ils ne devraient pas pouvoir se bloquer les uns les autres. Comment puis-je faire cela?Comment créer et afficher des fenêtres WPF sur des threads séparés?

En WinForms ceci est réalisé par:

  • Démarrer un nouveau thread
  • Créer un formulaire à partir du nouveau thread
  • Appel Application.Run avec le formulaire en tant que paramètre

Mais comment est-ce que je fais la même chose dans WPF?

Répondre

40

Comme msdn états:

private void NewWindowHandler(object sender, RoutedEventArgs e) 
{  
    Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint)); 
    newWindowThread.SetApartmentState(ApartmentState.STA); 
    newWindowThread.IsBackground = true; 
    newWindowThread.Start(); 
} 

private void ThreadStartingPoint() 
{ 
    Window1 tempWindow = new Window1(); 
    tempWindow.Show();  
    System.Windows.Threading.Dispatcher.Run(); 
} 

EDIT: C'est une ancienne réponse, mais comme il semble être visité souvent, je pourrais aussi penser des modifications/améliorations suivantes (non testé).

Si vous souhaitez fermer une telle fenêtre, il suffit de garder une référence à l'objet de la fenêtre à l'extérieur du fil (délégué), puis invoquer près, quelque chose comme ceci:

void CloseWindowSafe(Window w) 
{ 
    if (w.Dispatcher.CheckAccess()) 
     w.Close(); 
    else 
     w.Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(w.Close)); 
} 

// ... 
CloseWindowSafe(tempWindow); 

Si le nouveau thread pourrait devenir terminé (interrompu de force), conformément à la question dans les commentaires:

private void ThreadStartingPoint() 
{ 
    try{ 
     Window1 tempWindow = new Window1(); 
     tempWindow.Show();  
     System.Windows.Threading.Dispatcher.Run(); 
    } 
    catch(ThreadAbortException) 
    { 
     tempWindow.Close(); 
     System.Windows.Threading.Dispatcher.InvokeShutdown(); 
    } 
    //the CLR will "rethrow" thread abort exception automatically 
} 

AVERTISSEMENT: ne pas le faire à la maison, fils est l'interruption (presque toujours) des meilleures pratiques. Les threads doivent être manipulés gracieusement via l'une des différentes techniques de synchronisation, ou dans ce cas, simplement via un window.Close()

+3

Grande Comment puis-je fermer une fenêtre créée de cette façon –

+0

je sais que c'est une question ancienne mais cette approche encore Je n'ai qu'un seul problème - je l'utilise pour le chargement de la fenêtre - Montrer la fenêtre de chargement dans un nouveau fil -> faire des trucs -> newThread.Abort() et c'est ok mais si je le fais à nouveau il plante l'application entière. – MajkeloDev

+0

Salut, je me débattais avec ça aussi, pour moi, ça [link] (https://dontpaniclabs.com/blog/post/2013/11/14/dynamic -splash-screens-in-wpf /) a fonctionné.Cela utilise ManualResetEvent-way.Il y a une source à télécharger et vérifiez aussi (GitHub) – dba

2

Je pense que j'ai trouvé la réponse. Regardez la réponse de Jon Skeet dans ce question.

Fondamentalement, vous faites comme ceci dans votre méthode de démarrage de fil:

private void ThreadStartingPoint() 
{ 
    Window1 tempWindow = new Window1(); 
    tempWindow.Show();  
    System.Windows.Threading.Dispatcher.Run(); 
} 
+0

Oups .. à la fin, merci kek444. –

1

Exactement ce que je cherchais.

Je fais comme ça si:

App.xaml.cs

public partial class App : Application 
    { 
     protected override void OnStartup(StartupEventArgs e) 
     { 
      base.OnStartup(e); 

      Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint)); 
      newWindowThread.SetApartmentState(ApartmentState.STA); 
      newWindowThread.IsBackground = true; 
      newWindowThread.Start(); 

      var window = new MainWindow(newWindowThread); 
      window.DataContext = new MainWindowViewModel(window); 
      window.Show(); 
     } 

     private void ThreadStartingPoint() 
     { 
      SplashWindow tempWindow = new SplashWindow(); 
      tempWindow.Show(); 
      System.Windows.Threading.Dispatcher.Run(); 
     } 
    } 

MainWindow.Xaml.cs

public partial class MainWindow : Window 
{ 
    public MainWindow(Thread splashWindowThread) 
    { 
     InitializeComponent(); 

     MyInializaComponent(); 

     splashWindowThread.Abort(); 
    } 

//void DoStuff(){}; 
} 

je besoin de mon écran d'accueil pour aller après le programme a fait tout le chargement.

9

Pour tout ce que ça vaut, puisque cette réponse est le premier résultat fourni par Google. Je voudrais également ajouter ce qui suit pris de Eugene Prystupa's Weblog.

« Il y a un hic à notre solution simplifiée Fermeture d'une fenêtre particulière ne pas résilier fil de cette fenêtre répartiteur, de sorte que le fil continue à fonctionner et, après Fermant toutes les fenêtres, le processus ne se terminera pas et deviendra un processus fantôme.[La] solution simple (et non correcte) est de marquer nos threads en arrière-plan (en utilisant thread.IsBackground = true;). Cela les forcera à se terminer lorsque le thread principal de l'interface utilisateur se termine.

L'implémentation correcte arrêtera gracieusement le répartiteur lorsqu'il n'est plus nécessaire. Le code ci-dessous est un exemple d'une stratégie pour mettre fin au répartiteur lorsque la fenêtre se ferme:.? »

private void OnCreateNewWindow(object sender, RoutedEventArgs e) 
{ 
    Thread thread = new Thread(() => 
    { 
     Window1 w = new Window1(); 
     w.Show(); 

     w.Closed += (sender2, e2) => 
      w.Dispatcher.InvokeShutdown(); 

     System.Windows.Threading.Dispatcher.Run(); 
    }); 

    thread.SetApartmentState(ApartmentState.STA); 
    thread.Start(); 
} 
+1

Lien de référence similaire dans le cas où celui ci-dessus ne fonctionne plus: [Lancement d'une fenêtre WPF dans un thread séparé, partie 1] (http://reedcopsey.com/2011/11/28/launching-a-wpf-window-in -a-distinct-thread-partie-1 /) –

Questions connexes