Command Binding Null object problem

Topics: Prism v4 - Silverlight 4
Sep 21, 2012 at 1:41 PM

hi, 

I am creating a sample project with using esri silverlight api. I created a click command but an error occuring following code.

<UserControl x:Class="GIS.Views.MapView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:esri="clr-namespace:ESRI.ArcGIS.Client;assembly=ESRI.ArcGIS.Client"
             xmlns:cmd="clr-namespace:Infrastructure.Commands;assembly=Infrastructure"
    mc:Ignorable="d"
             VerticalAlignment="Stretch"
             HorizontalAlignment="Stretch"
    d:DesignHeight="300" d:DesignWidth="400">
    
    <Grid x:Name="LayoutRoot" Background="White">
        <esri:Map x:Name="MyMap" 
                  VerticalAlignment="Stretch" 
                  HorizontalAlignment="Stretch" 
                  cmd:MouseClick.Command="{Binding Map_Click}">
            <esri:ArcGISDynamicMapServiceLayer ID="MyLayer" Url="http://serverapps.esri.com/ArcGIS/rest/services/California/MapServer" />
        </esri:Map>
    </Grid>
</UserControl>
MouseClick event code is following
   public class MouseClick
    {
         public static ICommand GetCommand(Map map)
         {
             return (ICommand) map.GetValue(CommandProperty);
         }
         public static void SetCommand(Map map, ICommand value)
         {
             map.SetValue(CommandProperty, value);
         }

        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.RegisterAttached("Command",
            typeof (ICommand),
            typeof (MouseClick),
            new PropertyMetadata(OnSetCommandCallback));
        
        private static readonly DependencyProperty MouseClickCommandBehaviorProperty =
            DependencyProperty.RegisterAttached(
            "ClickCommandBehavior",
            typeof(MouseClickBehavior),
            typeof(MouseClick),
            null);
        
        public static object GetCommandParameter(DependencyObject obj)
        {
            return obj.GetValue(CommandParameterProperty);
        }

        public static void SetCommandParameter(DependencyObject obj, object value)
        {
            obj.SetValue(CommandParameterProperty, value);
        }

        // Using a DependencyProperty as the backing store for CommandParameter.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.RegisterAttached("CommandParameter",
            typeof(object),
            typeof(MouseClick),
            new PropertyMetadata(OnSetCommandParameterCallback));


        private static void OnSetCommandParameterCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            Map map = dependencyObject as Map;
            if (map != null)
            {
                MouseClickBehavior behavior = GetOrCreateBehavior(map);
                behavior.CommandParameter = e.NewValue;
            }
        }

        private static void OnSetCommandCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            Map map = dependencyObject as Map;
            if (map != null)
            {
                MouseClickBehavior behavior = GetOrCreateBehavior(map);
                behavior.Command = e.NewValue as ICommand;
            }
        }

        private static MouseClickBehavior GetOrCreateBehavior(Map map)
        {
            MouseClickBehavior behavior = map.GetValue(MouseClickCommandBehaviorProperty) as MouseClickBehavior;
            
            if (behavior == null)
            {
                behavior = new MouseClickBehavior(map);
                map.SetValue(MouseClickCommandBehaviorProperty, behavior);
            }

            return behavior;
        }
    }
And MapViewModel is here
    
   public class MapViewModel : IViewModel, IMapViewModel
    {
        private double y;
        private double x;
        private int dpi;
        private Size mapSize;

        public double Y
        {
            get { return y; }
            set
            {
                y = value;
                NotifyChange("Y");
            }
        }

        public double X
        {
            get { return x; }
            set
            {
                x = value;
                NotifyChange("X");
            }
        }
        
        public int Dpi
        {
            get
            {
                return dpi;
            }
            set
            {
                dpi = value;
                NotifyChange("Dpi");
            }
        }

        private readonly MapClickEvent mapClick;

        public DelegateCommand<object> Map_Click{ get; set; }
        public DelegateCommand<object> Size_Change { get; set; }

        public MapViewModel(IEventAggregator eventAggregator)
        {
            Dpi = 96;
            mapClick = eventAggregator.GetEvent<MapClickEvent>();
            Map_Click = new DelegateCommand<object>(OnClickCommand);
            Size_Change = new DelegateCommand<object>(OnSizeChangedCommand);
        }

        public void OnClickCommand(object obj)
        {
            Map.MouseEventArgs eventArgs = (Map.MouseEventArgs)obj;
            MapClickPayload payload = new MapClickPayload
                                          {
                                              X = eventArgs.MapPoint.X,
                                              Y = eventArgs.MapPoint.Y,
                                              MinX = eventArgs.MapPoint.Extent.XMin,
                                              MinY = eventArgs.MapPoint.Extent.YMin,
                                              MaxX = eventArgs.MapPoint.Extent.XMax,
                                              MaxY = eventArgs.MapPoint.Extent.YMax,
                                              Screen = mapSize,
                                              Dpi = dpi
                                          };
            mapClick.Publish(payload);
        }

        public void OnSizeChangedCommand(object obj)
        {
            MapInfo info = obj as MapInfo;

            if (info != null) 
                mapSize = info.MapSize;
        }
    }
when I click the Map object, 

OnClickCommand(object obj) paramaeter obj is coming null.

I mean is that true way?
Developer
Sep 21, 2012 at 5:46 PM

Hi,

As far as I know, in this case receiving a null value as the parameter in your OnClickCommand method is the expected behavior.

For example, when you define a DelegateCommand like this:

DelegateCommand<int> SampleCommand { get; set: }

You are defining a DelegateCommand that expects a CommandParameter of type int. Then, when using this command in a button, you could do something like this:

<Button Command="{Binding SampleCommand}" CommandParameter="1" />

And when the button is clicked the OnClickCommand method would receive 1 as the parameter.

I believe this is similar to your scenario. As it can be seen in the code snippets you posted, the MouseClick class defines a CommandParameter property, which (based on my understanding) is used to define the parameter to be passed to the command. However, you are never setting a MouseClick.CommandParameter property in your code and, as the command doesn't have any parameter defined, the OnClickCommand receives a null value.

On a side note, it's important to note that events and commands are different things, and that a command parameter is not the argument of an event. Therefore, what your OnClickCommand method is receiving is not the MouseEventArgs of the Map control.

If you wish to pass the arguments of an event as a parameter to a command, I believe you could find the EventToCommand action of the MVVM Light Toolkit useful:

I hope this helps,

Damian Cherubini
http://blogs.southworks.net/dcherubini