Pergunta

A minha pergunta genérica é como o título indica, é melhor carregar dados durante o ViewModel construção ou posteriormente através de algum evento Carregado de manipulação?

Eu estou supondo que a resposta é após a construção, através de alguns Carregado de manipulação de eventos, mas eu estou querendo saber como que é a mais limpa e coordenada entre ViewModel e Ver?

Veja aqui mais detalhes sobre a minha situação e o problema específico que eu estou tentando resolver:

Eu estou usando o MVVM Luz framework, bem como a Unidade de DI.Eu tenho alguns modos de exibição aninhados, cada um ligado a um correspondente ViewModel.O ViewModels são vinculados a cada Exibição da raiz de controle DataContext através do ViewModelLocator idéia de que Laurent Bugnion colocou em MVVM Luz.Isso permite encontrar ViewModels através de um recurso estático e para controlar o tempo de vida de ViewModels através de um framework de Injeção de Dependência, neste caso a Unidade.Ele também permite o Expression Blend para ver tudo no que diz respeito à ViewModels e como ligá-los.

Então, de qualquer maneira, eu tenho um pai Ver que tem uma caixa de Combinação de ligação de dados para uma ObservableCollection em seu ViewModel.Da caixa de Combinação SelectedItem é também dependente (duas vias) para uma propriedade da ViewModel.Quando a seleção da caixa de Combinação alterações, esta é a disparar atualizações em outros modos de exibição e visualizações secundárias.Atualmente estou realizando esta, através do sistema de Mensagens, que é encontrado no MVVM Luz.Isso é tudo funcionando muito bem e, como esperado quando você escolha diferentes itens na caixa de Combinação.

No entanto, o ViewModel é a obtenção de seus dados durante o tempo de construção, através de uma série de inicialização de chamadas de método.Isso parece ser apenas um problema se eu quero controlar o que o inicial SelectedItem do ComboBox é.Utilizando MVVM Luz do sistema de mensagens, eu tenho atualmente é definir até onde o compositor de o ViewModel da propriedade SelectedItem é a de radiodifusão, a atualização e a outros interessados ViewModels registrar para a mensagem em seus construtores.Parece que eu estou atualmente tentando definir o SelectedItem através do ViewModel no tempo de construção, o que não tem permitido sub-ViewModels para ser construído e registrar ainda.

Qual seria a maneira mais para coordenar a carga de dados e configuração inicial de SelectedItem dentro do ViewModel?Eu realmente quero ficar com o colocando de pouco em Vista do código-atrás de como é razoável.Eu acho que eu só preciso de um caminho para o ViewModel para saber quando o material foi Carregado e que, em seguida, pode continuar a carregar os dados e finalizar a fase de configuração.

Agradecemos antecipadamente por sua resposta.

Foi útil?

Solução

Para eventos que você deve usar o EventToCommand em MVVM Light Toolkit.Usando isso, você pode vincular qualquer evento de qualquer elemento da interface do usuário para relaycommand.Confira seu artigo sobre EventToCommand em

http://blog.galasoft.ch/archive/2009/11/05/mvvm-light-toolkit-v3-alpha-2-eventtocommand-behavior.aspx

Baixar o exemplo e ter um olhar.Seu grande.Você não precisa de nenhum code-behind em seguida.Um exemplo é o seguinte:

<Page x:Class="cubic.cats.Wpf.Views.SplashScreenView"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
      xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras"
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"
    Title="SplashScreenPage">

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <cmd:EventToCommand Command="{Binding LoadedCommand}" />
        </i:EventTrigger>        
    </i:Interaction.Triggers>

    <Grid>
        <Label Content="This is test page" />
    </Grid>
</Page>

e o modo de visualização pode ser assim

 public class SplashScreenViewModel : ViewModelBase
    {
        public RelayCommand LoadedCommand
        {
            get;
            private set;
        }

        /// <summary>
        /// Initializes a new instance of the SplashScreenViewModel class.
        /// </summary>
        public SplashScreenViewModel()
        {
            LoadedCommand = new RelayCommand(() =>
            {
                string a = "put a break point here to see that it gets called after the view as been loaded";
            });
        }
    }

se você gostaria de modelo de modo de exibição para ter EventArgs, você pode conjunto simples PassEventArgsToCommand para true:

<i:Interaction.Triggers>
            <i:EventTrigger EventName="Loaded">
                <cmd:EventToCommand PassEventArgsToCommand="True" Command="{Binding LoadedCommand}" />
  </i:EventTrigger>        
</i:Interaction.Triggers>

e o modelo de modo de exibição será como

