it-swarm-es.tech

Manejo de diálogos en WPF con MVVM

En el patrón MVVM para WPF, el manejo de los diálogos es una de las operaciones más complejas. Como su modelo de vista no sabe nada sobre la vista, la comunicación de diálogo puede ser interesante. Puedo exponer un ICommand que cuando la vista lo invoca, puede aparecer un diálogo.

¿Alguien sabe de una buena manera de manejar los resultados de los diálogos? Me refiero a los diálogos de windows como MessageBox.

Una de las formas en que lo hicimos fue tener un evento en el modelo de vista al que la vista se suscribiría cuando se requería un diálogo.

public event EventHandler<MyDeleteArgs> RequiresDeleteDialog;

Esto está bien, pero significa que la vista requiere un código que es algo de lo que me gustaría estar alejado.

226
Ray Booysen

Sugiero dejar de lado los diálogos modales de la década de 1990 y en su lugar implementar un control como superposición (lienzo + posicionamiento absoluto) con visibilidad vinculada a un booleano en la máquina virtual. Más cerca de un control de tipo ajax.

Esto es muy útil:

<BooleanToVisibilityConverter x:Key="booltoVis" />

como en:

<my:ErrorControl Visibility="{Binding Path=ThereWasAnError, Mode=TwoWay, Converter={StaticResource booltoVis}, UpdateSourceTrigger=PropertyChanged}"/>

Así es como tengo uno implementado como control de usuario. Al hacer clic en la 'x' se cierra el control en una línea de código en el código del control de usuario que está detrás. (Dado que tengo mis vistas en un archivo .exe y ViewModels en una DLL, no me siento mal por el código que manipula la interfaz de usuario).

Wpf dialog

130
Jeffrey Knight

Deberías usar un mediador para esto. El mediador es un patrón de diseño común también conocido como Messenger en algunas de sus implementaciones. Es un paradigma de tipo Registrar/Notificar y permite que su ViewModel y Vistas se comuniquen a través de un mecanismo de mensajería de acoplamiento bajo.

Debes revisar el grupo de Discípulos de WPF de Google y solo buscar el Mediador. Estarás muy contento con las respuestas ...

Sin embargo puedes comenzar con esto:

http://joshsmithonwpf.wordpress.com/2009/04/06/a-mediator-prototype-for-wpf-apps/

Disfrutar

Edición: puede ver la respuesta a este problema con el MVVM Light Toolkit aquí:

http://mvvmlight.codeplex.com/Thread/View.aspx?ThreadId=209338

51
Roubachof

Un buen diálogo de MVVM debería:

  1. Ser declarado con sólo XAML.
  2. Obtener todo su comportamiento de enlace de datos.

Desafortunadamente, WPF no proporciona estas características. Mostrar un cuadro de diálogo requiere una llamada de código subyacente a ShowDialog (). La clase de ventana, que admite diálogos, no se puede declarar en XAML, por lo que no se puede enlazar fácilmente con DataContext.

Para resolver esto, escribí un control de código auxiliar XAML que se encuentra en el árbol lógico y transmite el enlace de datos a una ventana y maneja mostrar y ocultar el cuadro de diálogo. Puede encontrarlo aquí: http://www.codeproject.com/KB/WPF/XAMLDialog.aspx

Es realmente simple de usar y no requiere cambios extraños en su ViewModel y no requiere eventos o mensajes. La llamada básica se ve así:

<dialog:Dialog Content="{Binding Path=DialogViewModel}" Showing="True" />

Probablemente quieras agregar un estilo que establezca Mostrar. Lo explico en mi artículo. Espero que esto te ayude.

29
user92541

Yo uso este enfoque para diálogos con MVVM.

Todo lo que tengo que hacer ahora es llamar lo siguiente desde mi modelo de vista.

var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);
23
blindmeis

Mi solución actual resuelve la mayoría de los problemas que mencionó, pero está completamente abstraída de elementos específicos de la plataforma y se puede reutilizar. Además, no utilicé ningún enlace de código detrás solo con DelegateCommands que implementa ICommand. El diálogo es básicamente una vista: un control independiente que tiene su propio ViewModel y se muestra desde el ViewModel de la pantalla principal pero se activa desde la interfaz de usuario a través del enlace DelagateCommand.

Vea la solución completa de Silverlight 4 aquí Diálogos modales con MVVM y Silverlight 4

16
Roboblob

Realmente luché con este concepto por un tiempo cuando aprendía (todavía estoy aprendiendo) MVVM. Lo que decidí, y lo que creo que otros ya decidieron pero que no estaba claro para mí es lo siguiente:

