2011-03-22 9 views
8

A WPF aplicación tiene una operación de carga de un control de usuario a partir de un archivo separado usando XamlReader.Load() método:XamlReader.Load en un hilo de fondo. ¿Es posible?

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

El proceso lleva algún tiempo debido al tamaño del archivo, de modo de interfaz de usuario se congela durante varios segundos.

Para mantener la aplicación receptiva trato de usar una hebra de fondo para realizar la parte de la operación que no está directamente invocada en la actualización de la IU.

Al intentar utilizar BackgroundWorker me dio un error: El subproceso de llamada debe ser STA, debido a que muchos componentes de interfaz de usuario requieren este

lo tanto, fui otra manera:

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; 
    } 

Este no resuelve nada porque todas las operaciones que consumen tiempo permanecen en el hilo de UI.

Cuando trato de este tipo, por lo que todos los análisis en segundo plano:

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; 
    } 

que tiene una excepción: El subproceso de llamada no se puede acceder a este objeto porque un subproceso diferente es el dueño. (en el UserControl cargado hay otros controles presentes que pueden dar el error)

¿Hay alguna manera de realizar esta operación de tal manera que la IU responda?

+0

Utilice backgroundworker, asegúrese de que si va a modificar (establecer/agregar) cualquiera de los objetos que no están dentro del alcance en lugar del hilo en el que trabaja el Backgroundworker, usa una función/func o delegue ese trabajo y no intente configurarlo en el hilo de backgroundworker. Si algo hace su trabajo en su lugar el backgroundworker y cuando haya terminado tome el resultado (e.result) en el evento/método OnComplete y actualice su objeto en el subproceso UI. – Landern

Respuesta

7

Lograr que el XAML cargue un hilo de fondo no es esencialmente un iniciador. Los componentes de WPF tienen una afinidad de subprocesos y, en general, solo se pueden usar a partir de los subprocesos en los que se crean. Por lo tanto, al cargar en un subproceso en segundo plano, la interfaz de usuario responderá pero creará componentes que luego no podrán conectarse a la secuencia de la interfaz de usuario.

La mejor opción que tiene aquí es dividir el archivo XAML en trozos más pequeños y cargarlos incrementalmente en el subproceso de la interfaz de usuario, asegurándose de permitir una bomba de mensajes entre cada operación de carga. Posiblemente usando BeginInvoke en el objeto Dispatcher para programar las cargas.

2

Como descubriste, no puedes usar XamlReader.Load a menos que el hilo sea STA e incluso si lo es, tendrás que hacer que inicie un mensaje de bomba y canalizar todo el acceso a los controles que creó a través de eso. Esta es una forma fundamental de cómo funciona WPF y no se puede ir en contra.

Así que sus únicas opciones reales son:

  1. hueco por la XAML en trozos más pequeños.
  2. Inicia un nuevo hilo STA para cada llamada Load. Después de que Load regresa, el subproceso tendrá que iniciar un ciclo de mensajes y administrar los controles que creó. Su aplicación deberá tener en cuenta el hecho de que diferentes controles son ahora propiedad de diferentes hilos.
0

sistema. Xaml tiene una clase Xaml​Background​Reader, tal vez podría hacer que funcione para usted. Analice el XAML en el hilo de fondo pero construya los objetos en el hilo de UI.

Cuestiones relacionadas