Hi, MapWINGIS community. Need assist. I have created a point Shapefile in MapWIndow5, containing about 400 points from Lat and Long. Each Point contains 52 Fields and Values that are displaying perfectly in MapWindow5. But when I add this Point Shapefile in C# Windows Application, Selected Points are not displaying Fields and Values. cmSelection, cmNone, cmIdentify, cmSelectByPolygon - all produce Nothing! Meanwhile other Polygon Shapefiles are displaying both Fields and Values perfectly with cmIdentify tool. How can I get these Points to display their Fields and Vaues? Thank You in advance!
Hello @sw4web, and welcome.
Have you flagged the layer as Identifiable or Selectable? I presume that you have, if it works for other layers.
You can set up a Global Callback, which may tell you if something is going wrong in the OCX.
Finally, if you don’t mind, can you post the Shapefile to this forum and someone can take a look at it?
Regards,
Jerry.
Thanks, Jerry. Here is the Point Shapefile that doesn’t show Point Info:din.zip (26.8 KB)
This Shapefile works with [ToolTip.cs] and EditAttributes.cs (https://www.mapwindow.org/documentation/mapwingis4.8/_tool_tip_8cs-example.html):nigeria_administrative.zip (58.4 KB)
N.B. I am unable to a Global Callback
Thank you for your kind assistance.
Hello @sw4web
In what seems to be opposite of what you are saying, I originally was not able to Identify shapes from the nigeria_administrative layer, but I was able to Select and Identify shapes from the din layer.
The projection of the nigeria_administrative layer is not recognized as a well-known projection, while the projection of the din is recognized. If you try to load both of these layers at the same time, without allowing for mismatched projections, then one of them is likely to misbehave. I was able to load both of them with the following settings, and I was then able to Identify shapes from each layer.
Here is some of the code that I am using (in VB.NET):
In Form_Load:
AxMap1.Projection = tkMapProjection.PROJECTION_GOOGLE_MERCATOR ' although .PROJECTION_NONE also worked
AxMap1.GrabProjectionFromData = False ' you should set True if using PROJECTION_NONE
' these are important for mismatched projections
Dim gs As GlobalSettings = new GlobalSettings()
gs.AllowProjectionMismatch = True
gs.ReprojectLayersOnAdding = True
My Test2 button simply does the following:
AxMap1.CursorMode = tkCursorMode.cmIdentify ' .cmSelection '
AxMap1.MapCursor = tkCursor.crsrMapDefault
A number of Event Handlers:
Private Sub AxMap1_ProjectionChanged(sender As Object, e As EventArgs) Handles AxMap1.ProjectionChanged
Debug.WriteLine("AxMap1_ProjectionChanged: " & AxMap1.Projection.ToString)
End Sub
Private Sub AxMap1_ProjectionMismatch(sender As Object, e As _DMapEvents_ProjectionMismatchEvent) Handles AxMap1.ProjectionMismatch
Debug.WriteLine("AxMap1_ProjectionMismatch")
End Sub
Private Sub AxMap1_SelectionChanged(sender As Object, e As _DMapEvents_SelectionChangedEvent) Handles AxMap1.SelectionChanged
Debug.WriteLine("AxMap1_SelectionChanged")
End Sub
Private Sub AxMap1_ShapeIdentified(sender As Object, e As _DMapEvents_ShapeIdentifiedEvent) Handles AxMap1.ShapeIdentified
Debug.WriteLine("AxMap1_ShapeIdentified")
Dim sf As Shapefile = AxMap1.get_Shapefile(e.layerHandle)
Debug.WriteLine("Name = " & sf.CellValue(sf.FieldIndexByName("Name"), e.shapeIndex))
End Sub
Private Sub AxMap1_LayerReprojected(sender As Object, e As _DMapEvents_LayerReprojectedEvent) Handles AxMap1.LayerReprojected
Debug.WriteLine("AxMap1_LayerReprojected: ")
End Sub
Private Sub AxMap1_ChooseLayer(sender As Object, e As _DMapEvents_ChooseLayerEvent) Handles AxMap1.ChooseLayer
e.layerHandle = 0
End Sub
And here’s the VS Output window:
Please let me know if this helps.
Regards,
Jerry.
Thanks a million, Jerry. I will implement as you suggested and revert to you ASAP.
Thank you!
Hi, Jerry, sorry to bug you soon again. I am using C# in Visual Studio, and I ran into two small hitches, if you could just quickly take a look. To you it’s a piece of cake. To me - headache.
Take a look at the screen shot. The code you suggested generated 2 Errors.
1 - Debug.WriteLine("AxMap1_ProjectionChanged: " + AxMap1.Projection.ToString); - Error message reads: "Object does not contain definition for ‘Projection’ and no accessible ‘Projection’ method accepting
a first argument of type 'object’could be found. (Are you missing a using directive or an assembly reference?"I’ve checked my “Usings” and they look ok. Reference looks ok.
2 - Debug.WriteLine("Name = " + sf.EditCellValue(sf.FieldIndexByName(“Name”), e.shapeIndex)); - Error message reads: “Non-invocable member ‘IShapefile.FieldIndexByName[string]’ cannot be used like a method.”
Why is now IShape in the querry?
I am sure once I can fix these 2 minor errors, I’ll be good to go.
Thanks once again for your time.
Hello.
Sorry about the mixup. The methods from the library are exposed differently depending on the calling language.
In VB, many of the properties go by their Name, while from c#, they require the ‘get_’ and ‘set_’ prefixes.
So in your case, you will use get_Projection and get_FieldNameByIndex.
IShape and IShapefile are the names of the COM Interfaces that are exposed from the library.
Regards.
Thanks for the added info. Will proceed and let you know thus far.
Hi, Jerry.
I was able to get over the second error msg. But I could not fix the first - Debug.WriteLine("AxMap1_ProjectionChanged: " + AxMap1.get_Projection.ToString); See attachment >>Projection.
However, I edited out the line and tried to run. I get this long line, combining both Field and Values in a continuous single line,
instead of breaking to form vertical. See attachment>>>Points.
However, I tried another Polygon Shapefile, see attached >>>States.zip, and everything works just fine with
EditAttributes and bam! everything works perfectly. See png >>> Shapes.
What am I missing, please?
Thank you once more.
States.zip (1.16 MB)
Hello @sw4web.
I’m sorry for the delay, I have too many irons in the fire.
Regarding the code in the ProjectionChanged event, the following syntax works. Sometimes you have to play with it a little to see what works. The Intellisense didn’t show the get_Projection, but did show the Projection. Then, of course, you need the open/close parens at the end of the ToString() function.
Debug.WriteLine("axMap1_ProjectionChanged: " + axMap1.Projection.ToString());
Regarding the issue of the Points vs the States, I’m not sure what the problem is. Rather than posting an image of your source code, if you could post the entire text, then I can paste it in and debug it.
I still suspect that there’s something odd about the DIN layer, but I don’t know what.
Regards,
Jerry.
Yes this code did not give error: Debug.WriteLine("axMap1_ProjectionChanged: " + axMap1.Projection.ToString());
BUT POINTS show nothing.
HERE IS THE FULL CODE - with notes
THIS LOADS THE POINT SHAPEFILE WITH CLICK_EVENT
(SEE Screenshot Point with this code enbled: //sf.Labels.Generate(expression, tkLabelPositioning.lpCentroid, false);
//sf.Labels.TextRenderingHint = tkTextRenderingHint.SystemDefault;)
With this code disabled, you draw a blank)
private void BtnLARGE_Click(object sender, EventArgs e)
{
string filename = dataPath + @“F:\0001a_iDiGiMapDNG1.0b\FINAL\FINAL_DIN\FINAL_DIN\Dams\LargeDams_point.shp”;
var sf = new Shapefile();
sf.Open(@“F:\0001a_iDiGiMapDNG1.0b\FINAL\FINAL_DIN\FINAL_DIN\Dams\LargeDams_point.shp”, null);
int layerHandle = axMap1.AddLayer(sf, true);
sf = axMap1.get_Shapefile(layerHandle); // in case a copy of shapefile was created by GlobalSettings.ReprojectLayersOnAdding
if (!sf.Table.StartEditingTable(null))
{
MessageBox.Show(“Failed to start edit mode: " + sf.Table.ErrorMsg[sf.LastErrorCode]);
}
else
{
string expression = “”;
for (int i = 1; i < sf.NumFields; i++) // all the fields will be displayed apart the first one
{
expression += “[” + sf.Field[i].Name + “]”;
if (i != sf.NumFields - 1)
{
const string endLine = “”\n”";
expression += string.Format("+ {0} +", endLine);
}
}
//sf.Labels.Generate(expression, tkLabelPositioning.lpCentroid, false);
//sf.Labels.TextRenderingHint = tkTextRenderingHint.SystemDefault;
axMap1.SendMouseDown = true;
axMap1.CursorMode = tkCursorMode.cmNone;
axMap1.MouseDownEvent += AxMap1MouseDownEvent2; // change MapEvents to axMap1
this.ZoomToValue(sf, “Name”, “Dams”);
}
private void AxMap1MouseDownEvent2(object sender, _DMapEvents_MouseDownEvent e)
{
int layerHandle = axMap1.get_LayerHandle(0); // it’s assumed here that the layer we want to edit is the first 1 (with 0 index)
Shapefile sf = axMap1.get_Shapefile(layerHandle);
if (sf != null)
{
double projX = 0.0;
double projY = 0.0;
axMap1.PixelToProj(e.x, e.y, ref projX, ref projY);
object result = null;
Extents ext = new Extents();
ext.SetBounds(projX, projY, 0.0, projX, projY, 0.0);
if (sf.SelectShapes(ext, 0.0, SelectMode.INCLUSION, ref result))
{
int[] shapes = result as int[];
if (shapes == null) return;
if (shapes.Length > 1)
{
string s = “More than one shapes were selected. Shape indices:”;
for (int i = 0; i < shapes.Length; i++)
s += shapes[i] + Environment.NewLine;
MessageBox.Show(s);
}
else
{
sf.set_ShapeSelected(shapes[0], true); // selecting the shape we are about to edit
axMap1.Redraw(); Application.DoEvents();
Form form = new Form();
for (int i = 0; i < sf.NumFields; i++)
{
System.Windows.Forms.Label label = new System.Windows.Forms.Label();
label.Left = 15;
label.Top = i * 30 + 5;
label.Text = sf.Field[i].Name;
label.Width = 60;
form.Controls.Add(label);
TextBox box = new TextBox();
box.Left = 80;
box.Top = label.Top;
box.Width = 80;
box.Text = sf.CellValue[i, shapes[0]].ToString();
box.Name = sf.Field[i].Name;
form.Controls.Add(box);
}
form.Width = 180;
form.Height = sf.NumFields * 30 + 70;
Button btn = new Button
{
Text = “Ok”,
Top = sf.NumFields * 30 + 10,
Left = 20,
Width = 70,
Height = 25
};
btn.Click += BtnClick;
form.Controls.Add(btn);
btn = new Button
{
Text = “Cancel”,
Top = sf.NumFields * 30 + 10,
Left = 100,
Width = 70,
Height = 25
};
btn.Click += BtnClick;
form.Controls.Add(btn);
form.FormClosed += FormFormClosed;
form.Text = "Shape: " + shapes[0];
form.ShowInTaskbar = false;
form.StartPosition = FormStartPosition.CenterParent;
form.FormBorderStyle = FormBorderStyle.FixedDialog;
form.MaximizeBox = false;
form.MinimizeBox = false;
form.ShowDialog(axMap1.Parent);
}
}
}
// Execute this code if you want to save the results.
// sf.StopEditingShapes(true, true, null);
}
//
// Clears selected shapes on the closing of the form
//
private void FormFormClosed(object sender, FormClosedEventArgs e)
{
int layerHandle = axMap1.get_LayerHandle(0);
Shapefile sf = axMap1.get_Shapefile(layerHandle);
if (sf != null)
{
sf.SelectNone();
axMap1.Redraw();
}
}
private void BtnClick(object sender, EventArgs e)
{
Form form = (sender as Control).Parent as Form;
if (form == null) return;
Button btn = sender as Button;
if (btn != null)
{
int layerHandle = axMap1.get_LayerHandle(0);
Shapefile sf = axMap1.get_Shapefile(layerHandle);
if (sf != null)
{
if (btn.Text == “Ok”)
{
// now we shall find the selected shape, the one being edited
// in real-world application would be better of course to store the index of this shape in private variable
int shapeIndex = -1;
for (int i = 0; i < sf.NumShapes; i++)
{
if (sf.ShapeSelected[i])
{
shapeIndex = i;
break;
}
}
if (shapeIndex != -1)
{
foreach (Control control in form.Controls)
{
if (control is TextBox)
{
int fieldIndex = sf.Table.FieldIndexByName[control.Name];
if (fieldIndex != -1)
sf.EditCellValue(fieldIndex, shapeIndex, control.Text);
}
}
sf.Labels.Expression = sf.Labels.Expression; // update the labels
axMap1.Redraw();
}
}
}
}
form.Close();
}
private void ZoomToValue(Shapefile sf, string fieldName, string value)
{
int fieldIndex = sf.Table.FieldIndexByName[fieldName];
if (fieldIndex != -1)
{
for (int i = 0; i < sf.NumShapes; i++)
{
if ((string)sf.CellValue[fieldIndex, i] == value)
{
axMap1.Extents = sf.Shape[i].Extents;
axMap1.MapUnits = tkUnitsOfMeasure.umMeters;
axMap1.CurrentScale = 5000;
}
}
}
}
}
THIS LOADS THE POLYGON SHAPE FILE (STATES)
private void BtnSTATES_Click(object sender, EventArgs e)
{
MapWinGIS.Shapefile couche = new MapWinGIS.Shapefile();
bool a = couche.Open(@“F:\0001a_iDiGiMapDNG1.0b\FINAL\FINAL_DIN\FINAL_DIN\Sates\Nigeria_Poly_export.shp”, null);
int b = axMap1.AddLayer(couche, true);
axMap1.SendMouseDown = true;
axMap1.SendMouseMove = true;
}
THIS LOADS THE POINT SHAPEFILE AND DISPLAYS ONLY FIELDS but VALUES ARE NOT DISPLAYED BOTH FOR
POINT AND POLYGON, BUT AT LEAST POINT DISPLAYS FIELDS IN A POP UP (SEE Screenshot FieldWithoutValues)
private void get_selected_attribute(int layerHandle)
{
var sf = new Shapefile();
try
{
sf = axMap1.get_Shapefile(layerHandle);
string expression = “”;
string data = “”;
for (int i = 1; i < sf.NumFields; i++)
if (i != sf.NumFields - 1)
{
const string endLine = “”\n"";
expression += “[” + sf.Field[i].Name + “]”;
expression += string.Format("+ {0} +", endLine);
}
int fieldIndex = sf.Table.FieldIndexByName[“num”];
if (fieldIndex != -1)
{
for (int i = 0; i < sf.NumSelected; i++)
{
const string endLine = “”\n"";
data += “[” + sf.CellValue[fieldIndex, 1].ToString() + “]”;
expression += string.Format("+ {0} +", endLine);
}
}
//MessageBox.Show("Objects: " + sf.NumSelected.ToString() + "\n Value: " + data_);
MessageBox.Show("Objects: " + sf.NumSelected.ToString() + ",\n Fields: " + expression + ",\n Value: " + data);
//using (Form2 f2 = new Form2(dt))
//{
//f2.ShowDialog();
//}
}
catch (Exception ex)
{
MessageBox.Show("ErrorMessage: " + ex, “ErrorMessage”, MessageBoxButtons.OK);
return;
}
axMap1.SendMouseDown = true;
axMap1.CursorMode = tkCursorMode.cmNone;
axMap1.MouseDownEvent += AxMap1MouseDownEvent2; // change MapEvents to axMap1
this.ZoomToValue(sf, “Name”, “Dams”);
}
N.B. Last thing I tried was REMOVESHAPE example and I keep getting the error message “NOTHING SELECTED”!
I suspect the layer is not being selected, or loaded, and the POINTS are not REAL points on the MapWindow.???
Needs New Drawing Layer or something like that?
Sorry Jerry, more irons now in your fire.
Thanks for making time for me.
Hello, Jerry you’ve forgotten about the discussion we started. Still too many Irons in the fire?
I haven’t been able to put my head around this.
Hello @sw4web
There are few things to note:
-
You should set your map setting and event handlers only once, usually in the Form_Load event, rather than in your various event handlers.
axMap1.SendMouseDown = true; axMap1.CursorMode = tkCursorMode.cmNone; axMap1.MouseDownEvent += AxMap1MouseDownEvent2;
-
When trying to click on a point feature, you need to specify a tolerance, otherwise your mouse click would have to land dead-on the point, which is not likely. I set a tolerance of 100 meters, but since your projection is in Degrees, we have to convert 100 meters to Degrees, as follows, then pass the tolerance into the SelectShapes method:
// for polygon layers, tolerance can be left at zero double tolerance = 0; // but for point layers, we need to buffer the click point if (sf.ShapefileType2D == ShpfileType.SHP_POINT) { tolerance = 100; // meters Utils utils = new Utils(); utils.ConvertDistance(tkUnitsOfMeasure.umMeters, tkUnitsOfMeasure.umDecimalDegrees, ref tolerance); } if (sf.SelectShapes(ext, tolerance, SelectMode.INTERSECTION, ref result)) { .... }
and finally,
- I changed the SelectMode in the SelectShapes method to INTERSECTION, which will work for both Points and Polygons.
So now both Points and Polygons can be selected, depending upon which layer is loaded.
Regards,
Jerry.
Oh my! Jerry, you are God’s gift to humanity, keep it up! I wish you success with all the irons in your fire. Thanks a million!
I’ll fix things up, and let you know ASAP!
Hi, Jerry, one last bugger on this subject. This won’t take a moment of your time. I ran into one tiny issue with buffering points. I can’t seem to figure out where to place the code. Believe me I’ve tried everywhere. If you just point this out to me. Thanks.
@pmeems - if Jerry is a bit tight, just take a second and look at my code. Where do I get this buffer code to work on a Point Shapefile? Thank you.
I’m sorry, @sw4web, but I’m not sure that I understand your question.
If you mean the buffer that I set up prior to the SelectShapes call, I inserted that into your MouseDown event, as shown below (I’ve pasted in the entire modified MouseDown event from your code). You can compare with your original.
If that’s not what you are asking, please clarify what you mean by the “buffer code to work on a Point Shapefile”.
private void AxMap1MouseDownEvent2(object sender, _DMapEvents_MouseDownEvent e)
{
int layerHandle = axMap1.get_LayerHandle(0); // it’s assumed here that the layer we want to edit is the first 1 (with 0 index)
Shapefile sf = axMap1.get_Shapefile(layerHandle);
if (sf != null)
{
double projX = 0.0;
double projY = 0.0;
axMap1.PixelToProj(e.x, e.y, ref projX, ref projY);
object result = null;
Extents ext = new Extents();
ext.SetBounds(projX, projY, 0.0, projX, projY, 0.0);
// for polygon layers, tolerance can be left at zero
double tolerance = 0;
// but for point layers, we need to buffer the click point
if (sf.ShapefileType2D == ShpfileType.SHP_POINT)
{
tolerance = 100; // meters
Utils utils = new Utils();
utils.ConvertDistance(tkUnitsOfMeasure.umMeters, tkUnitsOfMeasure.umDecimalDegrees, ref tolerance);
}
if (sf.SelectShapes(ext, tolerance, SelectMode.INTERSECTION, ref result))
{
int[] shapes = result as int[];
if (shapes == null) return;
if (shapes.Length > 1)
{
string s = "More than one shapes were selected. Shape indices:";
for (int i = 0; i < shapes.Length; i++)
s += shapes[i] + Environment.NewLine;
MessageBox.Show(s);
}
else
{
sf.SelectNone();
sf.set_ShapeSelected(shapes[0], true); // selecting the shape we are about to edit
axMap1.Redraw(); Application.DoEvents();
Form form = new Form();
for (int i = 0; i < sf.NumFields; i++)
{
System.Windows.Forms.Label label = new System.Windows.Forms.Label();
label.Left = 15;
label.Top = i * 30 + 5;
label.Text = sf.Field[i].Name;
label.Width = 60;
form.Controls.Add(label);
TextBox box = new TextBox();
box.Left = 80;
box.Top = label.Top;
box.Width = 80;
box.Text = sf.CellValue[i, shapes[0]].ToString();
box.Name = sf.Field[i].Name;
form.Controls.Add(box);
}
form.Width = 180;
form.Height = sf.NumFields * 30 + 70;
Button btn = new Button
{
Text = "Ok",
Top = sf.NumFields * 30 + 10,
Left = 20,
Width = 70,
Height = 25
};
btn.Click += BtnClick;
form.Controls.Add(btn);
btn = new Button
{
Text = "Cancel",
Top = sf.NumFields * 30 + 10,
Left = 100,
Width = 70,
Height = 25
};
btn.Click += BtnClick;
form.Controls.Add(btn);
form.FormClosed += FormFormClosed;
form.Text = "Shape: " + shapes[0];
form.ShowInTaskbar = false;
form.StartPosition = FormStartPosition.CenterParent;
form.FormBorderStyle = FormBorderStyle.FixedDialog;
form.MaximizeBox = false;
form.MinimizeBox = false;
form.ShowDialog(axMap1.Parent);
}
}
}
// Execute this code if you want to save the results.
// sf.StopEditingShapes(true, true, null);
}
Regards.
Jerry.
This is precisely what I mean. I’ll check things out and get just to tell you thanks, no more bother s on this.
Hi, Jerry good news. I just needed to be sure about the code. Problem was at my initial Zoom level of 5000, tolerance of 100 meters was too small, so i to it to 500 meters, but I had to zoom in very close to be able to select the point and all the other point zoomed off screen. I settled for tolerance of 5000, at which I only need one step zoom in, and also have some of the other points also in view.
Thanks, Jerry, I can live with that.
However, there is one small, tiny nag.
I added a vertical scroll button to the form displaying Fields and Values because the fields extended beyond the displayed form. I also added a third button to the default “OK” and “Cancel”. I added “Images”.
When I click on “Images”, I would like to open a corresponding image already saved in SQL Database in a new windows form = form2.
Code should execute the following:
If Field = Name+Textbox.Text (Name of selected point)
is null,
else
Error msg: “Name does not exit”
else,
Open DB Connection: "Connection string= Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=F:…) "
Select Image from ImagesTable (database table name) where Name = FIeld+Value = Name.Textbox.Text
using (Form2 frm = new Form2(dt))
{
frm.ShowDialog();
}
con.Close();
It’s how to reference the Field Name+Texbox+Text so I can search for the name in the Images DB to display its picture on another form.
That’s all for now, Jerry. You’ve been an immense support.
Thank you!
screenshot_177|386x500
Hi, Jerry, I haven’t received a response from you about retrieving Picture of the selected Shape from SQL Database, almost one week ago. I know about the loads of irons in your fire, but I assure you this won’t take a moment of your precious time - may be just a second or two.
And, by the way, thank you very much for the Point Shapefile Selection issue which you helped to resolve.
Looking forward to a guide in the right direction, and then no more buggers for now.
Regards!