Return the value of a Property from child ViewModel to Parent ViewModel

Topics: Actions & Coroutines, Conventions, Framework Services
May 16, 2013 at 6:47 PM
In my WPF MVVM app, using Caliburn.Micro, I have a ViewModel, CreateServiceViewModel that, on a button click, opens a GridView in a seperate window for the User to chose a Row from.

I created another ViewModel for this, MemberSearchViewModel which has two properties:
    private Member selectedMember;

    public Member SelectedMember
    {
        get { return selectedMember; }
        set { selectedMember = value; }
    }

    private IList<Member> members;

    public IList<Member> Members
    {
        get { return members; }
        set { members = value; }
    }
How do I get that SelectedMember value back to the calling ViewModel? That ViewModel has a property of Service.SelectedMember.
May 16, 2013 at 8:56 PM
Edited May 16, 2013 at 8:58 PM
You don't really indicate the method you use to open the secondary window or it's life cycle.

For example, do you create an instance of the MemberSearchViewModel and use the window manager ShowDIalog() to open it within CreateServiceViewModel and then only need the SelectedMember property when the window closes? If so, you should simply be able to examine the SelectedMember property from the instance you created.

Do you open the MemberSearchViewModel window and need to keep reacting to changes in SelectedMember? If so, you could open it with window manager ShowWindow() which won't block and then use the Event Aggregator to publish an event from the MemberSearchViewModel when selection changes and subscribe to it from CreateServiceViewModel to handle it. https://caliburnmicro.codeplex.com/wikipage?title=The%20Event%20Aggregator&referringTitle=Documentation

In the case of example 2, you could also simply wire up a handler to the PropertyChanged event of the MemberSearchViewModel and examine the property name and handle accordingly. You'd have to be sure to fire PropertyChanged in the setter of SelectedMember.
May 16, 2013 at 10:07 PM
Edited May 17, 2013 at 2:32 AM
i use the following code to fire up the parent datagrid
      public void OpenPhysicianWindowCommand()
      {
           if (CurrentDocument != null)
           {
          dynamic settings = new ExpandoObject();
          settings.WindowStartupLocation = WindowStartupLocation.CenterScreen;
           IoC.Get<IWindowManager>().ShowDialog(IoC.Get<MaintenanceDocumentPhysicianParentDataGridViewModel>(), null, settings);
           }
      }
      
       public void Handle(IParentPhysicianEventArgs message)
       {
           if (message != null)
           {
           CurrentPhysician = message.Physician;
           }
       }
then on the Datagrid that opens up,
after a selection is made
        public void Grid_OnMouseUp(MouseButtonEventArgs result)
        {
            if (CurrentPhysician != null)
            {
                _eventAggregator.Publish(new ParentPhysicianEventArgs { Physician = CurrentPhysician });
                TryClose();
            }
        }
in that way the two viewmdels talk to eachother via the event agregator
May 17, 2013 at 3:37 PM
It's use and life cycle are just for selecting a single member. The user is filling out a "form" of info where one of the fields is a Member. This should popup when they click a button and allow them to select 1 member from the GridView. I need that 1 Member returned and the GridView closed so they can continue filling out the form.

Right now I am showing the GridView VM as a Dialog and passing the Parent VM in the Constructor of the Child VM(the GridView) and then setting the appropriate property from the Child VM. See below -->

This is the Command that the Search Button calls on my Parent VM:
public void SearchClientsAdvanced()
        {
            TelerikWindowManager windowManager = new TelerikWindowManager();
            
            windowManager.ShowDialog(new AdvancedClientSearchViewModel(this));
        }
This is my Child VM:
[Export(typeof(IScreen))]
    public class AdvancedClientSearchViewModel : Screen
    {
        #region CONSTRUCTOR
        [ImportingConstructor]
        public AdvancedClientSearchViewModel(object parent)
        {
            this.Parent = parent;
            memberRepo = new MemberRepo();

            GetData();
        }
        #endregion

        #region FIELDS
        private MemberRepo memberRepo;
        #endregion

        #region PROPERTIES

        private Member selectedMember;

        public Member SelectedMember
        {
            get { return selectedMember; }
            set
            {
                selectedMember = value;
                NotifyOfPropertyChange();
            }
        }

        private IList<Member> members;

        public IList<Member> Members
        {
            get { return members; }
            set
            {
                members = value;
                NotifyOfPropertyChange();
            }
        }

        #endregion


        /// <summary>
        /// Gets the data.
        /// </summary>
        private void GetData()
        {
            Members = memberRepo.GetAll();
        }

        public bool CanSelectMember()
        {
            return true;
        }

        public void SelectMember()
        {            
            ((CreateAuthViewModel)this.Parent).Authorization.Member = SelectedMember;

            this.TryClose();
        }
    }
Now this actually works as expected. When the User clicks a row in the GridView it binds it back as expected to the Parent VM and the appropriate fields. It just seems like I'm doing it wrong.....