2010-05-04 13 views
10

Tengo un método que crea un hilo de fondo para realizar alguna acción. En este hilo de fondo, creo un objeto. Pero este objeto durante la creación en tiempo de ejecución me da una excepción:¿Cómo puedo crear controles WPF en un hilo de fondo?

El hilo que llama debe ser STA, porque muchos componentes de la interfaz de usuario lo requieren.

Sé que debo usar Dispatcher para que se refleje algo en la IU. Pero en este caso, simplemente creo un objeto y no interactúo con UI. Este es mi código:

public void SomeMethod() 
     { 
     BackgroundWorker worker = new BackgroundWorker(); 
     worker.DoWork += new DoWorkEventHandler(Background_Method); 
     worker.RunWorkerAsync(); 
     } 

    void Background_Method(object sender, DoWorkEventArgs e) 
     { 
     TreeView tv = new TreeView(); 
     } 

¿Cómo puedo crear objetos en el hilo de fondo?

utilizo aplicación WPF

+0

Una pregunta más: ¿es posible que el método del trabajador de referencia devuelva algún valor de tipo específico? – Polaris

+2

comprueba la propiedad e.Result en el método RunWorkerCompleted. http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx. – Amsakanna

Respuesta

6

TreeView es un control de interfaz de usuario. Solo puede crear y manipular controles de interfaz de usuario en un hilo de UI, por lo que lo que intenta hacer no es posible.

Lo que quiere hacer es hacer todo el trabajo que consume mucho tiempo en el subproceso en segundo plano, y luego "devolver la llamada" al subproceso de la interfaz de usuario para manipular la interfaz de usuario. Esto es realmente muy fácil:

void Background_Method(object sender, DoWorkEventArgs e) 
{ 
    // ... time consuming stuff... 

    // call back to the window to do the UI-manipulation 
    this.BeginInvoke(new MethodInvoker(delegate { 
     TreeView tv = new TreeView(); 
     // etc, manipulate 
    })); 
} 

pude haber conseguido la sintaxis incorrecta para BeginInvoke (que es la parte superior de la cabeza), pero hay que ir de todos modos ...

+0

Obtengo algunos datos del servicio web y el tiempo de ejecución pasa mucho tiempo para ello. Por eso quiero obtener datos en segundo plano y generar mi treeView cuando los datos estén listos. – Polaris

+0

He actualizado mi respuesta con algunos comentarios más sobre cómo puede hacer cosas en el hilo de la interfaz de usuario de un hilo de trabajo. –

0

Para hacer que su código simplemente trabajar , debe unirse a un apartamento STA COM llamando al Thread.SetApartmentState(ApartmentState.STA). Dado que BackgroundWorker probablemente esté utilizando un grupo de subprocesos compartidos, unirse a un apartamento en particular puede afectar a otros usuarios de este grupo de subprocesos o incluso puede fallar si ya se configuró en p. Ej. MTA antes. Incluso si todo salió bien, su recién creado TreeView se bloquearía en esta cadena de trabajo. No podría usarlo en su hilo de interfaz de usuario principal.

Si explicó con más detalle acerca de sus verdaderas intenciones, seguramente obtendrá una mejor ayuda.

0

intente seguir Código:

public void SomeMethod() 
{ 

System.ComponentModel.BackgroundWorker myWorker = new System.ComponentModel.BackgroundWorker(); 

myWorker.DoWork += myWorker_DoWork; 

myWorker.RunWorkerAsync(); 

} 

private void myWorker_DoWork(object sender, 
    System.ComponentModel.DoWorkEventArgs e) 
{ 
    // Do time-consuming work here 
} 
3

HTH:

void Background_Method(object sender, DoWorkEventArgs e) 
    { 
     // Time Consuming operations without using UI elements 
     // Result of timeconsuming operations 
     var result = new object(); 
     App.Current.Dispatcher.Invoke(new Action<object>((res) => 
      { 
       // Working with UI 
       TreeView tv = new TreeView(); 
      }), result); 
    } 
0
void Background_Method(object sender, DoWorkEventArgs e) 
{ 
    TreeView tv = new TreeView(); 
    // Generate your TreeView here 
    UIDispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => 
    { 
     someContainer.Children.Add(tv); 
    }; 
} 
0

I resuelto mi problema. Acabo de utilizar la propiedad e.Result del método RunWorkerCompleted. Obtengo datos en el hilo de fondo y luego uso estos datos cuando se completa el hilo. Agradezca a cada cuerpo por los métodos útiles. Gracias especiales a Veer por dar una recomendación acerca de la propiedad e.Result.

+0

Si desea actualizar su UI en algunos intervalos, puede usar el parámetro UserState del método ReportProgress para enviar sus datos y usarlos en su método ProgressChanged enviando e.UserState al tipo requerido. – Amsakanna

0

Nadie está discutiendo el caso de un subproceso STA independiente en los detalles (aunque el concepto es exactamente el mismo).

Así que imaginemos un simple control de ficha añadió a un clic de botón

private void button_Click(object sender, RoutedEventArgs e) 
    { 
     TabItem newTab = new TabItem() { Header = "New Tab" }; 
     tabMain.Items.Add(newTab); 
    } 

Si nos movemos a otro subproceso STA

private void button_Click(object sender, RoutedEventArgs e) 
    { 
     Thread newThread = new Thread(new ThreadStart(ThreadStartingPoint)); 
     newThread.SetApartmentState(ApartmentState.STA); 
     newThread.IsBackground = true; 
     newThread.Start(); 
    } 
    private void ThreadStartingPoint() 
    { 
     TabItem newTab = new TabItem() { Header = "New Tab" }; 
     tabMain.Items.Add(newTab); 
    } 

por supuesto tenemos una System.InvalidOperationException

Ahora, ¿Qué ocurre si agregamos el control

private void AddToParent(string header) 
    { 
     TabItem newTab = new TabItem() { Header = header }; 
     tabMain.Items.Add(newTab); 
    } 

usando un método delegado?

public void DelegateMethod(string header) 
    { 
     tabMain.Dispatcher.BeginInvoke(
       new Action(() => { 
        this.AddToParent(header); 
       }), null); 
    } 

que hace el trabajo si usted lo llama

private void button_Click(object sender, RoutedEventArgs e) 
    { 
     Thread newThread = new Thread(new ThreadStart(ThreadStartingPoint)); 
     newThread.SetApartmentState(ApartmentState.STA); 
     newThread.IsBackground = true; 
     newThread.Start(); 
    } 
    private void ThreadStartingPoint() 
    { 
     DelegateMethod("new tab"); 
    } 

porque claro ahora mantenemos el árbol visual en el mismo hilo original.

Cuestiones relacionadas