Mi idea original fue que no se debería permitir que un ViewModel llame a un cuadro de diálogo directamente, ya que no tiene por qué decidir cómo debe aparecer un diálogo. Debido a esto, comencé a pensar en cómo podría pasar mensajes como lo haría en MVP (es decir, View.ShowSaveFileDialog ()). Sin embargo, creo que este es el enfoque equivocado.

Está bien que un ViewModel llame directamente a un diálogo. Sin embargo, cuando está probando un ViewModel, eso significa que el cuadro de diálogo aparecerá durante su prueba o fallará por completo (nunca lo intenté realmente).

Por lo tanto, lo que debe suceder es que durante la prueba se use una versión de "prueba" de su diálogo. Esto significa que para cada diálogo que tenga, debe crear una Interfaz y simular la respuesta del diálogo o crear un simulacro de prueba que tendrá un comportamiento predeterminado.

Ya debería estar utilizando algún tipo de Localizador de servicios o IoC que puede configurar para proporcionarle la versión correcta según el contexto.

Usando este enfoque, su ViewModel aún se puede probar y, dependiendo de cómo se burle de sus diálogos, puede controlar el comportamiento.

Espero que esto ayude.

6
Mike Rowley

Hay dos buenas maneras de hacer esto: 1) un servicio de diálogo (fácil, limpio) y 2) con asistencia. La vista asistida proporciona algunas características interesantes, pero generalmente no vale la pena.

SERVICIO DE DIALOGO

a) una interfaz de servicio de diálogo como a través de un constructor o algún contenedor de dependencia:

interface IDialogService { Task ShowDialogAsync(DialogViewModel dlgVm); }

b) Su implementación de IDialogService debería abrir una ventana (o inyectar algo de control en la ventana activa), crear una vista correspondiente al nombre del tipo dlgVm dado (usar registro o convención del contenedor o un ContentPresenter con el tipo de Plantillas de Datos asociado). ShowDialogAsync debe crear un TaskCompletionSource y devolver su dominio .Task. La propia clase DialogViewModel necesita un evento que pueda invocar en la clase derivada cuando desee cerrar, y ver en la vista de diálogo para cerrar/ocultar el cuadro de diálogo y completar el TaskCompletionSource.

b) Para usar, simplemente llame a wait this.DialogService.ShowDialog (myDlgVm) en su instancia de alguna clase derivada de DialogViewModel. Después de esperar devoluciones, mire las propiedades que ha agregado en su diálogo VM para determinar qué sucedió; Ni siquiera necesitas una devolución de llamada.

VER AYUDA

Esto tiene su vista escuchando un evento en el modelo de vista. Todo esto podría incluirse en un Comportamiento de mezcla para evitar el uso de código y recursos si lo desea (FMI, subclase de la clase "Comportamiento" para ver una especie de propiedad adjunta de Blendable en esteroides). Por ahora, haremos esto manualmente en cada vista:

a) Cree un OpenXXXXXDialogEvent con una carga útil personalizada (una clase derivada de DialogViewModel).

b) Haga que la vista se suscriba al evento en su evento OnDataContextChanged. Asegúrese de ocultar y cancelar la suscripción si el valor anterior! = Nulo y en el evento Sin carga de la ventana.

c) Cuando se dispare el evento, haga que la vista abra su vista, que podría estar en un recurso en su página, o podría ubicarla por convención en otro lugar (como en el enfoque del servicio de diálogo).

Este enfoque es más flexible, pero requiere más trabajo para utilizar. No lo uso mucho. La única ventaja de Niza es la capacidad de colocar la vista físicamente dentro de una pestaña, por ejemplo. He utilizado un algoritmo para colocarlo en los límites del control del usuario actual, o si no es lo suficientemente grande, recorrer el árbol visual hasta que se encuentre un contenedor lo suficientemente grande.

Esto permite que los diálogos estén cerca del lugar en el que realmente se usan, solo atenúa la parte de la aplicación relacionada con la actividad actual, y permite al usuario moverse dentro de la aplicación sin tener que presionar manualmente los diálogos, incluso tener varios cuasi. Los diálogos modales se abren en diferentes pestañas o sub-vistas.

5
Chris Bordeman

Utilice un comando de congelación

<Grid>
        <Grid.DataContext>
            <WpfApplication1:ViewModel />
        </Grid.DataContext>


        <Button Content="Text">
            <Button.Command>
                <WpfApplication1:MessageBoxCommand YesCommand="{Binding MyViewModelCommand}" />
            </Button.Command>
        </Button>

