Search code examples
c#xamlmvvmxamarin.formsarcgis-runtime-net

Expose XAML Element to ViewModel to run methods Xamarin Forms


I need to be able to run methods on a XAML element in my ViewModel, I have 3 files - DataPrepPage.cs, DataPrepPage.xaml and DataPrepViewModel.cs.

In my XAML(DataPrepPage.xaml) page I have the element like this:

<esriUI:MapView x:Name="MapElement" 
                Map="{Binding Map}"/>

I set my binding context on the parent grid element like this:

<Grid.BindingContext>
     <local:DataPrepViewModel/>
</Grid.BindingContext>

Of course I can access my MapView element and methods in the code-behind like this for example:

MapElement.GraphicsOverlays.Add(MyOverlay);

So the problem is I need to be able to do this in the ViewModel but the x:Name does not expose it to my ViewModel.

At the moment I have a static in my ViewModel

public static MapView MapView;

And I assign my element to it in the constructor of my page code-behind:

    public DataPrepPage ()
    {
        InitializeComponent ();
        DataPrepViewModel.MapView = MapElement;
    }

Which allows me to do this in my ViewModel:

MapView.GraphicsOverlays.Add(MyOverlay);

So the question is:

How do I expose the element to my ViewModel without using a static? || How can I run methods on an element from the ViewModel?


Solution

  • The whole idea behind MVVM is that your view and viewmodel are de-coupled. You're asking how to couple them together again. Short answer: don't.

    You can Bind the GraphicsOverlays in XAML:

            <esri:MapView x:Name="MapView1" Height="517" MapViewTapped="MapView1_MapViewTapped">
    
                <!-- Add a Map. -->
                <esri:Map x:Name="Map1">
    
                    <!-- Add a backdrop ArcGISTiledMapServiceLayer. -->
                    <esri:ArcGISTiledMapServiceLayer ID="myArcGISTiledMapServiceLayer" 
                      ServiceUri="http://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer" />
    
                </esri:Map>
    
                <!-- Add a MapView.GraphicsOverlays collection. -->
            <esri:MapView.GraphicsOverlays>
    
                <!-- Add a GraphicsOverlay to hold Graphics added via code behind from a FindTask operation. Set the Renderer to draw the polygon graphics. -->
                <esri:GraphicsOverlay Renderer="{StaticResource mySimpleRenderer}"/>
    
            </esri:MapView.GraphicsOverlays>
    
        </esri:MapView>
    

    More complete documentation is here.

    So create additional properties or DependencyProperty instances of the types required and use XAML to then bind to these new view model properties.

    Just for completeness, you can make XAML element public like this:

    <Button x:Name="MyButton" x:FieldModifier="public" />
    

    But you should be asking yourself why you are doing that as it's probably a code smell you should be avoiding.