Pergunta

Eu tenho vindo a desenvolver um aplicativo LOB muito grande usando o meu sabor de M-V-VM que eu chamo de M-V-MC (Model-View-ModelController), que é uma espécie de combinação entre M-V-C e M-V-VM. Eu tinha postado esta resposta sobre como vistas se instanciado no MV-VM para a pergunta " que-é-o-mais-common-erros-made-in-wpf-desenvolvimento ".

Sam fez o seguinte comentário sobre a minha resposta:

Isso cria um follow-up-pergunta: como você cria os pontos de vista? eu uso RelayCommands para acções de ligação a partir da visualizar a ViewModel, portanto, a vista nem sabe uma ação tem Despedido, não sabe que ele deve abrir uma nova visão. Solução: criar um evento no a VM para o Vista para subscrever?

Quando eu originalmente começou desenvolvimento MV-VM eu tinha essa noção de que tudo deve viver no ViewModel, e ter estudado um monte de exemplos de caras como Josh Smith e Karl Shifflett . No entanto eu ainda tenho que vir para cima com um bom exemplo de quando um comando necessidades para viver no ViewModel.

Por exemplo, digamos que eu tenho um ListView que exibe Clientes, e um botão que eu clique para permitir-me para editar o cliente selecionado no momento. O ListView (View) está vinculado a um CustomerVM (ViewModel). Clicando no botão aciona o EditCustomerCommand que abre uma janela pop-up que me permite editar todas as propriedades do CustomerVM. Onde faz isso EditCustomerCommand ao vivo? Se envolve a abertura de uma janela, (funcionalidade UI), que não deveria ser definida no código-behind do ponto de vista? text alt

Alguém tem algum exemplo de quando eu deveria definir um comando na Vista versus o ViewModel?

Matthew Wright estados abaixo:

Novo e exclusão de uma lista seria bons exemplos. Nesses casos, um espaço em branco registro é adicionado ou o registro atual é excluído pelo ViewModel. Qualquer medidas tomadas pela visão deve estar em resposta a esses eventos ocorrem.

Então, se eu clicar no botão novo, o que acontece? Uma nova instância do CustomerVM é criado pelo pai ViewModel e acrescentou-lhe de direito coleção? Então, como seria a minha tela de edição ficar aberto? A visão deve criar uma nova instância do ViewModel Cliente, e passá-lo para o ParentVM.Add (newlyCreatedVM) direito método?

Digamos que eu excluir um registro do cliente através da vida DeleteCommand na VM. o VM chama na camada de negócio e tenta excluir o registro. Não pode por isso retorna uma mensagem para o VM. Eu quero mostrar esta mensagem dialogbox. Como é que a vista passar a mensagem da acção de comando?

Foi útil?

Solução

Nunca pensei que me vejo sendo citado em uma pergunta.

Eu ponderei essa pergunta a mim mesmo por algum tempo, e tomou uma decisão bastante pragmática para minha base de código:

Na minha base de código, o ViewModel está sendo chamado quando as ações acontecem, e eu queria que ficar assim. Além disso eu não quero o ViewModel para controlar os pontos de vista.

O que eu fiz?
Eu adicionei um controlador para a navegação:

public interface INavigation
{
  void NewContent(ViewModel viewmodel);
  void NewWindow(ViewModel viewmodel);
}

Este controlador contém duas ações: NewContent () mostra o novo conteúdo na janela atual, NewWindow () cria uma nova janela, preenche com o conteúdo e mostra-
. É claro que meus viewmodels não tem nenhum indício que ver para mostrar. Mas eles sabem que viewmodel eles querem mostrar, assim de acordo com o seu exemplo, quando DeleteCommand é executado, ele chamaria a função de serviço de navegação NewWindow (novo ValidateCustomerDeletedViewModel ()) para mostrar uma janela dizendo 'o cliente foi eliminado'(um exagero para este simples messagebox, mas seria fácil ter uma função de navegador especial para messageboxes simples).

Como é que o ViewModel obter o serviço de navegação?

Minha classe viewmodel tem uma propriedade para o controlador de navegação:

public class ViewModel
{
  public INavigation Navigator { get; set; }
  [...]
}

Quando um viewmodel é anexado a uma janela (ou o que exibe a vista), a janela irá definir a propriedade Navigator, de modo que o viewmodel pode chamá-lo.

Como é que o navegador criar a vista para o viewmodel?