public class SplashScreenViewModel : ViewModelBase
{
    public RelayCommand<MouseEventArgs> LoadedCommand
    {
        get;
        private set;
    }

    /// <summary>
    /// Initializes a new instance of the SplashScreenViewModel class.
    /// </summary>
    public SplashScreenViewModel()
    {
        LoadedCommand = new RelayCommand<MouseEventArgs>(e =>
        {
            var a = e.WhateverParameters....;
        });
    }

}

Outras dicas

A solução a seguir é semelhante ao que já está previsto e aceito, mas não use um comando no modelo de modo de exibição para carregar os dados, mas um "método normal".Eu acho que os comandos são mais adequadas para as ações do usuário (comandos pode estar disponível e não disponível em tempo de execução), e por isso, o uso regular de uma chamada de método, mas também pela definição de uma interação disparar no modo de exibição.

Sugiro esta:Criar um modelo de modo de exibição de classe.Instanciar o modelo de modo de exibição de classe dentro do xaml do modo de exibição, criando-o para dentro da DataContext propriedade.

Implementar um método para carregar os dados no seu modelo de modo de exibição, por exemplo, LoadData.Configurar o modo de exibição, de modo que este método é chamado quando o modo de exibição de cargas.Isto é feito através de uma interação desencadear, na sua opinião, o que está vinculada ao método no modelo de modo de exibição (referência a "Microsoft.Expressão.Medicamentosas" e "do Sistema.O Windows.Interatividade", são necessários):

Vista (xaml):

<Window x:Class="MyWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test" 
    xmlns:viewModel="clr-namespace:ViewModels"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"            
    >
<Window.DataContext>
    <viewModel:ExampleViewModel/>
</Window.DataContext>
<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <ei:CallMethodAction TargetObject="{Binding}" MethodName="LoadData"/>
    </i:EventTrigger>
</i:Interaction.Triggers>   

Isso vai chamar a LoadData método em ViewModel em tempo de execução quando a vista é carregado.Este é o lugar onde você carregar seus dados.

public class ExampleViewModel
{
    /// <summary>
    /// Constructor.
    /// </summary>
    public ExampleViewModel()
    {
        // Do NOT do complex stuff here
    }


    public void LoadData()
    {
        // Make a call to the repository class here
        // to set properties of your view model
    }

Se o método no repositório é um método assíncrono, você pode fazer o LoadData método assíncrono também, mas isso não é necessário em cada caso.

Pelo caminho, geralmente eu não iria carregar dados no construtor do modelo de modo de exibição.No exemplo acima, a (parâmetro menos) construtor do modelo de modo de exibição é chamado quando o designer mostra a sua visão.Fazer coisas complexas aqui pode causar erros no designer ao mostrar a sua visão (pela mesma razão que eu não iria fazer coisas complexas em vista construtor).

Em alguns cenários de código na vista de modelos construtor pode, inclusive, causar problemas em tempo de execução, quando o modo de exibição de modelos de construtores executa, defina as propriedades do modelo de modo de exibição que estão ligados aos elementos na vista, enquanto que o objeto de exibição não está completamente acabado de criar.

Ok, então.:-)

Você pode vincular a um método em ViewModel usando um comportamento.

Aqui está um link que vai te ajudar com isso.http://expressionblend.codeplex.com/

Eu decidi ter o XAML de forma declarativa vinculado a um manipulador de eventos Carregado no modo de Exibição de código-behind, que por sua vez chamou um método no objeto ViewModel, através do modo de Exibição do elemento raiz UserControl DataContext.

Era uma forma bastante simples, direto, e limpar solução.Eu acho que eu estava esperando por uma forma de ligar o evento Carregado para o objeto ViewModel da mesma forma declarativa você pode com ICommands no XAML.

Talvez eu tenha dado Klinger, a resposta oficial de crédito, mas ele postou um comentário à minha pergunta, e não uma resposta.Então, eu, pelo menos, deu-lhe um-em seu comentário.

Eu tive este mesmo problema ao lidar com mensagens entre uma janela principal e uma janela filho.Basta alterar a ordem em que seus modelos de visão são criadas no seu ViewModelLocator classe.Certifique-se de que todos os modelos de visão que são dependentes de uma mensagem são criados antes de o modelo de modo de exibição que envia a mensagem.

Por exemplo, em seu ViewModelLocator construtor da classe:

public ViewModelLocator()
{
    if (s_messageReceiverVm == null)
    {
        s_messageReceiverVm = new MessageReceiverVM();
    }

    if (s_messageSenderVm == null)
    {
        s_messageSenderVm = new MessageSenderVM();
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top