</Grid>
public class MessageBoxCommand : Freezable, ICommand
{
    public static readonly DependencyProperty YesCommandProperty = DependencyProperty.Register(
        "YesCommand",
        typeof (ICommand),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata(null)
        );


    public static readonly DependencyProperty OKCommandProperty = DependencyProperty.Register(
        "OKCommand",
        typeof (ICommand),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata(null)
        );


    public static readonly DependencyProperty CancelCommandProperty = DependencyProperty.Register(
        "CancelCommand",
        typeof (ICommand),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata(null)
        );


    public static readonly DependencyProperty NoCommandProperty = DependencyProperty.Register(
        "NoCommand",
        typeof (ICommand),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata(null)
        );


    public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
        "Message",
        typeof (string),
        typeof (MessageBoxCommand),
        new FrameworkPropertyMetadata("")
        );

    public static readonly DependencyProperty MessageBoxButtonsProperty = DependencyProperty.Register(
        "MessageBoxButtons",
        typeof(MessageBoxButton),
        typeof(MessageBoxCommand),
        new FrameworkPropertyMetadata(MessageBoxButton.OKCancel)
        );

    public ICommand YesCommand
    {
        get { return (ICommand) GetValue(YesCommandProperty); }
        set { SetValue(YesCommandProperty, value); }
    }

    public ICommand OKCommand
    {
        get { return (ICommand) GetValue(OKCommandProperty); }
        set { SetValue(OKCommandProperty, value); }
    }

    public ICommand CancelCommand
    {
        get { return (ICommand) GetValue(CancelCommandProperty); }
        set { SetValue(CancelCommandProperty, value); }
    }

    public ICommand NoCommand
    {
        get { return (ICommand) GetValue(NoCommandProperty); }
        set { SetValue(NoCommandProperty, value); }
    }

    public MessageBoxButton MessageBoxButtons
    {
        get { return (MessageBoxButton)GetValue(MessageBoxButtonsProperty); }
        set { SetValue(MessageBoxButtonsProperty, value); }
    }

    public string Message
    {
        get { return (string) GetValue(MessageProperty); }
        set { SetValue(MessageProperty, value); }
    }

    public void Execute(object parameter)
    {
        var messageBoxResult = MessageBox.Show(Message);
        switch (messageBoxResult)
        {
            case MessageBoxResult.OK:
                OKCommand.Execute(null);
                break;
            case MessageBoxResult.Yes:
                YesCommand.Execute(null);
                break;
            case MessageBoxResult.No:
                NoCommand.Execute(null);
                break;
            case MessageBoxResult.Cancel:
                if (CancelCommand != null) CancelCommand.Execute(null); //Cancel usually means do nothing ,so can be null
                break;

        }
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;


    protected override Freezable CreateInstanceCore()
    {
        throw new NotImplementedException();
    }
}
4
Maxm007

Una alternativa interesante es usar controladores que sean responsables de mostrar las vistas (diálogos).

La forma en que funciona esto se muestra enWPF Application Framework (WAF).

3
jbe

He implementado un comportamiento que escucha un mensaje de ViewModel. Se basa en la solución de Laurent Bugnion, pero como no usa el código detrás y es más reutilizable, creo que es más elegante.

Cómo hacer que WPF se comporte como si MVVM fuera compatible de la caja

3
Elad Katz

¿Por qué no solo elevar un evento en el VM y suscribirse al evento en la vista? Esto mantendría la lógica de la aplicación y la vista separadas y aún así le permitiría usar una ventana secundaria para los diálogos.

3
Eric Grover

Creo que el manejo de un diálogo debe ser responsabilidad de la vista, y la vista debe tener un código que lo respalde.

Si cambia la interacción ViewModel - View para manejar los diálogos, entonces ViewModel depende de esa implementación. La forma más sencilla de resolver este problema es hacer que View sea responsable de realizar la tarea. Si eso significa mostrar un diálogo, entonces está bien, pero también podría ser un mensaje de estado en la barra de estado, etc.

Mi punto es que todo el punto del patrón MVVM es separar la lógica empresarial de la GUI, por lo que no debe mezclar la lógica GUI (para mostrar un diálogo) en la capa empresarial (el ViewModel).

3
Cameron MacFarland

Creo que la vista podría tener un código para manejar el evento desde el modelo de vista.

