Domanda

Devo capire come comunicare tra ViewModels. Sono nuovo di MVVM, quindi per favore sii gentile.

Ecco un esempio stupido

definizioni di classe (supponiamo che io abbia agganciato l'evento Child.PropertyChanged in ParentViewModel):

public class ParentViewModel : ViewModelBase
{
    public ChildViewModel Child { get; set; }
}

public class ChildViewModel : ViewModelBase
{
    String _FirstName;
    public String FirstName 
    {
        get { return _FirstName; }
        set
        {
            _FirstName = value;
            OnPropertyChanged("FirstName");
        }
    }
}

Ecco cosa vedi nel dizionario delle risorse

<DataTemplate DataType="{x:Type vm:ParentViewModel}">
    <vw:ParentView/>
</DataTemplate>

<DataTemplate DataType="{x:Type vm:ChildViewModel}">
    <vw:ChildView/>
</DataTemplate>

e il codice di ChildView:

public partial class ChildView : UserControl
{
    public QueueView()
    {
        InitializeComponent();
        DataContext = new ChildViewModel();
    }
}

Il problema evidente è che quando ChildView viene istanziato (tramite la selezione da DataTemplate) crea una nuova classe ChildViewModel e ParentViewModel non ha accesso ad essa.

Quindi, come posso creare un'istanza di DataContext della vista come ViewModel originale che ha causato la selezione di DataTemplate?

Una soluzione ovvia consiste nel fondere le proprietà di ChildViewModel in ParentViewModel, ma preferirei separarle perché per il riutilizzo.

Sono sicuro che la risposta sia banale, vorrei solo sapere di cosa si tratta. :)

Grazie in anticipo.

È stato utile?

Soluzione

Dovresti semplicemente rimuovere la linea:

DataContext = new ChildViewModel();

Il DataContext della vista verrà impostato automaticamente da WPF. DataTemplates hanno sempre il loro contesto di dati impostato sui dati per il modello (in questo caso ViewModel):

<DataTemplate DataType="{x:Type vm:ChildViewModel}">
    <vw:ChildView/>
</DataTemplate>

Il risultato finale è che puoi costruire gli oggetti del tuo modello di vista separatamente (classi padre e figlio) e poi visualizzarli in un secondo momento semplicemente collegandoli ai controlli del contenuto.

Altri suggerimenti

Il modo più semplice per comunicare tra ViewModels usando l'approccio MVVM è usare il modello Mediator (EventAggregator in Prism). Un buon esempio di questo approccio può essere visto nei seguenti link:

  1. MVVM Mediator Pattern di Sacha Barber
  2. MVVM + Mediatore di Marlon Grech

Guarda anche MVVM sample framework del progetto.

Supponiamo che tu abbia un QueueView che utilizza un QueueViewModel.

public class QueueViewModel : INotifyPropertyChanged
{
    public ParentType Parent { get; set; }

    public QueueViewModel(ParentType parent)
    {
        this.Parent = parent;
        foreach (ChildType child in Parent)
        {
            child.PropertyChanged += delegate(object sender,
                PropertyChangedEventArgs e)
            {
                if (e.PropertyName != "IsSelected")
                    return;

                //do something like this:
                Parent.IsSelected = AllChildrenAreSelected();
            };
        }
    }

}

public class ParentType : INotifyPropertyChanged
{
    private bool _isSelected;

    public IList<ChildType> Children { get; set; }
    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            _isSelected = value;
            OnPropertyChanged("IsSelected");
        }
    }
}

public class ChildType : INotifyPropertyChanged
{
    private string _name;
    private bool _isSelected;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged("Name");
        }
    }

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            _isSelected = value;
            OnPropertyChanged("IsSelected");
        }
    }
}

- Parte QueueView

<StackPanel>
<CheckBlock Text="{Binding Path=Parent.Name}" 
            IsChecked="{Binding Parent.IsSelected}"/>
<ItemsControl ItemsSource="{Binding Path=Parent.Children}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>                                    
            <CheckBox Content="{Binding Path=Name}"
                      IsChecked="{Binding Path=IsSelected, Mode=TwoWay}"/>
        </DataTemplate>
    <ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top