Raster Data Loading from FilePath in Dotspatial - c#

I have this simple line of code in DotSpatial
var raster = Raster.OpenFile("X://Data//4mr_project.tif");
Why raster just getting null value??
I also have .aux, .ovr, .tfw files in the same directory.
EDITED:
I found that the line below works fine:
var featureSet = FeatureSet.Open("X:\\Test Data\\shap\\edited.shp")
because Dotspatial have capability to load .shp file by default. But loading raster data .tif format, Dotspatial need GDAL extensions. Now the question is how to load GDAL extensions manually in Dotspatial using C#.

GDAL extensions can be supported in your own application through the use of the AppManager component. You can drag and drop this onto your form. This allows for support from the GDAL data extensions, and will also gives support to other plug-ins. Here is a basic walk through for adding the AppManager to a new project that just has a Map on the form.
1) From the Visual Studio Toolbox, right click and click on "Choose Items"
2) From the dialog, choose "Browse" and browse to the DotSpatial.Controls.dll library.
3) Click Ok as needed to close the dialogs and get back to the Toolbox.
4) Find the AppManager component you just added in the Toolbox.
5) Drag the AppManager component onto your form. (not on the map, but on the form). A new instance should appear below your form in the non-visual components list.
6) Select this component to view it's properties in the Properties Dialog.
7) Set the map for the appManager (or other components if you are using them).
8) The GDAL component does not even require the Map to be defined in order to work, it should just work. But you will need the GDAL extension. You can find the DotSpatial.Data.Rasters.GdalExtension in the "Windows Extensions" folder. Ensure that you have a similar folder in your output directory with the necessary GdalExtension. One method is just to ensure that this is in your final distribution folder manually.
9) (Optional) One trick you can use, to ensure you have the GDAL plugin in your release folders is to add the libraries as content. This way, regardless if you are working on a debug version or a release version, it will ensure that the GDAL data extension makes it to the output folders.
10) Ensure that the directory you are using (like "Windows Extensions") is listed in the Directories property of the AppManager. The image below shows the default folders which are "Application Extensions" and "Plugins". I think it originally was "Application Extensions" but got updated to "Windows Extensions" later. Unfortunately, I don't think they updated the default folder.
11) In the code somewhere (probably in the form constructor) you need to call appManager1.LoadExtensions(); If you don't call this, it will not actually load the GDAL extension even if you have the GDAL library as part of your project.
12) Add a SpatialDockManager, SpatialHeaderManager, SpatialStatusStrip to the project. Then assign these to the properties on the AppManager, the same way you did the map. For reasons that are beyond me and were implemented after I left, the previously open ended design structure has changed, and now it will throw message box errors if the program does not include these things but you try to use Extensions. The "ProgressHandler" property takes the SpatialStatusStrip.
After following all 12 of these steps (and running the project in x86 mode) the raster code you posted in the initial question works, and you can open geotifs. I also pushed the GDAL extension into the root "Application Extensions" directory while trying to get it to work, but I don't think you have to do that. It should work if it is in a subfolder.

Sorry to be that late (hopefully, it's never too late), but if you wish to use the plugin without using AppManager, because you may be composing something custom and do not want to depend on the main DotSpatial application framework (note that the AppManager utilizes some slightly advanced "magic" to make it all work together), you can do yourself the following few simple tasks:
1) Add a reference to the file
(DotSpatial Release Folder)\Windows
Extensions\DotSpatial.Data.Rasters.GdalExtension.dll
to your project (this is the main GdalExtension Plugin output file).
NOTE: To make sure this step is done correctly, make sure that building your library (the one that references the GdalExtension.dll) ends up copying to this project's output directory the additional files from the same folder (i.e. gdal_csharp.dll etc.).
2) This same folder also contains a gdal subfolder. Copy the folder itself, as-is, to your output path (usually ...\bin\Release\\ or ...\bin\Debug\\, depending on your configuration). Of course in your final project, you would probably like to use a post-build copy event to automate the process, or just include the folder as content in your application build output, as Ted also mentions in step 9 of his answer.
NOTE: By output folder, I am referring to the Application Output Path, not the library output path. If your application is using a library, which undertakes the task of loading rasters (through GdalExtension), the gdal folder does not need to be in the output folder of this library. It needs to end up in your final application's output folder. The reason is that the various dll files are loaded dynamically, so they have to be found in the executing application folder.
3) As early as possible in your codebase, create a new GdalRasterProvider, which should now be referenced by the dll file added in step 1. This means, add something like the following line to your project
var grp = new DotSpatial.Data.Rasters.GdalExtension.GdalRasterProvider();
Thereafter, the first line of code in your post should work as expected. So, technically, the answer to the original question is that the DefaultDataManager class did not find any suitable provider to perform the task of actually loading the Raster file. Therefore, you are left with a null variable.
Interestingly, you don't need to hold the reference anywhere (i.e. do anything with variable grp). If you check the source code, the constructor itself undertakes the task of adding itself to the DefaultDataProvider.PreferredProviders dictionary, which is eventually invoked behind the scenes in the call to Raster.Open(string) method. The only "tough-to-figure-out" part is simply to copy the gdal folder in your application output path, because the GDAL extension loads a number of references located therein upon instantiation of any provider, and the loading is based on a "gdal" subfolder located in whichever folder your application resides and is executed from.
(Note that the Plugin also contains two more providers (GdalImageProvider and OgrDataProvider). To make these two work, you need to instantiate them but also to manually add them to the PreferredProviders dictionary of the DefaultDataProvider, typically also up early in your application code)

