Pergunta

Eu tenho um aplicativo WPF que chama MessageBox.show () no ViewModel (Para verificar se o usuário realmente deseja excluir). Isso realmente funciona, mas vai contra o grão da MVVM Como o ViewModel não deve determinar explicitamente o que acontece na visualização.

Então agora estou pensando Como posso implementar melhor a funcionalidade messagebox.show () No meu aplicativo MVVM, opções:

  1. Eu poderia ter uma mensagem com o texto "Você tem certeza ...?" Juntamente com dois botões sim e não em uma borda no meu xaml e crie um gatilho no modelo para que ele seja recolhido/visível com base em um viewModelProperty chamado AreyourSleSleSleiGogueBoxIsvisible, e então, quando eu precisar desta caixa de diálogo, atribua o AreyourSleSuseDialogueBoxissible a "True" e também lide com os dois botões via DelegateCommand de volta ao meu ViewModel.

  2. De alguma forma, eu também poderia tentar lidar com isso com gatilhos no XAML, para que o botão Excluir apenas faça com que algum elemento de borda apareça com a mensagem e os botões nele, e o botão sim fez a exclusão.

Ambas as soluções parecem ser muito complexas para o que costumava ser algumas linhas de código com MessageBox.Show ().

De que maneira você implementou com sucesso caixas de diálogo em seus aplicativos MVVM?

Foi útil?

Solução

Dos dois que você mencionou, eu prefiro a opção #2. O botão Excluir na página apenas faz com que a caixa de diálogo "Confirm Excluir" apareça. A "diálogo Confirm Excluir" começa a excluir.

Você verificou Karl Shifflett's WPF Line of Business Slides e demos? Eu sei que ele faz algo assim. Vou tentar lembrar onde.

EDIT: Confira a demonstração #11 "Validação de dados em MVVM" (EditContActitemScentrolSelectionViewModel.DeleteCommand). Karl chama um pop-up do ViewModal (o que!? :-). Na verdade, gosto mais da sua ideia. Parece mais fácil de unidade de teste.

Outras dicas

Serviços para o resgate. Usando Ônix (Isenção de isenção, eu sou o autor) Isso é tão fácil quanto:

public void Foo()
{
    IDisplayMessage dm = this.View.GetService<IDisplayMessage>();
    dm.Show("Hello, world!");
}

Em um aplicativo em execução, isso indiretamente chamará o MessageBox.show ("Olá, mundo!"). Ao testar, o serviço IdisplayMessage pode ser ridicularizado e fornecido ao ViewModel para fazer o que você deseja realizar durante o teste.

Para expandir a resposta de Dean Chalk agora que seu link é Kaput:

No arquivo app.xaml.cs, conectamos a caixa de diálogo Confirmar à ViewModel.

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    var confirm = (Func<string, string, bool>)((msg, capt) => MessageBox.Show(msg, capt, MessageBoxButton.YesNo) == MessageBoxResult.Yes);
    var window = new MainWindowView();
    var viewModel = new MainWindowViewModel(confirm);
    window.DataContext = viewModel;
    ...
}

Na exibição (MainWindowView.xaml), temos um botão que chama um comando no ViewModel

<Button Command="{Binding Path=DeleteCommand}" />

O ViewModel (MainWindowViewModel.cs) usa um comando delegado para mostrar o "Você tem certeza?" diálogo e execute a ação. Neste exemplo, é um SimpleCommand igual a isto, mas qualquer implementação do ICommand deve fazer.

private readonly Func<string, string, bool> _confirm;

//constructor
public MainWindowViewModel(Func<string, string, bool> confirm)
{
    _confirm = confirm;
    ...
}

#region Delete Command
private SimpleCommand _deleteCommand;
public ICommand DeleteCommand
{
    get { return _deleteCommand ?? (_deleteCommand = new SimpleCommand(ExecuteDeleteCommand, CanExecuteDeleteCommand)); }
}

public bool CanExecuteDeleteCommand()
{
    //put your logic here whether to allow deletes
    return true;
}

public void ExecuteDeleteCommand()
{
    bool doDelete =_confirm("Are you sure?", "Confirm Delete");
    if (doDelete)
    {
        //delete from database
        ...
    }
}
#endregion

Eu apenas crio uma interface (iMessagedisplay ou similar) que é injetada na VM e possui métodos como uma caixa de mensagem (showMessage () etc.). Você pode implementar isso usando uma caixa de mensagem padrão ou algo mais específico do WPF (eu uso este no codeplex um cara chamado Prajeesh).

Dessa forma, tudo está separado e testável.

Que tal criar um evento como "MessageBoxRequested" tratado no CodeBehind da visualização (de qualquer maneira, é apenas o código de visualização, para que não vejo nenhum problema em ter esse código no CodeBehind).

Eu fiz um controle simples de wrapper para caixa de mensagem para usarmos em uma solução pura de MVVM e ainda permitindo a capacidade de teste de unidade. Os detalhes estão no meu blog http://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspx

Mukapu

Eu implementei um comportamento que ouve uma mensagem do ViewModel. É baseado na solução Laurent Bugnion, mas como não usa código por trás e é mais reutilizável, acho que é mais elegante.

