Polygon is not being rendered on InformationLayer...

4 posts, 0 answers
  1. Yan Moura
    Yan Moura avatar
    33 posts
    Member since:
    Feb 2010

    Posted 16 Sep 2011 Link to this post

    Hi,

    I am trying to trace a polygon on the information layer with data retrieved from SQL Server.
    Everything SEEMS fine, but the fact is that the polygon is NOT being rendered!

    I have this LoadPolygon function that invokes the proper stored procedure in MSSQL and when the data is fully loaded, it triggs the LoadedPolygon event. I have checked and the data IS being properly loaded in the LoadedPolygon through the string var MinnesotaState (the polygon should be a stroke line surrounding the MN state). Only the RadMap is declared in the XAML file and all the rest is instantiated programatically in the xaml.cs code (the information layer, the SQLGeospatialDataReader and the MapShapeFill).

    The data loaded is in the format:
    POLYGON ((-96.799938 46.817947, -96.799911999999992 46.817628, ... etc ...  ))

    The application compiles and run smoothly (no warnings or errors), but the polygon itself is NEVER rendered...

    What am I missing here?

    Thanks!



    Here my "MainPage.xaml":

    <UserControl x:Class="YV_GIS.MainPage"
        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"
        mc:Ignorable="d"
        d:DesignHeight="600" d:DesignWidth="1000"
        xmlns:telerikQuickStart="clr-namespace:Telerik.Windows.Controls.QuickStart;assembly=Telerik.Windows.Controls"
        xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation">

        <Grid x:Name="LayoutRoot" Background="White" Height="600" Width="1000">
            <telerik:RadMap x:Name="radMap" Width="1000" Height="600" />
        </Grid>
    </UserControl>


    And here my "MainPage.xaml.cs":

    namespace YV_GIS
    {
        public partial class MainPage : UserControl
        {
            public MainPage()
            {
                InitializeComponent();
                this.radMap.Provider = new BingMapProvider(MapMode.Aerial, true, "myBingKey");
                this.radMap.InitializeCompleted += new EventHandler(radMap_InitializeCompleted);
            }

            private void radMap_InitializeCompleted(object sender, EventArgs e)
            {
                LoadPolygon("ReadPolygon.aspx");
            }

            private void LoadPolygon(String myurl)
            {
                WebClient webClient = new WebClient();
                webClient.Headers["content-type"] = "application/x-www-form-urlencoded";
                webClient.Encoding = Encoding.UTF8;
                webClient.UploadStringCompleted += new UploadStringCompletedEventHandler(LoadedPolygon);
                webClient.UploadStringAsync(new Uri(SERVER_ADDRESS + myurl, UriKind.Absolute), "POST", "");
            }

            private void LoadedPolygon(object sender, UploadStringCompletedEventArgs e)
            {
                XDocument xmlDoc = XDocument.Parse(e.Result);
                var MyPolygons = from MyPolygon in xmlDoc.Descendants("geodata")
                               select new
                               {
                                   polygon = MyPolygon.Element("polygon").Value,
                               };

                String MinnesotaState = "";

                foreach (var MyPolygon in MyPolygons)
                    MinnesotaState += MyPolygon.polygon;

                SqlGeospatialDataReader MySQLGDR = new SqlGeospatialDataReader();
                MySQLGDR.Source = MinnesotaState;

                InformationLayer MyInfoLayer = new InformationLayer();
                MyInfoLayer.Reader = MySQLGDR;

                MapShapeFill MyShapeFill = new MapShapeFill();
                MyShapeFill.Fill = new SolidColorBrush(Colors.Gray);
                MyShapeFill.Stroke = new SolidColorBrush(Colors.Red);
                MyShapeFill.StrokeThickness = 3;

                MyInfoLayer.ShapeFill = MyShapeFill;
                MyInfoLayer.UpdateLayout();
            }
        }
    }
  2. Andrey
    Admin
    Andrey avatar
    1681 posts

    Posted 21 Sep 2011 Link to this post

    Hi Yan Moura,

    First you should add the information layer to the map control in the LoadedPolygon method like the following:
    radMap.Items.Add(MyInfoLayer);

    The SqlGeospatialDataReader requires IEnumerable type for its Source property. Also the SqlGeospatialDataReader requires to use the GeospatialPropertyName property. It must define the name of the wkt geometry property of the class you use for collection. For more information please take a look at the Wkt Geospatial Data Reader example and the following documentation topic:
    http://demos.telerik.com/silverlight/#Map/WktReader
    http://www.telerik.com/help/silverlight/radmap-features-sql-geospatial-data.html

    Best wishes,
    Andrey Murzov
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  3. DevCraft banner
  4. Yan Moura
    Yan Moura avatar
    33 posts
    Member since:
    Feb 2010

    Posted 21 Sep 2011 Link to this post

    Hi Andrei!

    Thanks for the answer -- however in the meantime, I found a solution by myself that is working and that I would share:

    It is important to mention that I started figuring out things from the Telerik sample that Bart gave to me at:
    http://demos.telerik.com/silverlight/#Map/WktReader

    1. I modified the XAML file to the following, in order to have the least as possible declared there:
    (Basically I only have the objects declared, as all the rest will be done in the XAML.CS file)

    <UserControl x:Class="YV_GIS.MainPage"
        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"
        mc:Ignorable="d"
        d:DesignHeight="600" d:DesignWidth="1000"
        xmlns:telerikQuickStart="clr-namespace:Telerik.Windows.Controls.QuickStart;assembly=Telerik.Windows.Controls"
        xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation">

        <Grid x:Name="LayoutRoot" Background="White" Height="600" Width="1000">
            <telerik:RadMap x:Name="radMap" Width="1000" Height="600">

                <telerik:InformationLayer>
                    
                    <telerik:InformationLayer.Reader>
                        <telerik:SqlGeospatialDataReader x:Name="MySQLReader" />
                    </telerik:InformationLayer.Reader>
                    
                    <telerik:InformationLayer.ShapeFill>
                        <telerik:MapShapeFill x:Name="MyShapeFill" />
                    </telerik:InformationLayer.ShapeFill>
                    
                </telerik:InformationLayer>
                
            </telerik:RadMap>
            <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="-19,383,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
        </Grid>

    </UserControl>

    2. Then I removed the 'WkDataViewModel.cs' and 'WktDatarow.cs' classes from the project and moved the essential of them to my XAML.CS file.

    3. And here it goes my XAML.CS file...

    It will navigate and zoom the map to the USA Minnesota state and will trace a triangle with red borders over that. The most interesting is that it is an asynchronous task, and differently from the original Telerik sample, you DON'T have to declare the SQLGeospatial coordinates directly in your code; you can, instead, have a separated class that reads it from DB and then load data on-the-fly into the information layer. This i specially interesting because the polygon can be traced onto the information layer at any time.

    To see a good example as it works, add a button to your application and call the TracePolygon() function in the CLICK event of the button. Then run the application, await until the map load (or not) and then click the button any time you want: you will see that the polygon will be traced properly!

    In my case, I added a class that loads the coordinates from MSSQL DB and after it is fully loaded, it triggs an event that traces the polygon with the loaded coords.


    namespace YV_GIS
    {
        public partial class MainPage : UserControl
        {
            double _LATITUDE;
            double _LONGITUDE;

            // this collection and type came from the WktDataViewModel class was removed from the project
            // BEGIN
            private Collection<GeoType> _GeoShapes;
            public Collection<GeoType> GeoShapes
            {
                get
                   { return this._GeoShapes; }
                set
                   { this._GeoShapes = value; }
            }
            // END

            public MainPage()
            {
                InitializeComponent();
                this.radMap.Provider = new BingMapProvider(MapMode.Aerial, true, "Bing Credentials");
                this.radMap.InitializeCompleted += new EventHandler(radMap_InitializeCompleted);
                TracePolygon();
            }

            private void radMap_InitializeCompleted(object sender, EventArgs e)
            {
                Navigate(CoordToDec(45, 34, 02,"N"), CoordToDec(94, 16, 04,"W"));
                Zoom(5);
            }

            // This are functions to provide automatic navigation, zoom and also a coordinate convertion
            // BEGIN
            private void Navigate(double latitude,double longitude)
            {
                Location MyLocation = new Location();
                MyLocation.Latitude = latitude;
                MyLocation.Longitude = longitude;
                this.radMap.Center = MyLocation;
            }

            private void Zoom(int zoom)
            {
                this.radMap.ZoomLevel = zoom;
            }

            private float CoordToDec(int degrees,float minutes,float seconds,string direction)
            {
                int factor = 1;
                if ((direction == "S") || (direction == "W"))
                    factor = -1;
                return (degrees + (minutes / 60) + (seconds / 3600))*factor;
            }
            // END

            private void TracePolygon()
            {
                this.GeoShapes = new Collection<GeoType>();
                GeoType MyGeometry = new GeoType();
                MyGeometry.Geometry = "POLYGON ((-96.799938 46.817947, -92.799911999999992 46.817628, -92.799911999999992 43.817628, -96.799938 46.817947 ))";

                this.GeoShapes.Add(MyGeometry);
                MySQLReader.Source = this.GeoShapes;
                MySQLReader.GeospatialPropertyName = "Geometry";
                MyShapeFill.Fill = new SolidColorBrush(Colors.Gray);
                MyShapeFill.Stroke = new SolidColorBrush(Colors.Red);
                MyShapeFill.StrokeThickness = 3;
            }
        }

        // this class came from the WktDataRow.cs class that was removed from the project -- I deleted the 'name' property as I didn't need it
        // BEGIN
        public class GeoType
        {
            private string _geometry;
            public string Geometry
            {
                get
                   { return this._geometry; }
                set
                   { this._geometry = value; }
            }
        }
        // END
    }

    NONETHELESS, I still have a question!

    As mentioned above, I have a class named as 'LoadPolygon.aspx.cs' that reads SQL db and pass back the readed data through XML. However it is capturing the data converted to text format with the MSSQL Polygon.STAsText() function, instead the binary data. It is working fine, but I was thinking if maybe it would run faster if I use the hexa data instead the text one?

    And if YES, how could I pass the binary data directly to the SQLGeospatialDataReader?

    Let me show how I am doing it right now...

    Here, my ASPX.CS class that reads the database and put info into XML format:

        public partial class SPReadPolygon : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                // Run the Stored Procedure that will get data
                SqlConnection myConn = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString);
                SqlCommand myCommand = new SqlCommand("EXEC GetCoordinates", myConn);
                myConn.Open();
                SqlDataReader myTable;
                myTable = myCommand.ExecuteReader();

                // Put text data into the XML
                string xmloutput = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<dataset>\n";
                while (myTable.Read())
                {
                    xmloutput += "<geodata>\n";
                    xmloutput += "<polygon>" + myTable["Point"].ToString() + "</polygon>\n";
                    xmloutput += "</geodata>\n";
                }
                myTable.Close();
                myConn.Close();
                xmloutput += "</dataset>\n";

                // Send data back to the caller
                Response.Cache.SetNoStore();
                Response.ContentType = "text/xml";
                Response.Write(xmloutput);
            }
        }

    And here, the event function in the XAML.CS file that captures the data

            private void LoadPolygon(String myurl)
            {
                WebClient webClient = new WebClient();
                webClient.Headers["content-type"] = "application/x-www-form-urlencoded";
                webClient.Encoding = Encoding.UTF8;
                webClient.UploadStringCompleted += new UploadStringCompletedEventHandler(LoadedPolygon);
                webClient.UploadStringAsync(new Uri(SERVER_ADDRESS + myurl, UriKind.Absolute), "POST", "");
            }

            private void LoadedPolygon(object sender, UploadStringCompletedEventArgs e)
            {

                XDocument xmlDoc = XDocument.Parse(e.Result);
                var MyPolygons = from MyPolygon in xmlDoc.Descendants("geodata")
                               select new
                               {
                                   polygon = MyPolygon.Element("polygon").Value,
                               };

                String MinnesotaState = "";

                foreach (var MyPolygon in MyPolygons)
                    MinnesotaState += MyPolygon.polygon;

                this.GeoShapes = new Collection<GeoType>();
                GeoType MyGeometry = new GeoType();
                MyGeometry.Geometry = MinnesotaState;
                this.GeoShapes.Add(MyGeometry);
                MySQLReader.Source = this.GeoShapes;
                MySQLReader.GeospatialPropertyName = "Geometry";

                MyShapeFill.Fill = new SolidColorBrush(Colors.Gray);
                MyShapeFill.Stroke = new SolidColorBrush(Colors.Red);
                MyShapeFill.StrokeThickness = 3;
            }

    As mentioned above, it works.

    But my question is - how to pass the binary data (instead the text data) to the MySQLReader.Source?

    Thanks!
  5. Andrey
    Admin
    Andrey avatar
    1681 posts

    Posted 23 Sep 2011 Link to this post

    Hello Yan Moura,

    Yes, you can use binary data for the SQLGeospatialDataReader.
    In addition to Wkt the SQLGeospatialDataReader can also use the Wkb (Well known binary) format for Geospatial data. So, if the Geometry property of the GeoType class is be represented a the binary type (byte[]), then it will be read as Wkb. You can use the Polygon.STAsBinary() of MSSQL to get data in binary format.
    I hope this information helps.

    Best wishes,
    Andrey Murzov
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

Back to Top