2010-01-01 16 views
14

Ho recentemente iniziato a studiare il modello MVVM con WPF per un progetto imminente. Ho iniziato con Josh Smith's MSDN article. Ho una domanda (molte, ma iniziamo con una):MVVM (con WPF): associazione di più viste alla stessa vista Modello

Ho un IndividualViewModel che espone le proprietà del modello. Ho bisogno di due viste "Aggiungi persona" e "Modifica persona" che sono molto simili, come puoi immaginare. Quello che ho fatto attualmente è di avere 2 sottoclassi AddIndividualViewModel e EditIndividualViewModel che espongono rispettivamente i comandi Aggiungi e Modifica. Ho anche 2 viste denominate simili che si legano a queste.

Ora questo metodo funziona e queste classi sono comunque abbastanza piccole, ma mi chiedo se sia possibile per me avere solo un modello di visualizzazione, che espone entrambi i comandi. Avrei ancora 2 viste che si legherebbero a questo stesso modello di vista, esponendo il comando appropriato come un pulsante. Non sono abbastanza sicuro di come farlo. Nei principali risorse della finestra ho qualcosa di simile:

 <DataTemplate DataType="{x:Type ViewModels:AddIndividualViewModel}"> 
      <Views:AddIndividualView /> 
     </DataTemplate> 

Con questo metodo di rilegatura si può avere solo un uno-a-uno vincolante, vale a dire la stessa vista viene sempre visualizzato per un determinato modello di vista. C'è un modo per cambiare automaticamente la vista a seconda di una proprietà sul modello di vista (ad esempio IndividualViewModel.Mode). C'è un approccio diverso che dovrei prendere in considerazione?

Si noti che la finestra principale ha una collezione di modelli di visualizzazione e li mostra in una scheda.

Grazie!

risposta

1

Non c'è motivo per cui non si dovrebbe riuscire a farlo. Un modo per farlo è quello di fornire un certo flag nel modello di visualizzazione che indica se ci si trova in modalità di aggiunta o in modalità di modifica e lo styling della vista in base a tale flag utilizzando semplici associazioni, trigger o selettori di modelli.

Per riferimento si può guardare Sacha Barber's DataWrapper class che fa parte della sua Cinch quadro (non direttamente applicabile al vostro caso, ma è un buon punto di partenza), che avvolge i campi di dati nel modello vista in modo tale da sostenere una bandiera per attivare o disattivare tra sola lettura (visualizza modalità di registrazione) e lettura-scrittura (modifica modalità di registrazione). È possibile applicare un approccio simile per distinguere tra aggiungi e modifica.

Fondamentalmente, anziché avere proprietà semplici nel modello di visualizzazione, creare un'istanza di una classe wrapper dati che include una proprietà Value e una proprietà IsAdding. Nella tua vista, puoi usare bind, trigger o selettori di modelli per modificare i modelli in base a quella proprietà.

4

Grazie per avermi indicato nella giusta direzione! Sono ancora nuovo con WPF e sto imparando tutte le diverse possibilità, compresi i metodi di binding. Ad ogni modo, per chiunque sia interessato, ecco la soluzione per cui sono arrivato:

Ho deciso di mantenere separati i modelli di visualizzazione in due sottoclassi AddIndividualViewModel e EditIndividualViewModel che espongono solo i comandi, anziché cercare di gestire lo stato nel una classe. Tuttavia volevo una vista in modo tale da non duplicare lo XAML.Ho finito per usare due DataTemplates e DataTemplateSelector per passare i pulsanti di azione a seconda del modello di vista:

 <DataTemplate x:Key="addTemplate"> 
      <Button Command="{Binding Path=AddCommand}">Add</Button> 
     </DataTemplate> 

     <DataTemplate x:Key="editTemplate"> 
      <Button Command="{Binding Path=UpdateCommand}">Update</Button> 
     </DataTemplate> 

     <TemplateSelectors:AddEditTemplateSelector 
      AddTemplate="{StaticResource addTemplate}" 
      EditTemplate="{StaticResource editTemplate}" 
      x:Key="addEditTemplateSelector" /> 

e un presentatore contenuti nella parte inferiore del modulo:

 <ContentPresenter Content="{Binding}" 
          ContentTemplateSelector="{StaticResource addEditTemplateSelector}" /> 

ecco il codice per il selettore di modello:

class AddEditTemplateSelector : DataTemplateSelector 
{ 
    public DataTemplate AddTemplate { get; set; } 
    public DataTemplate EditTemplate { get; set; } 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     if (item is AddIndividualViewModel) 
     { 
      return AddTemplate; 
     } 
     else if (item is EditIndividualViewModel) 
     { 
      return EditTemplate; 
     } 

     return null; 
    } 
} 

questo può o non può essere come implementare l'ultima cosa (visti i requisiti), ma è bello vedere che ho questo tipo di opzione disponibile.

1

Per questa attività non è necessario alcun DataTemplateSelector.

  1. Derivare EditIndividualVM e AddINdividualVM da IndividualVM.
  2. I percorsi Modifica e Aggiungi a una proprietà setter in IndividualVM.
  3. Il setter VM = new AddIndividualVM o VM = new EditIndividualVM a seconda del pulsante premuto.
  4. in XAML vi legano nel contentgrid alla vostra proprietà VM in questo modo:

+2

Sembra che il codice sia mancante. Potresti aggiornare la tua risposta con lo snippet di codice, per favore? – PlagueHammer

4

quindi è necessario 2 diversi punti di vista sulla base di un valore della proprietà. Una cosa da considerare è refactor your presentation code, quindi invece dei valori di una proprietà potresti avere delle sottoclassi reali. Quindi puoi utilizzare 2 diversi DataTemplate per ogni classe.

<DataTemplate DataType="{x:Type ViewModels:AddIndividualViewModel}"> 
    <Views:AddIndividualView /> 
</DataTemplate> 

<DataTemplate DataType="{x:Type ViewModels:EditIndividualViewModel}"> 
    <Views:EditIndividualView /> 
</DataTemplate> 

Se si pensa che è un eccessivo, è possibile utilizzare un trigger e avvolgere le viste specifiche in un ContentPresenter.

<DataTemplate x:Key="AddIndividualTemplate" DataType="{x:Type ViewModels:IndividualViewModel}"> 
    <Views:AddIndividualView /> 
</DataTemplate> 

<DataTemplate x:Key="EditIndividualTemplate" DataType="{x:Type ViewModels:IndividualViewModel}"> 
    <Views:EditIndividualView /> 
</DataTemplate> 

<DataTemplate DataType="{x:Type ViewModels:IndividualViewModel}"> 
    <ContentPresenter Content="{Binding}"> 
    <ContentPresenter.Style> 
     <Style TargetType="ContentPresenter"> 
     <Setter Property="ContentTemplate" Value="{StaticResource AddIndividualTemplate}" /> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding Mode}" Value="{x:Static ViewModels:IndividualMode.Edit}"> 
      <Setter Property="ContentTemplate" Value="{StaticResource EditIndividualTemplate}" /> 
      </DataTrigger> 
     </Style.Triggers> 
     </Style> 
    </ContentPresenter.Style> 
    </ContentPresenter> 
</DataTemplate> 
+0

Questa è la classica soluzione MVVM. Specifica entrambe le opzioni e non ha codice dietro. –

Problemi correlati