Domanda

Un'applicazione WPF è un'operazione di caricamento di un controllo utente da un file separato utilizzando XamlReader.Load() metodo:

StreamReader mysr = new StreamReader(pathToFile);
DependencyObject rootObject = XamlReader.Load(mysr.BaseStream) as DependencyObject;
ContentControl displayPage = FindName("displayContentControl") as ContentControl;
displayPage.Content = rootObject;

Il processo richiede un certo tempo, a causa della dimensione del file, in modo UI diventa congelato per diversi secondi.

Per mantenere l'app reattivo cerco di usare un thread in Background per eseguire la parte di operazione, che non è direttamente coinvolte in l'aggiornamento dell'interfaccia utente.

Quando si tenta di utilizzare BackgroundWorker Ho ottenuto un errore: Il thread chiamante deve essere PERSONALE, perché molti componenti dell'interfaccia utente di richiedere questo

Così, sono andato in un altro modo:

 private Thread _backgroundThread;
 _backgroundThread = new Thread(DoReadFile);
 _backgroundThread.SetApartmentState(ApartmentState.STA);
 _backgroundThread.Start();
 void DoReadFile()
 {
   StreamReader mysr3 = new StreamReader(path2);
   Dispatcher.BeginInvoke(
           DispatcherPriority.Normal,
           (Action<StreamReader>)FinishedReading,
           mysr3);
 }

 void FinishedReading(StreamReader stream)
    {            
        DependencyObject rootObject = XamlReader.Load(stream.BaseStream) as DependencyObject;
        ContentControl displayPage = FindName("displayContentControl") as ContentControl;
        displayPage.Content = rootObject;
    }

Questo non risolve nulla perché tutto il tempo di consumare le operazioni di rimanere nel thread dell'interfaccia utente.

Quando cerco come questo, e facendo tutte le analisi in background:

private Thread _backgroundThread;
_backgroundThread = new Thread(DoReadFile);
_backgroundThread.SetApartmentState(ApartmentState.STA);
_backgroundThread.Start();
 void DoReadFile()
 {
  StreamReader mysr3 = new StreamReader(path2);      
  DependencyObject rootObject3 = XamlReader.Load(mysr3.BaseStream) as DependencyObject;
        Dispatcher.BeginInvoke(
           DispatcherPriority.Normal,
           (Action<DependencyObject>)FinishedReading,
           rootObject3);
  }

  void FinishedReading(DependencyObject rootObject)
  {            
    ContentControl displayPage = FindName("displayContentControl") as ContentControl;
    displayPage.Content = rootObject;
  } 

Ho avuto un'eccezione: Il thread chiamante non può accedere a questo oggetto, perché un thread diverso proprietario. (caricato UserControl ci sono altri controlli presenti che, magari, di dare l'errore)

C'è un modo per eseguire questa operazione in modo che l'interfaccia utente sia reattivo?

È stato utile?

Soluzione

Far caricarlo a XAML un thread di sfondo è essenzialmente un non-avviamento. I componenti WPF hanno un'affinità dei thread e sono generalmente parlando solo dai thread che ne sono creati uno. Quindi il caricamento su un thread di sfondo renderà l'interfaccia utente reattiva ma creerà componenti che non possono essere collegati al thread dell'interfaccia utente.

L'opzione migliore che hai qui è di rompere il file XAML in pezzi più piccoli e caricarli in modo incrementale nel thread dell'interfaccia utente assicurandoti di consentire una pompa di messaggio tra ogni operazione di carico. Forse usando BeginInvoke sul Dispatcher obiettare per programmare i carichi.

Altri suggerimenti

Come hai scoperto, non puoi usare XamlReader.Load A meno che il thread non sia STA e anche se lo è, dovrai avviare una pompa del messaggio e imbuto tutto l'accesso ai controlli creati attraverso quello. Questo è un modo fondamentale di come funziona WPF e non puoi andare contro di esso.

Quindi le tue uniche opzioni reali sono:

  1. Abbattere lo XAML in pezzi più piccoli.
  2. Avvia un nuovo thread STA per ciascuno Load chiamata. Dopo Load Restituisce, il thread dovrà avviare un ciclo di messaggi e gestire i controlli creati. La tua applicazione dovrà tenere conto del fatto che diversi controlli sono ora di proprietà di diversi thread.

Sistema.Xaml è un Xaml​Background​Reader classe, forse si potrebbe ottenere a lavorare per voi.Parser XAML sul thread in background, ma creare gli oggetti sul thread UI.

Puoi chiamare un metodo che consente di dare il controllo a un altro thread:

http://msdn.microsoft.com/en-us/library/ms748331.aspx

Si chiama .freeze ()

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top