Según el evento/escenario, también podría tener un desencadenante de evento que se suscriba para ver eventos del modelo y una o más acciones para invocar en respuesta.

2
Nikhil Kothari

Tuve la misma situación y envolví el MessageBox en un control invisible del diseñador. Los detalles estan en mi blog.

http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx

Lo mismo se puede extender a cualquier diálogo modal, control de búsqueda de archivos, etc.

2
mukapu

Karl Shifflett ha creado una aplicación de ejemplo para mostrar cuadros de diálogo utilizando el enfoque de servicio y el enfoque Prism InteractionRequest.

Me gusta el enfoque de servicio: es menos flexible, por lo que es menos probable que los usuarios rompan algo :) También es coherente con la parte de WinForms de mi aplicación (MessageBox.Show). Pero si planea mostrar muchos diálogos diferentes, InteractionRequest es un mejor manera de ir.

http://karlshifflett.wordpress.com/2010/11/07/in-the-box-ndash-mvvm-training/

1
surfen

Sé que es una pregunta antigua, pero cuando hice esta búsqueda, encontré muchas preguntas relacionadas, pero no encontré una respuesta muy clara. ¡Así que hago mi propia implementación de un cuadro de diálogo/mensaje/popin, y lo comparto!
Creo que es "a prueba de MVVM", y trato de hacerlo simple y apropiado, pero soy nuevo en WPF, así que siéntase libre de comentar, o incluso hacer una solicitud de extracción.

https://github.com/Plasma-Paris/Plasma.WpfUtils

Puedes usarlo así:

public RelayCommand YesNoMessageBoxCommand { get; private set; }
async void YesNoMessageBox()
{
    var result = await _Service.ShowMessage("This is the content of the message box", "This is the title", System.Windows.MessageBoxButton.YesNo);
    if (result == System.Windows.MessageBoxResult.Yes)
        // [...]
}

O así si quieres popin más sofisticado:

var result = await _Service.ShowCustomMessageBox(new MyMessageBoxViewModel { /* What you want */ });

Y está mostrando cosas como esta:

2

1
Xav987

Después de pasar un tiempo con esto, finalmente se me ocurrió la siguiente solución. Algunas ventajas clave de este enfoque son:

  1. Implementa la propia IDialogService de MVVM Light.
  2. La vista no necesita agregar la referencia de MVVM Light.
  3. VM no necesita hacer ninguna actividad de nivel de presentación. Ni siquiera necesita PresentationFramework referencia.
  4. Utiliza el canal de Messenger de MVVM Light, por lo que la presentación y VM capas se desacoplan.
  5. Admite diálogos con un valor de retorno, como preguntas Sí/No o situaciones Aceptar/Cancelar.
  6. Soporta diálogos personalizados.

Aquí está la implementación de IDialogService (entra en ViewModel project):

using System;
using System.Linq;
using System.Threading.Tasks;

namespace VM
{
  public enum MessageBoxButtonVM
  {
    OK,
    OKCancel,
    YesNo
  }

  public enum MessageBoxImageVM
  {
    None,
    Information,
    Question,
    Error
  }

  public class MessageBoxArgs
  {
    public MessageBoxButtonVM Buttons { get; set; }
    public MessageBoxImageVM Icon { get; set; }
    public string Title { get; set; }
    public string Message { get; set; }
  }

  //For custom dialogs that return a value
  public class MessageBoxNotificationWithAction<T>
  {
    private readonly Action<T> _callback;

    public MessageBoxArgs Notification { get; set; }

    public MessageBoxNotificationWithAction(MessageBoxArgs notification, Action<T> callback)
    {
      Notification = notification;

      CheckCallback(callback);
      _callback = callback;
    }

    public virtual void Execute(T argument)
    {
      _callback.Invoke(argument);
    }

    private static void CheckCallback(Delegate callback)
    {
      if (callback == null)
      {
        throw new ArgumentNullException(nameof(callback), "Callback must not be null");
      }
    }
  }

  /// <summary>
  /// Provides an implementation-agnostic way of communicating with the user through dialog boxes. Clients must register for communication messages using
  /// MVVM Light messaging system.
  /// </summary>
  public class DialogService : GalaSoft.MvvmLight.Views.IDialogService
  {
    private static GalaSoft.MvvmLight.Messaging.IMessenger Messenger = GalaSoft.MvvmLight.Messaging.Messenger.Default;

    private string _ProductName = "";

