Select to view content in your preferred language

PointDataSource IsSelected binding doesn't effect anything.

548
3
06-28-2012 12:14 PM
NathanHagen
New Contributor
I'm trying to implement something similar to a featuredatagrid where a datagrid and a map are populated by the same observable collection using MVVM.

I've got them both synced up quite nicely, except that selecting a graphic on the map does not change the underlying datapoint's IsSelected property. I assume that the IsSelectedBinding property is supposed to implement this functionality.

1) Is my assumption right? The sample does not indicate that it is ( http://help.arcgis.com/en/webapi/silverlight/samples/start.htm#UsingPointDataSource ), but in the sample, it appears that the IsSelectedBinding property does nothing at all, which leads me to believe its a bug of some sort. What impact does IsSelectedBinding have on the sample?

2) If my assumption is right about what the purpose of IsSelectedBinding is, how might I go about converting the following code behind into MVVM?

private void GraphicsLayer_MouseLeftButtonDown(object sender, ESRI.ArcGIS.Client.GraphicMouseButtonEventArgs e)
{
    e.Graphic.Selected = !e.Graphic.Selected; 
    DataPoint obs =  ((MapPageViewModel)datagrid.DataContext).Data.Single(datapoint => datapoint == e.Graphic.Attributes["DataContext"]);
    obs.IsSelected = !obs.IsSelected;
}


My XAML is virtually identical to the XAML in the sample, except that there is a datagrid. Here is the PointDataSource elem:

                        <esri:PointDataSource
                            ItemsSource="{Binding Source={StaticResource ViewModel}, Path=Data, Mode=TwoWay}"
                            XCoordinateBinding="{Binding X}"
                            YCoordinateBinding="{Binding Y}"
                            IsSelectedBinding="{Binding IsSelected, Mode=TwoWay}">
                        </esri:PointDataSource>


My DataPoint class is identical to the example.

Hopefully someone knows a thing or two about this feature. There doesn't seem to be many examples of it online (only one post on these forums).

Thanks.
0 Kudos
3 Replies
ae
by
Frequent Contributor
Did you ever figure out what the problem was? I'm trying to use isSelectedBinding in pointdatasource in WPF and experience the same problem as you (i.e. the isSelectedBinding does not update when the isSelected property has been changed). The X and Y bindings works perfectly fine though.
0 Kudos
JoeHershman
MVP Alum
I agree that it seems that it should work as you describe, but the binding is a one way binding from the DataPoint to the Graphic only.  So Selecting the Graphic does not change the ViewModel, but changng IsSelected on the ViewModel will update the Graphic


        private void GraphicsLayer_MouseLeftButtonDown(object sender, ESRI.ArcGIS.Client.GraphicMouseButtonEventArgs e)
        {
            //Get the bound ViewModel
            var dataPoint = e.Graphic.Attributes["DataContext"] as DataPoint;
            if ( dataPoint == null ) return;


            //Change IsSelected - will change the Graphic also
            dataPoint.IsSelected = !dataPoint.IsSelected;
        }



I believe this would toggle the Selected state of both Graphic and DataGrid in one shot

Good Luck
Thanks,
-Joe
0 Kudos
NathanHagen
New Contributor
I never found a solution through ESRI's tools. I still don't know if its a bug or a missing feature.

I ended up solving this problem by implementing the messenger system from MVVMLight along with some attached behavior using System.Windows.Interactivity.

Here is the message.

    /// <summary>
    /// Class representing messages to be sent when DataPoints get selected.
    /// 
    /// </summary>
    public class DataPointSelectedMessage : GenericMessage<List<DataPoint>>
    {
        public DataPointSelectedSource Identifier { get; set; }

        public DataPointSelectedMessage(List<DataPoint> data)
            : base(data)
        {
        }
    }


Defining the behavior:

    /// <summary>
    /// Behavior attaching to a button.
    /// </summary>
    public class DataPointGraphicSelectedBehavior : Behavior<GraphicsLayer>
    {
        /// <summary>
        /// Event that occurs when something is attached to this.
        /// AssociatedObject is the object that we're attaching this to.
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.MouseLeftButtonUp += new GraphicsLayer.MouseButtonEventHandler(AssociatedObject_Click);
        }

        /// <summary>
        /// What do we want to do when the associated object is clicked?
        /// </summary>
        /// <param name="sender">Sender (associated object?)</param>
        /// <param name="e"></param>
        void AssociatedObject_Click(object sender, GraphicMouseButtonEventArgs e)
        {

            //DataPoint Point = e.Graphic.Attributes["DataContext"] as DataPoint;
            //Point.SelectMe(DataPointSelectedSource.Map);
            List<DataPoint> listofpointselected = new List<DataPoint>();
            listofpointselected.Add((DataPoint)e.Graphic.Attributes["DataContext"]);
            Messenger.Default.Send(new DataPointSelectedMessage(listofpointselected) { Identifier = DataPointSelectedSource.Map });
        }

        protected override void OnDetaching()
        {
            AssociatedObject.MouseLeftButtonDown -= AssociatedObject_Click;
            base.OnDetaching();
        }
    }


Attaching the behavior:

                <esri:GraphicsLayer ID="graphics">

                    <i:Interaction.Behaviors>
                        <mvBehaviours:DataPointGraphicSelectedBehavior />
                    </i:Interaction.Behaviors>

                ...

                </esri:GraphicsLayer>


I just announce that a point as been selected, and the datapoints all listen and check if they're the one thats been called. Then they change their status to correspond to it, which propogates across the app. Alternatively, other objects can listen for changes, and act accordingly (specifically, I can keep track of which are selected in collections).


This is probably more complex than and less performant than minerjoe's suggestion, but I've found that the messenger system makes things a bit more flexible for my purposes, and allows me to have more information about where the selection is coming from, and I don't have to worry about tying codebehind to my viewmodel--instead, the attached behavior (which i consider to be basically code-behind, though it technically isn't) just sends a generic notification to a central messenger that an event has occurred, and I can very cleanly and easily register listeners for when the event happens.
0 Kudos