Confira aqui

Caixas de mensagem WPF e Silverlight

MVVM suportado

http://slwpfmessagebox.codeplex.com/

Apenas caso qualquer outra pessoa ainda esteja lendo e insatisfeita:

Eu só queria lidar com caixas de mensagem do tipo 'notificação' (ou seja, eu não me importo com o DialogResult), mas o problema que tenho com a maioria das soluções que li é que elas parecem forçá -lo indiretamente a escolher sua implementação de visualização (ou seja, atualmente eu tenho um MessageBox.Show, mas se eu decidir mais tarde apenas mexer com a visibilidade de um painel oculto diretamente na minha opinião, isso não combina muito bem com um INotification interface passou para o viewmodel).

Então eu fui rápido e sujo:

O viewmodel tem um string NotificationMessage propriedade, com alterações notificadas para PropertyChanged.

A vista assina para PropertyChanged, e se vê o NotificationMessage A propriedade vem, faz o que quiser.

Ok, então isso significa que a visualização tem código-behind e o nome de PropertyChanged é codificado, mas seria codificado no XAML de qualquer maneira. E isso significa que evito todas as coisas como conversores para visibilidade e propriedades para dizer se a notificação ainda é visível ou não.

(É certo que isso é apenas para um caso de uso limitado (fogo e esquecer), não pensei muito em como querer estendê-lo.)

Eu apenas jogaria da VM. Eu não quero ter que usar o serviço de outra pessoa ou escrever o meu apenas para jogar uma caixa de mensagem.

Recentemente, me deparei com esse problema em que tive que substituir o MessageBox.Show nos modelos ViewModels por algum mecanismo de caixa de mensagem de reclamação totalmente MVVM.

Para conseguir isso, usei InteractionRequest<Notification> e InteractionRequest<Confirmation> Juntamente com a interação gatilhos e escreveu minhas próprias opiniões para a caixa de mensagens.

O que eu implementei foi publicado aqui

Há tantas respostas sobre esse tópico que variam de criar uma classe personalizada e usar bibliotecas de terceiros. Eu diria que use uma biblioteca de terceiros se você quiser pop -ups legais com bons visuais.

Mas se você deseja apenas usar a caixa de mensagens regular da Microsoft para o seu aplicativo WPF aqui está uma implementação amigável para testar MVVM/unidade:

Inicialmente, pensei em herdar da caixa de mensagens e embrulhá -la com uma interface, mas não pude, devido ao fato de a caixa de mensagem não ter um construtor público, então aqui está a solução "fácil":

Caixa de mensagens de descompilação No Visual Studio Você pode ver todas as sobrecargas de métodos, verifiquei quais eu queria criar uma nova classe e adicionei os métodos, enrolou-a com uma interface e Ta-Da! Agora você pode usar o Ninject para ligar a interface e a classe, injetar -a e usar o MOQ para testar o teste de unidade etc.

Crie uma interface (adicionou apenas algumas das sobrecargas, pois não preciso de todas elas):

public interface IMessageBox
    {
        /// <summary>Displays a message box that has a message, title bar caption, and button; and that returns a result.</summary>          
        MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button);

        /// <summary>Displays a message box that has a message, title bar caption, button, and icon; and that returns a result.</summary>           
        MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon);

        /// <summary>Displays a message box that has a message and title bar caption; and that returns a result.</summary>            
        MessageBoxResult Show(string messageBoxText, string caption);
    }

Então temos a classe que herdará dela:

public class MessageBoxHelper : IMessageBox
    {
        /// <summary>Displays a message box that has a message, title bar caption, button, and icon; and that returns a result.</summary>            
        public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button,
            MessageBoxImage icon)
        {
            return MessageBox.Show(messageBoxText, caption, button, icon, MessageBoxResult.None,
                MessageBoxOptions.None);
        }

        /// <summary>Displays a message box that has a message, title bar caption, and button; and that returns a result.</summary>            
        public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button)
        {
            return MessageBox.Show(messageBoxText, caption, button, MessageBoxImage.None, MessageBoxResult.None,
                MessageBoxOptions.None);
        }

        /// <summary>Displays a message box that has a message and title bar caption; and that returns a result.</summary>            
        public MessageBoxResult Show(string messageBoxText, string caption)
        {
            return MessageBox.Show(messageBoxText, caption, MessageBoxButton.OK, MessageBoxImage.None,
                MessageBoxResult.None, MessageBoxOptions.None);
        }

        /// <summary>Displays a message box that has a message and that returns a result.</summary>           
        public MessageBoxResult Show(string messageBoxText)
        {
            return MessageBox.Show(messageBoxText, string.Empty, MessageBoxButton.OK, MessageBoxImage.None,
                MessageBoxResult.None, MessageBoxOptions.None);
        }
    }

Agora, basta usar isso ao injetar etc e boom, você tem uma abstração frágil que fará o truque ... o que é bom, dependendo de onde você o usará. Meu caso é um aplicativo simples apenas para fazer algumas coisas, portanto, não há sentido em projetar uma solução. Espero que isso ajude alguém.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top