ContentView's Model is ignored in Xamarin.Forms #349

Closed
nologinatgit opened this Issue Jul 21, 2016 · 4 comments

Projects

None yet

3 participants

@nologinatgit
nologinatgit commented Jul 21, 2016 edited

I have the following XAML for a parent view:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="MyProject.Views.MainContainerView"
             xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:cm="clr-namespace:Caliburn.Micro.Xamarin.Forms;assembly=Caliburn.Micro.Platform.Xamarin.Forms"
             Title="Container">
    <ContentView cm:View.Model="{Binding DetailViewModel}" />
</ContentPage>

This is its ViewModel:

public class MainContainerViewModel : Screen
{
    public MainContainerViewModel()
    {
      DetailViewModel = new DetailsViewModel ();
    }

    public DetailsViewModel DetailViewModel{ get; set; }

    public void Save()
    {
      var y = 7;
    }
}

This is the DetailsView:

<?xml version="1.0" encoding="utf-8" ?>
<ContentView x:Class="MyProject.Views.DetailsView"
             xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:cm="clr-namespace:Caliburn.Micro.Xamarin.Forms;assembly=Caliburn.Micro.Platform.Xamarin.Forms"
             xmlns:sys="clr-namespace:System;assembly=mscorlib">
    <Button cm:Message.Attach="Save" Text="Save" />
</ContentView>

This is the ViewModel for the Details:

public class DetailsViewModel : Screen
{
   public void Save()
    {
      var y = 2;
    }
}

I always end up in the MainContainerViewModel's Save method instead of the detail viewmodel.

Why? What should I modify?

@nigel-sampson nigel-sampson added this to the v3.0.2 milestone Jul 21, 2016
@nigel-sampson nigel-sampson added the bug label Jul 21, 2016
@nigel-sampson
Contributor

This looks like a bug. I'm not sure about a work around at the moment.

@Yakyyaky
Yakyyaky commented Sep 6, 2016

As a work around, if possible is to not have the Save() method in MainContainerViewModel.
For some reason, it appears that the method propagation is working in reverse of what is it normally.
For example in WPF, it would do DetailsViewModel.Save() and then to the parent's MainContainerViewModel.Save() if it's not found in the child.
However in XF. It's MainContainerViewModel.Save() and then DetailsViewModel.Save() if it's not found in the parent.

@nigel-sampson
Contributor

This looks to be a timing issue caused by lack of decent events in Xamarin.Forms. When we "bind" the view and view model together we set an attached dependency property on the view called Action.Target.

When the element with the message attached is Loaded into the visual tree we walk up the tree we find the Target and therefore which view model to call the method on (the bubbling works by continuing the traversal if the target doesn't have the method).

In this case Xamarin Forms doesn't have an equivalent of Loaded so I've been hacky and used BindingContextChanged. What's happened is this event is firing before the target could be set on the details view and therefore it finds the container.

Switching some order of operations (bind the view / view model before adding to visual tree) lets us set the target before causing the event to fire.

It's something I've wanted to do in the main framework for a while now, but could be a breaking change. Happy to try it out in Xamarin.Forms first.

@nigel-sampson
Contributor

Just pushed a fix, if you want to have a look and see if it resolves in your app as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment