Hi,
Is there any option to programatically update, that is add or delete columns from a shapefile? If so, please let me know how it can be done.
I have a shapefile with a few columns for adding attributes, but need to give the user the option to add more fields through a custom application.
Thanks in advance,
Jacob
Option to update attribute coulmns of a Shapefile?
Hi Jacob,
You should want to implement that like this:
ShapeFileFeatureLayer layer = new ShapeFileFeatureLayer("You File Path");
layer.FeatureSource.BeginTransaction();
layer.FeatureSource.DeleteColumn("Index");
layer.FeatureSource.AddColumn(new FeatureSourceColumn("Priority", "Int", 1));
layer.FeatureSource.UpdateColumn("Name", new FeatureSourceColumn("Description", "String", 500));
layer.FeatureSource.CommitTransaction();
Regards,
Don
Thank you Don for the reply.
One more related query…
I am trying to insert new points to shapefile using layer.FeatureSource.AddFeature(NewPoint);
It works fine for a new shapefile with no geometry present. But, when I try with an existing shapefile where there are already some records, it shows me this error:
An unhandled exception of type ‘System.ArgumentException’ occurred in WpfDesktopEdition.dll
Additional information: ids
How do I go about this?
Thanks and regards,
Jacob
Hi Jacob,
If you want to insert new data to exsiting shapefile, you should want to use the code like how you DeleteColumn, we still need BeginTransaction and CommitTransaction.
Please try that and let me know whether that works for you.
Regards,
Don
Hi Don,
I am using Begin and Commit transaction… Following is the snippet I’m using
private void wpfMap1_MapDoubleClick(object sender, MapClickWpfMapEventArgs e)
{
try
{
LayerOverlay layerOverlay = new LayerOverlay();
ShapeFileFeatureLayer layer = new ShapeFileFeatureLayer(strExistingShapeFile);
string strdateTimeNow = DateTime.Now.ToString();
string shapefileLayer = “ShapeLayer” + strdateTimeNow;
string shapefileOverlay = “ShapeOverlay” + strdateTimeNow;
layerOverlay.Layers.Add(shapefileLayer, layer);
wpfMap1.Overlays.Add(shapefileOverlay, layerOverlay);
if (wpfMap1.TrackOverlay.TrackMode == TrackMode.Point)
{
layer.ReadWriteMode = ThinkGeo.MapSuite.Core.ShapeFileReadWriteMode.ReadWrite;
layer.Open();
layer.FeatureSource.BeginTransaction();
foreach (var item in PointsArrayList)
{
string strCoordinates = item.ToString();
string strXcoord = strCoordinates.Split(’,’)[0];
string strYcoord = strCoordinates.Split(’,’)[1];
double dbX = double.Parse(strXcoord, CultureInfo.InvariantCulture);
double dbY = double.Parse(strYcoord, CultureInfo.InvariantCulture);
Feature NewPoint = new Feature(new PointShape(dbX, dbY));
layer.FeatureSource.AddFeature(NewPoint);
}
PointsArrayList.Clear();
layer.FeatureSource.CommitTransaction();
layer.Close();
wpfMap1.Refresh();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
-------------------------------------------------------------------
1)
When I debug, it passes through the event without any error, but immediately after that it shows an error:
An unhandled exception of type ‘System.ArgumentException’ occurred in WpfDesktopEdition.dll
Additional information: ids
------------------------------------------------------------------
2) more details:
System.ArgumentException was unhandled
_HResult=-2147024809
_message=ids
HResult=-2147024809
IsTransient=false
Message=ids
Parameter name: Parameter Ids should be from 1 to the record number in ShapeFileFeatureSource
Source=WpfDesktopEdition
ParamName=Parameter Ids should be from 1 to the record number in ShapeFileFeatureSource
StackTrace:
at ThinkGeo.MapSuite.WpfDesktopEdition.Tile.<>c__DisplayClass6.<DrawException>b__4()
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunDispatcher(Object ignore)
at System.Windows.Application.RunInternal(Window window)
at System.Windows.Application.Run(Window window)
at System.Windows.Application.Run()
at HelloWorld.App.Main() in d:\Projects\HelloWorld\HelloWorld\obj\x86\Debug\App.g.cs:line 0
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
------------------------------------------------------------------------------------------------
3)
Then it shows a page in VS2013 - No Symbols Loaded. WpfDesktopEdition.pbd not loaded.
Symbol load information:
D:\Projects\HelloWorld\HelloWorld\bin\Debug\WpfDesktopEdition.pdb: Cannot find or open the PDB file.
D:\Projects\HelloWorld\HelloWorld\bin\Debug\WpfDesktopEdition.pdb: Cannot find or open the PDB file.
C:\ThinkGeo\MapSuite3.0\Development\WpfDesktopEdition\WpfDesktopEdition\obj\Evaluation\WpfDesktopEdition.pdb: Cannot find or open the PDB file.
C:\Windows\WpfDesktopEdition.pdb: Cannot find or open the PDB file.
C:\Windows\symbols\dll\WpfDesktopEdition.pdb: Cannot find or open the PDB file.
C:\Windows\dll\WpfDesktopEdition.pdb: Cannot find or open the PDB file.
C:\Users\jacob\AppData\Local\Temp\SymbolCache\WpfDesktopEdition.pdb\204ed45b5ae54fec81aec43410a8a5b54\WpfDesktopEdition.pdb: Cannot find or open the PDB file.
C:\Users\jacob\AppData\Local\Temp\SymbolCache\MicrosoftPublicSymbols\WpfDesktopEdition.pdb\204ed45b5ae54fec81aec43410a8a5b54\WpfDesktopEdition.pdb: Cannot find or open the PDB file.
msdl.microsoft.com/download/symbols: Skipped checking location. The symbol file was not found in this location before.
---------------------------------------------------
Hi Jacob,
Does that exception thrown by wpfMap1.Refresh()?
From your exception, it looks that caused by your index file haven’t been update.
So you should want to call ShapeFileFeatureLayer.BuildIndexFile(“Your Path”, BuildIndexMode.Rebuild); after you modify your shapefile.
Regards,
Don
Hi Don,
The error is not thrown on wpfMap1.Refresh() … wpfMap1.Refresh() is inside a try catch block and no exception is caught.
It is just after the mose dbl click event that the error comes up.
I did try
ShapeFileFeatureLayer.BuildIndexFile(strFile, BuildIndexMode.Rebuild);
after the layer.Close();
It showed me an error that
{“The process cannot access the file ‘D:\Projects\SampleData\ShapeFiles\Created\New30_10_2014 11_50_08 AM.idx’ because it is being used by another process.”}
I had tried
ShapeFileFeatureLayer.Rebuild(strFile);
after the layer.Close(); … here there was no error that file is being used, but finally after the event I get the same exception.
An unhandled exception of type ‘System.ArgumentException’ occurred in WpfDesktopEdition.dll
Additional information: ids
Thanks,
Jacob
Hi Don,
Just an update… Although this ids error is shown and the application crashes, the feature is actually being getting written to the shapefile. I can see that the newly added features are being shown in the file when I load it again to the map.
As I already mentioned, this error happens only on adding new features to a shapefile which already has some features present. It could be because of some issue with the unique id when it is writing to the file… But when I check the created file in ArcGIS Explorer, it also shows all the features (including new ones) with a proper FID.
Thanks,
Jacob
Hi Jacob,
Please show me more code about how you add this layer and then edit it.
When I test the code you provided, the shapefile is modified succeed and haven’t throw any exception.
So I think that should because you use this layer in some other code out of the click event and haven’t release it before you edit it.
BTW, could you make sure you are using WPF Desktop Edition or Desktop Edition for the issue? Because you put the question in DesktopEdition sub fourm but your code looks like call WPF Desktop Edition.
Regards,
Don
Hi Don,
I am using WPF Desktop Edition… sorry for posting this in the wrong forum.
I use the following function to load a shapefile
//----Function for loading shapefile
public void LoadShapeFile(string strFilename)
{
try
{
wpfMap1.MapUnit = GeographyUnit.DecimalDegree;
ShapeFileFeatureLayer ShapeFileLayer1 = new ShapeFileFeatureLayer(strFilename);
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.Country1;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.DefaultLineStyle = LineStyles.SecondaryRoad1;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.City1;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
if (!File.Exists(ShapeFileLayer1.IndexPathFileName))
{
ShapeFileFeatureLayer.BuildIndexFile(strFilename, BuildIndexMode.DoNotRebuild);
//ShapeFileFeatureLayer.BuildIndexFile(strFilename, BuildIndexMode.Rebuild); // Tried either of these… same error
}
LayerOverlay layerOverlay = new LayerOverlay();
string strdateTimeNow = DateTime.Now.ToString().Replace(’/’, ‘_’).Replace(’:’, ‘_’);
layerOverlay.Layers.Add(“ShapeLayer” + strdateTimeNow, ShapeFileLayer1);
wpfMap1.Overlays.Add(“ShapeOverlay” + strdateTimeNow, layerOverlay);
wpfMap1.Overlays[1].Name = “ShapeOverlay” + strdateTimeNow;
strOverlay = “ShapeOverlay” + strdateTimeNow;
ShapeFileLayer1.Open();
if (ShapeFileLayer1.FeatureSource.GetCount() > 0)
{
wpfMap1.CurrentExtent = ShapeFileLayer1.GetBoundingBox();
}
ShapeFileLayer1.Close();
wpfMap1.Refresh();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
//------------------------------------------------------------------
I already sent you the code where I try to edit it…
This is how I tested it
1. I took a shapefile which did not have any records
2. loaded it using the above function.
3. Then I edited it using the double click event… The points were added successfully and was loaded in the mapwindow.
4. I closed the application… and started it again fresh
5. Loaded the updated shapefile using the above function.
6. Then I edited it using the double click event… Ids Error was shown
In the above test I dont think I used any other function… Only difference was that the shapefile did not have any records initially.
How do i make sure that the .idx file is not used by any other process? Where in these two functions should I do use ShapeFileFeatureLayer.BuildIndexFile(“Your Path”, BuildIndexMode.Rebuild); as mentioed in your earlier post?
Hi Jacob,
Thanks for your code, I found the problem of your code.
You load the shapefile when you initiliaze it, but in your DoubleClick function, you open shapefile by another layer, that cause the conflict.
Please get the layer you added in LoadShapeFile function and directly edit it, which will works well and you it looks you don’t need rebuild index file.
As below is my test code, for simple I just create a ShapeFileLayer1 so I can directly use that in doubleclick function, you can also get that by key.
ShapeFileFeatureLayer ShapeFileLayer1;
private void WpfMap_Loaded(object sender, RoutedEventArgs e)
{
LoadShapeFile(@“D:\abctest.shp”);
}
public void LoadShapeFile(string strFilename)
{
try
{
Map1.MapUnit = GeographyUnit.DecimalDegree;
ShapeFileLayer1 = new ShapeFileFeatureLayer(strFilename, ShapeFileReadWriteMode.ReadWrite);
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.Country1;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.DefaultLineStyle = LineStyles.SecondaryRoad1;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.City1;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
if (!File.Exists(ShapeFileLayer1.IndexPathFileName))
{
ShapeFileFeatureLayer.BuildIndexFile(strFilename, BuildIndexMode.DoNotRebuild);
}
LayerOverlay layerOverlay = new LayerOverlay();
string strdateTimeNow = DateTime.Now.ToString().Replace(’/’, ‘_’).Replace(’:’, ‘_’);
layerOverlay.Layers.Add(“ShapeLayer” + strdateTimeNow, ShapeFileLayer1);
Map1.Overlays.Add(“ShapeOverlay” + strdateTimeNow, layerOverlay);
ShapeFileLayer1.Open();
if (ShapeFileLayer1.FeatureSource.GetCount() > 0)
{
Map1.CurrentExtent = ShapeFileLayer1.GetBoundingBox();
}
ShapeFileLayer1.Close();
Map1.Refresh();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void Map1_MapDoubleClick(object sender, MapClickWpfMapEventArgs e)
{
try
{
LayerOverlay layerOverlay = new LayerOverlay();
string strdateTimeNow = DateTime.Now.ToString();
string shapefileLayer = “ShapeLayer” + strdateTimeNow;
string shapefileOverlay = “ShapeOverlay” + strdateTimeNow;
ShapeFileLayer1.Open();
ShapeFileLayer1.FeatureSource.BeginTransaction();
Feature NewPoint = new Feature(e.WorldLocation);
ShapeFileLayer1.FeatureSource.AddFeature(NewPoint);
ShapeFileLayer1.FeatureSource.CommitTransaction();
ShapeFileLayer1.Close();
Map1.Refresh();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
Regards,
Don
Thanks a lot, Don, for the support. Its working fine.
Jacob,
If other questions, don’t hesitate to let us know.
Thanks,
Troy
Hi,
I am loading a shapefile in the LoadShapeFile function and assigning the key as follows
//***************************************************************
LayerOverlay layerOverlay = new LayerOverlay();
layerOverlay.Layers.Add(“ShapeLayer” , ShapeFileLayer1);
wpfMap1.Overlays.Add(layerOverlay);
wpfMap1.Overlays[wpfMap1.Overlays.Count -1].Name = “ShapeOverlay”;
//***************************************************************
Later when I click an item in the treeview (which has a list of loaded shapefiles), I need to find the shapefile selected… For that i am doing
//***************************************************************
ShapeFileLayer1 = (ShapeFileFeatureLayer)wpfMap1.FindFeatureLayer(“ShapeOverlay”);
//***************************************************************
But ShapeFileLayer1 value shows null . Am I missing something?
I am attaching more code below for a better understanding…
//-------------------------------------------------------------------------------------
ShapeFileFeatureLayer ShapeFileLayer1;
private void WpfMap_Loaded(object sender, RoutedEventArgs e)
{
LoadShapeFile(@“D:\abctest.shp”);
}
public void LoadShapeFile(string strFilename)
{
try
{
Map1.MapUnit = GeographyUnit.DecimalDegree;
ShapeFileLayer1 = new ShapeFileFeatureLayer(strFilename, ShapeFileReadWriteMode.ReadWrite);
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.Country1;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.DefaultLineStyle = LineStyles.SecondaryRoad1;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.City1;
ShapeFileLayer1.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
if (!File.Exists(ShapeFileLayer1.IndexPathFileName))
{
ShapeFileFeatureLayer.BuildIndexFile(strFilename, BuildIndexMode.DoNotRebuild);
}
LayerOverlay layerOverlay = new LayerOverlay();
string strdateTimeNow = DateTime.Now.ToString().Replace(’/’, ‘_’).Replace(’:’, ‘_’);
layerOverlay.Layers.Add(“ShapeLayer”, ShapeFileLayer1); //Hardcoded
Map1.Overlays.Add(“ShapeOverlay”, layerOverlay); //Hardcoded
ShapeFileLayer1.Open();
if (ShapeFileLayer1.FeatureSource.GetCount() > 0)
{
Map1.CurrentExtent = ShapeFileLayer1.GetBoundingBox();
}
ShapeFileLayer1.Close();
Map1.Refresh();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void TreeViewItem_OnClick(object sender, RoutedEventArgs e)
{
try
{
ShapeFileLayer1 = (ShapeFileFeatureLayer)Map1.FindFeatureLayer(“ShapeOverlay”); //Gets only null
FeatureLayer testLayer = Map1.FindFeatureLayer(“ShapeOverlay”); //Testing… result is null
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
//-----------------------------------------------------------------------------------------------
Hi,
I think I figured it out… I should have used "ShapeLayer" instead of "ShapeOverlay" in TreeViewClick…
…
ShapeFileLayer1 = (ShapeFileFeatureLayer)Map1.FindFeatureLayer("ShapeLayer");
instead of
ShapeFileLayer1 = (ShapeFileFeatureLayer)Map1.FindFeatureLayer("ShapeOverlay"); //Gets only null
…
Thanks.
Hi Jacob,
Great! Any other questions, please feel free to let us know.
Thanks
Troy