Você poderia ter uma lista simples que ver para criar para o qual viewmodel, no meu caso eu posso usar a reflexão simples, já que os nomes são de harmonização:

public static FrameworkElement CreateView(ViewModel viewmodel)
{
  Type vmt = viewmodel.GetType();
  // big bad dirty hack to get the name of the view, but it works *cough*
  Type vt = Type.GetType(vmt.AssemblyQualifiedName.Replace("ViewModel, ", "View, ")); 
  return (FrameworkElement)Activator.CreateInstance(vt, viewmodel);
}

É claro que a visão precisa de um construtor aceitar a viewmodel como parâmetro:

public partial class ValidateCustomerDeletedView : UserControl
{
  public ValidateCustomerDeletedView(ValidateCustomerDeletedViewModel dac)
  {
    InitializeComponent();
    this.DataContext = dac;
  }
}

Como é que minha janela olhar como?

Simples: minha janela principal não implementar a interface INavigation, e mostra uma página inicial na criação. Veja por si mesmo:

public partial class MainWindow : Window, INavigation
{
  public MainWindow()
  {
    InitializeComponent();
    NewContent(new StartPageViewModel());
  }

  public MainWindow(ViewModel newcontrol)
  {
    InitializeComponent();
    NewContent(newcontrol);
  }

  #region INavigation Member
  public void NewContent(ViewModel newviewmodel)
  {
    newviewmodel.Navigator = this;
    FrameworkElement ui = App.CreateView(newviewmodel);
    this.Content = ui;
    this.DataContext = ui.DataContext;
  }

  public void NewWindow(ViewModel viewModel)
  {
    MainWindow newwindow = new MainWindow(viewModel);
    newwindow.Show();
  }
  #endregion
}

(Isto funciona igualmente bem com um NavigationWindow e envolvendo o ponto de vista em uma página)

Claro que isto é testável, uma vez que o controlador de navegação pode ser ridicularizado facilmente.

Eu não tenho certeza se esta é uma solução perfeita, mas ele funciona muito bem para mim agora. Todas as idéias e comentários são bem-vindos!

Outras dicas

Para o seu caso caixa de mensagem de exclusão, I messageboxes fora abstratas através de um interface. Semelhante a este. Eu também injetar essas interfaces para meu aplicativo WPF.

Construtor

    public MyViewModel(IMessage msg)
    {
      _msg = msg;
    }

Em seguida, no método de exclusão método no ViewModel ... algo como

    public void Delete()
    {
      if(CanDelete)
      {
        //do the delete 
      }
      else
      {
        _msg.Show("You can't delete this record");
      }
    }

Isto tornará mais testável, você pode conectar um diferentes implementações IMessage que realmente não mostram uma messagebox. Aqueles só poderia imprimir para o console, para fins de teste. Obviamente seu aplicativo WPF pode ter uma implementação como

public class MessageBoxQuestion : IMessage
{
   public void Show(string message)
   {
     MessageBox.Show(message);
   }
}

Fazendo isto torna o exame das diferentes rotas (pense Sim / Não diálogos) muito fácil e direto. Você pode imaginar uma confirmação de exclusão. Você poderia usar um exemplo concreto da IMessage para retornar verdadeiro / falso para confirmação ou zombar fora do recipiente durante o teste.

[Test]
public void Can_Cancel_Delete()
{
  var vm = new ProductViewModel(_cancel);
  ...

}
[Test]
public void Can_Confirm_Delete()
{
  var vm = new ProductViewModel(_yes);
  ...

}

Por sua outra pergunta sobre quando usar o comando, eu instanciar os adicionar novos ou detalhes vistas a partir da visão em questão. Assim como você tem no seu exemplo. Visualizações só são instanciado por outros Visualizações em nosso aplicativo. Eu não uso um comando nesses casos. Eu faço no entanto usar as propriedades ViewModel da vista principal para a visão da criança.

public void Object_DoubleClick(object sender, EventArgs e)
{
  var detailView = new DetailView(ViewModel.Product);
  detailView.Show();
}

Espero que isso ajude!

Novo e exclusão de uma lista seriam bons exemplos. Nesses casos, um registo em branco é adicionado ou a ficha de corrente é apagado pelo ViewModel. Qualquer medida tomada pela visão deve ser em resposta a esses eventos ocorrem.

Uma forma seria usar um objeto de parâmetro de comando que a camada de negócios pode modificar e sua VM pode processar após o comando em execução.

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