tutorial que programacion principiantes para mvvc modelo implementar español ejemplo como .net wpf multithreading mvvm

.net - que - wpf como implementar mvvm



Asegurándose de que se llama a OnPropertyChanged() en el subproceso de interfaz de usuario en la aplicación MVVM WPF (5)

Esto es más una extensión de la respuesta aceptada, pero lo hice con mi ejecutor de eventos ...

using System.Threading; private void Handler(object sender, RoutedEventArgs e) { if (Thread.CurrentThread == this.Dispatcher.Thread) { //do stuff to this } else { this.Dispatcher.Invoke( new Action<object, RoutedEventArgs>(Handler), sender, e); } }

En una aplicación WPF que escribo usando el patrón MVVM, tengo un proceso en segundo plano que hace las cosas, pero necesita obtener actualizaciones de estado de la interfaz de usuario.

Estoy usando el patrón MVVM, por lo que mi ViewModel no conoce prácticamente nada de la vista (UI) que presenta el modelo al usuario.

Supongamos que tengo el siguiente método en mi ViewModel:

public void backgroundWorker_ReportProgress(object sender, ReportProgressArgs e) { this.Messages.Add(e.Message); OnPropertyChanged("Messages"); }

En mi opinión, tengo un ListBox vinculado a la propiedad Messages (a List<string> ) del ViewModel. OnPropertyChanged cumple la función de la interfaz INotifyPropertyChanged llamando a PropertyChangedEventHandler .

Necesito asegurarme de que OnPropertyChanged se OnPropertyChanged en el hilo de UI. ¿Cómo hago esto? He intentado lo siguiente:

public Dispatcher Dispatcher { get; set; } public MyViewModel() { this.Dispatcher = Dispatcher.CurrentDispatcher; }

A continuación, agregue lo siguiente al método OnPropertyChanged :

if (this.Dispatcher != Dispatcher.CurrentDispatcher) { this.Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(delegate { OnPropertyChanged(propertyName); })); return; }

pero esto no funciono. ¿Algunas ideas?


Manejo el evento BackgroundWorker.ReportProgress fuera de mi modelo de vista y paso la instancia actual de BackgroundWorker y ViewModel a mi clase que define los métodos de asincronización.

El método asynch luego llama a bgWorker.ReportProgress y pasa una clase que envuelve a un delegado como el estado del usuario (como objeto). El delegado lo escribo como un método anónimo.

En el controlador de eventos, lo lanzo desde el objeto al tipo de envoltura y luego invoco al delegado dentro.

Todo esto significa que puedo codificar los cambios de la interfaz de usuario directamente desde el código que se ejecuta de forma asíncrona, pero solo tiene este ajuste.

Esto explica con más detalle:

http://lukepuplett.blogspot.com/2009/05/updating-ui-from-asynchronous-ops.html


REALMENTE ME GUSTA la respuesta de Jeremy: Despachar en Silverlight

Resumen:

  • Colocar Dispatcher en ViewModel parece poco elegante

  • Creando una propiedad de Acción <Acción>, configúrelo solo para ejecutar la acción en el constructor de VM

  • Al usar la máquina virtual de la V, establezca la propiedad Acción para invocar al distribuidor

Tuve un escenario similar justo esta semana (MVVM aquí también). Tuve una clase aparte haciendo su trabajo, informando sobre el estado en un controlador de eventos. El controlador de eventos se llamaba como se esperaba, y pude ver que los resultados llegaban justo a tiempo con Debug.WriteLine .

Pero con WPF, no importaba lo que hiciera, la IU no se actualizaría hasta que el proceso estuviera completo. Tan pronto como finalice el proceso, la IU se actualizará como se espera. Era como si obtuviera PropertyChanged, pero esperando que se complete el subproceso antes de realizar todas las actualizaciones de UI a la vez.

(Para mi gran consternación, el mismo código en Windows.Forms con un DoEvents y .Refresh () funcionaba como un amuleto).

Hasta ahora, he resuelto esto comenzando el proceso en su propio hilo:

//hook up event handler myProcess.MyEvent += new EventHandler<MyEventArgs>(MyEventHandler); //start it on a thread ... ThreadStart threadStart = new ThreadStart(myProcess.Start); Thread thread = new Thread(threadStart); thread.Start();

y luego en el controlador de eventos:

private void MyEventHandler(object sender, MyEventArgs e) { .... Application.Current.Dispatcher.Invoke( DispatcherPriority.Send, (DispatcherOperationCallback)(arg => { //do UI updating here ... }), null);

No recomiendo este código, ya que todavía estoy tratando de entender el modelo de subproceso de WPF, cómo funciona Dispatcher y por qué en mi caso la IU no se actualizaría hasta que el proceso se completara incluso con el manejador de eventos que se llamaba como se esperaba ( ¿por diseño?). Pero esto ha funcionado para mí hasta ahora.

Encontré estos dos enlaces útiles:

http://www.nbdtech.com/blog/archive/2007/08/01/Passing-Wpf-Objects-Between-Threads-With-Source-Code.aspx

http://srtsolutions.com/blogs/mikewoelmer/archive/2009/04/17/dealing-with-unhandled-exceptions-in-wpf.aspx


WPF automáticamente clasifica los cambios de propiedad en el subproceso de interfaz de usuario. Sin embargo, no coordina los cambios en la recopilación, por lo que sospecho que agregar un mensaje está causando la falla.

Puede ordenar el complemento manualmente (vea el ejemplo a continuación) o usar algo como esta técnica que publiqué hace un tiempo.

Marcalización manual:

public void backgroundWorker_ReportProgress(object sender, ReportProgressArgs e) { Dispatcher.Invoke(new Action<string>(AddMessage), e.Message); OnPropertyChanged("Messages"); } private void AddMessage(string message) { Dispatcher.VerifyAccess(); Messages.Add(message); }