AnsweredAssumed Answered

Can I show callouts using MVVM ?

Question asked by kirkKuykendall on Jul 24, 2019
Latest reply on Jul 25, 2019 by minerjoe

I would like to use MVVM to show callouts.

 

I'm able to use code that  Thad Tilton posted here in the Show Callout sample in the viewer.

It's not very pretty, but it works:

It doesn't use MVVM.  Here's the code:

private void Initialize()
{
    Basemap myBasemap = Basemap.CreateStreets();
    Map myMap = new Map(myBasemap);
    MyMapView.Map = myMap;
    MyMapView.GeoViewTapped += MyMapView_GeoViewTapped;
    //this.DataContext = _vm;
}

private void MyMapView_GeoViewTapped(object sender, esriCtrls.GeoViewInputEventArgs e)
{
    MapPoint mapLocation = e.Location;
    Geometry myGeometry = GeometryEngine.Project(mapLocation, SpatialReferences.Wgs84);
    MapPoint projectedLocation = (MapPoint)myGeometry;
    esriCtrls.Callout c = new esriCtrls.Callout()
    {
        Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.CornflowerBlue),
        BorderBrush = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.PaleVioletRed),
        BorderThickness = new System.Windows.Thickness(5, 5, 5, 3),
        Content = $"Lat: {projectedLocation.Y:F3} Long:{projectedLocation.X:F3}"
    };
    GeoView.SetViewOverlayAnchor(c, e.Location);
    MyMapView.Overlays.Items.Add(c);
    //_vm.MyCallouts.Add(c);
}

This is where I get lost, this xaml compiles:

<Grid>
    <esri:MapView x:Name="MyMapView">
        <esri:MapView.Overlays>
            <esri:OverlayItemsControl ItemsSource="{Binding MyOverlays}"/>
        </esri:MapView.Overlays>
    </esri:MapView>
    <Border Style="{StaticResource BorderStyle}">
        <TextBlock Text="Tap to show a callout."
                FontWeight="SemiBold"
                TextAlignment="Center" />

    </Border>
</Grid>

Here's my viewmodel (PropertyChangedBase implements INotifyPropertyChanged):

public class MyVM: PropertyChangedBase
{
    public ObservableCollection<esriCtrls.Callout> MyCallouts { get; private set; } =
        new ObservableCollection<esriCtrls.Callout>();
       
    public MyVM()
    {
    }
}

Uncommented/commented code to use vm:

private void Initialize()
{
    Basemap myBasemap = Basemap.CreateStreets();
    Map myMap = new Map(myBasemap);
    MyMapView.Map = myMap;
    MyMapView.GeoViewTapped += MyMapView_GeoViewTapped;
    this.DataContext = _vm;
}

private void MyMapView_GeoViewTapped(object sender, esriCtrls.GeoViewInputEventArgs e)
{
    MapPoint mapLocation = e.Location;
    Geometry myGeometry = GeometryEngine.Project(mapLocation, SpatialReferences.Wgs84);
    MapPoint projectedLocation = (MapPoint)myGeometry;
    esriCtrls.Callout c = new esriCtrls.Callout()
    {
        Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.CornflowerBlue),
        BorderBrush = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.PaleVioletRed),
        BorderThickness = new System.Windows.Thickness(5, 5, 5, 3),
        Content = $"Lat: {projectedLocation.Y:F3} Long:{projectedLocation.X:F3}"
    };
    GeoView.SetViewOverlayAnchor(c, e.Location);
    //MyMapView.Overlays.Items.Add(c);
    _vm.MyCallouts.Add(c);
}

I get a run-time error before I even tap on the screen:

System.Windows.Data Error: 2 : 
Cannot find governing FrameworkElement or FrameworkContentElement for target element.
BindingExpression:Path=MyOverlays; DataItem=null;
target element is 'OverlayItemsControl' (HashCode=19513753);
target property is 'ItemsSource' (type 'IEnumerable')

With this xaml also fails:

<esri:MapView x:Name="MyMapView">
    <esri:MapView.Overlays>
        <esri:OverlayItemsControl
        ItemsSource="{Binding Path=DataContext.MyOverlays, RelativeSource={RelativeSource AncestorType={x:Type esri:MapView}}}"/>

    </esri:MapView.Overlays>
</esri:MapView>

But with a different error:

System.Windows.Data Error: 4 : Cannot find source for binding with reference

'RelativeSource FindAncestor, AncestorType='Esri.ArcGISRuntime.UI.Controls.MapView', AncestorLevel='1''.

BindingExpression:Path=DataContext.MyOverlays; DataItem=null;

target element is 'OverlayItemsControl' (HashCode=16581154);

target property is 'ItemsSource' (type 'IEnumerable')

 

Looking at the live visual tree on the version that works (with no mvvm), I see the callout textbox under the mapview:

 

Any clues or suggestions are greatly appreciated!

Outcomes