Pregunta

Necesito averiguar cómo comunicarme entre ViewModels. Soy nuevo en MVVM, por favor sea amable.

Aquí hay un ejemplo de tonto

definiciones de clase (supongamos que enganché el evento Child.PropertyChanged en 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");
        }
    }
}

Esto es lo que ves en el diccionario de recursos

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

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

y el código subyacente de ChildView:

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

El problema obvio es que cuando se crea una instancia de ChildView (a través de la selección de DataTemplate) se crea una nueva clase de ChildViewModel y ParentViewModel no tiene acceso a ella.

Entonces, ¿cómo puedo crear una instancia del DataContext de la Vista para que sea el ViewModel original que hizo que se seleccionara el DataTemplate?

Una solución obvia es combinar las propiedades de ChildViewModel en ParentViewModel, pero preferiría separarlas para su reutilización.

Estoy seguro de que la respuesta es trivial, solo me gustaría saber qué es. :)

Gracias de antemano.

¿Fue útil?

Solución

Simplemente debes eliminar la línea:

DataContext = new ChildViewModel();

El DataContext de la vista se establecerá automáticamente por WPF. DataTemplates siempre tienen su contexto de datos configurado para los datos de la plantilla (en este caso, el Modelo de Vista):

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

El resultado final es que puede crear los objetos de su modelo de vista por separado (tanto para las clases primarias como para las secundarias) y luego mostrarlos más tarde simplemente insertándolos en los controles de contenido.

Otros consejos

La forma más fácil de comunicarse entre ViewModels utilizando el enfoque MVVM es usar el patrón de Mediador (EventAggregator in Prism). Un buen ejemplo de este enfoque se puede ver en los siguientes enlaces:

  1. Patrón de mediador de MVVM por Sacha Barber
  2. MVVM + Mediador por marlon grech

También puedes ver el MVVM muestra marco del proyecto.

Supongamos que tienes un QueueView que usa 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>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top