    public string ProductName
    {
      get
      {
        if (_ProductName == "")
        {
          //The following statement returns the Title attribute of the current Assembly, as defined in project properties (Assembly Information dialog).
          var TitleAttrib = System.Reflection.Assembly.GetExecutingAssembly().GetCustomAttributesData().First(x => x.AttributeType.Name == "AssemblyTitleAttribute");

          if (TitleAttrib != null)
          {
            _ProductName = TitleAttrib.ConstructorArguments[0].Value.ToString();
          }
          else
          {
            _ProductName = "Default Application Name";
          }
        }

        return _ProductName;
      }
    }

    public Task ShowError(Exception error, string title, string buttonText, Action afterHideCallback)
    {
      return ShowError(error.Message, title, buttonText, afterHideCallback);
    }

    public Task ShowMessage(string message, string title)
    {
      return Task.Run(() => MessengerSend(message, title, MessageBoxButtonVM.OK, MessageBoxImageVM.Error));
    }

    public Task ShowError(string message, string title, string buttonText, Action afterHideCallback)
    {
      return Task.Run(() =>
      {
        MessengerSend(message, title, MessageBoxButtonVM.OK, MessageBoxImageVM.Error);
        afterHideCallback?.Invoke();
      });
    }

    public Task ShowMessage(string message, string title, string buttonText, Action afterHideCallback)
    {
      return Task.Run(() =>
      {
        MessengerSend(message, title);
        afterHideCallback?.Invoke();
      });
    }

    public Task<bool> ShowMessage(string message, string title, string buttonConfirmText, string buttonCancelText, Action<bool> afterHideCallback)
    {
      if ((buttonConfirmText == "OK" && buttonCancelText == "Cancel") ||
        (buttonConfirmText == "Yes" && buttonCancelText == "No"))
      {
        return Task.Run<bool>(() =>
        {
          MessageBoxButtonVM btn;
          if (buttonConfirmText == "OK")
            btn = MessageBoxButtonVM.OKCancel;
          else
            btn = MessageBoxButtonVM.YesNo;


          bool Response = false;
          Messenger.Send(new MessageBoxNotificationWithAction<bool>(
                                                      new MessageBoxArgs()
                                                      {
                                                        Buttons = btn,
                                                        Icon = MessageBoxImageVM.Question,
                                                        Title = (string.IsNullOrEmpty(title) ? _ProductName : title),
                                                        Message = message
                                                      },
                                                      (result) => Response = result
                                                        ));

          afterHideCallback?.Invoke(Response);

          return Response;
        });
      }
      else
        throw new ArgumentException($"{nameof(buttonConfirmText)} and {nameof(buttonCancelText)} must either be OK/Cancel or Yes/No.");
    }

    /// <summary>
    /// For debugging purpose only
    /// </summary>
    /// <param name="message"></param>
    /// <param name="title"></param>
    /// <returns></returns>
    public Task ShowMessageBox(string message, string title) => ShowMessage(message, title);

    private void MessengerSend(string msg, string title = "", MessageBoxButtonVM btn = MessageBoxButtonVM.OK, MessageBoxImageVM icon = MessageBoxImageVM.Information)
    {
      Messenger.Send(new MessageBoxArgs()
      {
        Buttons = MessageBoxButtonVM.OK,
        Icon = MessageBoxImageVM.Information,
        Title = (string.IsNullOrEmpty(title) ? _ProductName : title),
        Message = msg
      });
    }
  }
}

Aquí está la capa de presentación (entra en Ver proyecto)

using System.Windows;
using VM;

namespace View
{
  class DialogPresenter
  {
    private Window _Parent;

    public DialogPresenter()
    {
      //For simple information boxes
      GalaSoft.MvvmLight.Messaging.Messenger.Default.Register<MessageBoxArgs>(this, (arg) => ShowDialog(arg));

      //For Yes/No or OK/Cancel dialog boxes.
      GalaSoft.MvvmLight.Messaging.Messenger.Default.Register<MessageBoxNotificationWithAction<bool>>(this, (arg) => arg.Execute(ShowDialog(arg.Notification)));

      //For notifications that require a string response (such as Manual Timeslot Description)
      GalaSoft.MvvmLight.Messaging.Messenger.Default.Register<MessageBoxNotificationWithAction<string>>(this,
        (arg) => arg.Execute(ShowStringInputDialog(arg.Notification.Title, arg.Notification.Message)));
    }