Related

Deploy .json file with UserControl WinForms

I have built a custom User Control in Visual Studio (Win Forms).
This User Control requires a .json file to be deployed along with it.
Short Version: How is this possible?
Long Version:
When I am testing the User Control from with the Control designer itself, it works no problem.
This would be because I have set the following:
Build Action to Content and;
Copy To Output Directory - Copy if Newer
So when I'm debugging it, everything is there, as I expect it to be.
The problem occurs when I create a separate Win Forms application, and add this newly designed control to the Palette by:
Right click Toolbox->Choose Items->Browse->Browse to the Project Directory of the Control->Select the DLL->OK
It show up on my Palette, but the problem is of course when I drop the User Control onto the form itself. It has no means of getting "MyFile.json" from User Control Application/Dll to the Current Project.
How do I make this work?
Chud
One easy way is to build your json file as a EmbeddedResource instead of Content. That way it will be embedded into the UserControl's binary (the dll file itself). You can then use ResourceManager class to read it in your code.
If you're going to change the content of json file at runtime, you can instead create an application setting of string type that stores the actual json content. This setting can then be read/written easily using ProjectName.Properties.Settings.Default.YourSettingName.
Also note that if you have set your json file's Build Action to Content and Copy to Output Directory to Always Copy, and you add a reference to this project from another project that also exists in that solution, the content file (json file) should get copied to the bin folder correctly. But if your UserControl project does not exist in the current solution, or you're referencing your control through Browse button, you'll not get your content files. This may not seem obvious, but once you think about it, you'll understand that VS cannot figure out what dependencies does a DLL file has if you simply add a file reference.
In the latter case, a setting is the cheapest solution (described above) that you can use.

How can I share resources across multiple projects within a C# solution?