    private bool ShowDialog(MessageBoxArgs arg)
    {
      MessageBoxButton btn = MessageBoxButton.OK;
      MessageBoxImage ico = MessageBoxImage.None;

      switch (arg.Buttons)
      {
        case MessageBoxButtonVM.OK: btn = MessageBoxButton.OK; break;
        case MessageBoxButtonVM.OKCancel: btn = MessageBoxButton.OKCancel; break;
        case MessageBoxButtonVM.YesNo: btn = MessageBoxButton.YesNo; break;
      }

      switch (arg.Icon)
      {
        case MessageBoxImageVM.Error: ico = MessageBoxImage.Error; break;
        case MessageBoxImageVM.Information: ico = MessageBoxImage.Information; break;
        case MessageBoxImageVM.None: ico = MessageBoxImage.None; break;
        case MessageBoxImageVM.Question: ico = MessageBoxImage.Question; break;
      }

      bool Result = false;
      _Parent.Dispatcher.Invoke(() =>
      {
        var Res = MessageBox.Show(arg.Message, arg.Title, btn, ico);
        Result = (Res == MessageBoxResult.OK || Res == MessageBoxResult.Yes);
      });

      return Result;
    }

    private string ShowStringInputDialog(string title, string description, string value = "", int maxLength = 100)
    {
      string Result = null;

      _Parent.Dispatcher.Invoke(() =>
      {
        //InputBox is a WPF Window I created for taking simple
        //string values from the user. This also shows that you can
        //any custom dialog using this approach.

        InputBox input = new InputBox();
        input.Title = title;
        input.Owner = _Parent;
        if (input.ShowDialog(description, value, maxLength).Value)
          Result=input.Value;
        else
          Result=null;
      });

      return Result;
    }

    //Call this somewhere at application startup so that the dialog boxes
    //appear as child windows.
    public void SetParentWindow(Window parent)
    {
      _Parent = parent;
    }
  }
}
1
dotNET

Rodé mi propio cargador de ventanas descrito en una respuesta a esta pregunta:

Gestionar múltiples vistas WPF en una aplicación

1
Mark Bostleman

He escrito un artículo bastante completo sobre este mismo tema y también he desarrollado una biblioteca emergente para diálogos de MVVM. La adherencia estricta a MVVM no solo es posible sino también muy limpia cuando se implementa correctamente, y se puede extender fácilmente a las bibliotecas de terceros que no se adhieren a ellas mismas:

https://www.codeproject.com/Articles/820324/Implementing-Dialog-Boxes-in-MVVM

0
Mark Feldman

Lo siento, pero tengo que intervenir. He revisado varias de las soluciones sugeridas, antes de encontrar el espacio de nombres Prism.Wpf.Interactivity en el proyecto Prism. Puede usar las solicitudes de interacción y la acción de la ventana emergente para desplegar una ventana personalizada o para necesidades más simples, hay ventanas emergentes de notificación y confirmación integradas. Estos crean ventanas verdaderas y se gestionan como tales. puede pasar un objeto de contexto con las dependencias que necesite en el cuadro de diálogo. Usamos esta solución en mi trabajo desde que la encontré. Tenemos numerosos desarrolladores senior aquí y nadie ha encontrado nada mejor. Nuestra solución anterior fue el servicio de diálogo en una superposición y el uso de una clase de presentador para hacerlo realidad, pero tenía que tener fábricas para todos los modelos de diálogo, etc.

Esto no es trivial pero tampoco es super complicado. Y está integrado en Prism y, por lo tanto, es la mejor (o mejor) práctica IMHO.

Mis 2 centavos!

0
jogi

Estaba pensando en un problema similar cuando pregunté cómo debería verse el modelo de vista para una tarea o diálogo .

Mi solución actual se ve así:

public class SelectionTaskModel<TChoosable> : ViewModel
    where TChoosable : ViewModel
{
    public SelectionTaskModel(ICollection<TChoosable> choices);
    public ReadOnlyCollection<TChoosable> Choices { get; }
    public void Choose(TChoosable choosen);
    public void Abort();
}

Cuando el modelo de vista decide que se requiere la entrada del usuario, se extrae una instancia de SelectionTaskModel con las posibles opciones para el usuario. La infraestructura se ocupa de mostrar la vista correspondiente, que en el momento adecuado llamará a la función Choose() con la elección del usuario.

0
David Schmitt

Luché con el mismo problema. Se me ha ocurrido una forma de intercomunicación entre la vista y el ViewModel. Puede iniciar el envío de un mensaje desde el ViewModel a la Vista para indicarle que muestre un buzón de mensajes y le informará el resultado. Luego, el ViewModel puede responder al resultado devuelto por la Vista.

Demuestro esto en mi blog :

0
Jaco Karsten