I have multiple projects in a solution and I'd like them all to share one pool of graphics resources. I've tried this:
1 - Created project1, made its resource file public, added some graphics to it.
2 - Created project2, Alt+dragged Resources.resx from project1\Properties to project2 (not in the Properties folder)
3 - Add reference in project2 to project1
So, now all the images from project1 are available in project2. So far, so good. I can use them at design time just fine.
But, when I want to access them at runtime, I try this (in project2)...
Image img = project1.Properties.Resources.image14;
And that crashes with a MissingManifestResourceException.
What am I doing wrong here? Is there a better way I could approach this? All I'm trying to do is maintain all my graphics in one place, so if I add a resource, it becomes available to all projects in the solution.
Just built an example following these steps:
Create a class library do hold the resources (Project 1)
Create the consumer project (Project 2)
Add a resource file (GlobalResources.resx) in the Project 1 and add a resource item Information
Change the BuildAction of the resource file to Embedded Resource
Change the Do not copy of the resource file to False
Check if the Custom Tool of the resource file is set to PublicResXFileCodeGenerator
Add a reference to the class library (Project 1) to the consumer project (Project2).
Add the resource namespace reference wherever you want to use it.
Finally it is working: GlobalResources.Information
It should be simple.
Edit:
You are concerned about using an external resource file inside the design time property editor. Sorry to inform that there is no standard support for this :(
However, if you think that the benefits are greater than the effort:
Issue with shared WinForms resources across projects in Visual Studio
How do I get the Windows Forms Designer to use resources from external assembly?
Hope it helps.
Choose the referenced file in your solution explorer, then properties, then see what the "copy to output" property looks like. I suspect it's not set to "Copy Always" or "Copy if Newer" of which either should be fine.
Once it's being copied, let's also check to see where it's being copied. Is the output path for that particular item the same as where the program ultimately expects? Is it being copied to the bin\Debug of the correct project?
Make sure it's being copied to the path where the MissingManifestResourceException says it's failed to find the resource.
Finally, given additional information in our comments, I would also suggest you verify the following:
culture the resources are targeting. Check spelling and capitalization.
any culture settings of your build xml or publish xml.
culture setting(s?) of your host system that's running this code.

Windows Form Localization

I'm trying to get localization to work in my application. I can follow the typical example online and get it to work in a sample project. (ie. setting the Localizable property and the cultures).
When I try to use it in my application, it always uses the default resource file no matter what language I choose.
EDIT: If I go to the properties of my startup project, select Debug, and set the Start Action to Start Project, it will work. If I run the executable that gets created when building by selecting it in "Start external program", it will not work. Any idea why?
EDIT: When I use the Start External Program, the executable I am pointing to is not pointing to the bin/Debug folder of the project. I have a post build event to copy it elsewhere and am pointing to that. Because of this, maybe it is not able to see the reference files that are in the Debug folder?
When you localize a form, it creates a folder per language in the build's output path that holds a resource file projectname.resources.dll.
I have a post build command that puts our .dlls elsewhere. I needed to change the command to also push out the resource files so that they were in the same directory. Once I did this, I was able to get it to work.

How can I use only a part of my assembly?

I want to split the components of my applications like:
Application A -> Component X <- Application B
without compiling Component X to a dll.
When I include the .cs, Visual Studio copies it to the application directory. I don't want that. I want to include the file and then use a part of it, like C's #define. For example if I have a ZIP library, I don't want to include the whole assembly if I need a decompression. What's the C# way to make this? Can I somehow tell VS to not copy the file and use #defines or maybe some method attributes?
An assembly is a single, complete file. If you want multiple assemblies which are only included as needed, you need to build them using multiple projects (one per assembly) and reference only the ones you want in the downstream projects you want.
Bigger question, however, is ... Why?
Don't create a problem where there isn't any.
Create a new dll, and MOVE .cs files that should be shared there. Build it, and have AppA and AppB reference and use that dll.
BTW, you can add reference from AppA to AppB, or from AppB to AppA, but not at the same time because it will create circular reference.
And if you want to stick to your idea, LINK your code files as Chris suggested, and use:
#if APPA
// code for AppA
#endif
To have pieces of code compile just in one application. Use project level #defines (project properties) to define APPA and APPB in their respective projects.
You can link to source files in Visual Studio, rather than copying them into in your project. Right click on the folder where you want to put the file, click "Add Existing Item", find the file that you want to add in the dialog, and before hitting Open, note the little down arrow next to the Open button. Click that, and click add as link.
Documentation here: http://msdn.microsoft.com/en-us/library/9f4t9t92(v=VS.100).aspx
Add Existing Item...
Browse to the file you want to include.
Instead of selecting "add", press the arrow to the right of the "Add" button and select "Link" in the drop down.
/B
May be you need Multifile Assembly?

How to include non-compiled content alongside a C# program published via Visual Studio

I'm trying to publish an XNA game through the Visual Studio Publish tool. The game uses some compiled and some non-compiled content. Basically, I have a level loaded in via XML serialization and a short video. These two files are essentially streamed in, so they aren't compiled. The publish tool includes the compiled content fine, but any references to relative paths are broken because the CurrentDirectory for installed programs are set in the AppData folder.
I know that XNA can now compile XML without having to write custom content processors, but I don't particularly want to go back to rewrite that. I suppose I can if there's no other option, but that still doesn't remedy the video problem.
Is there any way to set up the publish tool so that I can do what I need to do? A setting or something? Or will I need to use a more fully-featured tool like NSIS?
Right click project, Add Existing Resource, browse and select the file you want to add. Then right click the file and click properties and change "Build Action" to content, and "Copy To Output Directory" to Copy if newer (or copy always if the need be). Then you can access it by using the relative path.
I use this for my XML and I can access my content using the following code:
XmlDocument document = new XmlDocument();
document.Load("Resources/DefaultConfig.xml");
Please note that my DefaultConfig.xml file is inside a "Resoruces" Directory which I created in Visual Studio(this is optional, but it helps me keep my project neat)

Categories