I am transferring a code from a VBA module to a C# arcmap add-in. I am using ArcMap 10.2 and Visual Studio 2010.
I cannot figure out how to translate what appears to be a method from a different class (module) within an ElseIf Not statement that places 2 variables from the current class within the method. The biggest problem for me in translating the code is that I can't really figure out with 100% certainty what the original code is saying with that ElseIf Not statement.
Any assistance will be appreciated.
This is the code snippet that I am referring to (ValidFacet is the method from a different module):
ElseIf Not ValidFacet(txtFacetNumber.Text & cboFacetLetter.Text) Then MsgBox "The facet you entered does not exist." & vbCrLf & _ "Please check and try again.", vbSystemModal
Here it is again within the original VBA code.
Private Sub cmdCreateFacet_Click() Dim strFacetNumber As String If txtFacetNumber.Text = "" Then MsgBox "You must inter a value for the facet.", vbCritical + vbSystemModal txtFacetNumber.SetFocus Exit Sub ElseIf cboFacetLetter.Text = "" And Not optFullFacet.Value Then MsgBox "You must inter a value for the facet letter.", vbCritical + vbSystemModal cboFacetLetter.SetFocus Exit Sub ElseIf Not ValidFacet(txtFacetNumber.Text & cboFacetLetter.Text) Then MsgBox "The facet you entered does not exist." & vbCrLf & _ "Please check and try again.", vbSystemModal cboFacetLetter.Text = "" With txtFacetNumber .Text = "" .SetFocus End With Exit Sub End If strFacetNumber = txtFacetNumber.Text & cboFacetLetter.Text DrawMap strFacetNumber 'MsgBox "Drawing" cmdExit_Click End Sub
Here is my C# translation so far. I have created a different class (FacetClass) for the ValidFacet method. I reference the FacetClass namespace (SingleFacet1) within the 'using' section although both SingleFacetForm1 and FacetClass are from the same namespace.
public partial class SingleFacetForm1 : Form
{
private void searchBtn_Click(object sender, EventArgs e)
{
string facetNumberstr;
if (facetNumbertxt.Text == "")
{
MessageBox.Show(new Form {TopMost = true }, "You must enter a value for the facet.");
facetNumbertxt.Focus();
}
else if (qFacetCmb.Text == "" && !(wFacetrb.Checked))
{
MessageBox.Show(new Form {TopMost = true }, "You must enter a value for the facet letter.");
qFacetCmb.Focus();
}
else (! FacetClass.ValidFacet(facetNumbertxt.Text && qFacetCmb.Text))
{
MessageBox.Show(new Form {TopMost = true }, "The facet you entered does not exist." + newLine + " " + "Please check and try again.");
qFacetCmb.Text = "";
facetNumbertxt.Text = "";
facetNumbertxt.Focus();
}
facetNumberstr = facetNumbertxt.Text + qFacetCmb.Text;
facetNumberstr.DrawMap facetNumberstr;
//facetNumberstr = new Draw(Map);
//Draw(Map) (facetNumberstr);
MessageBox.Show("Drawing");
//cancelBtn_Click();
cancelBtn_Click
}
And just in case it helps, here is my C# code for ValidFacet:
public static void ValidFacet()
{
string newLine = System.Environment.NewLine;
IMxDocument pMxDoc = ArcMap.Document;
IMap pMap = pMxDoc.FocusMap;
IFeatureLayer pFLayer;
bool ValidFacet = true;
string facetStr = "";
int y;
pFLayer = (IFeatureLayer)pMap.get_Layer(0);
for (y = 0; y <= pMap.LayerCount - 1; y++)
{
if (pMap.get_Layer(y).Name == "Facet")
{
pFLayer = pMap.get_Layer(y) as IFeatureLayer;
}
else if (pFLayer as IFeatureLayer == null)
{
MessageBox.Show("Failed to find the Facet Layer." + newLine + "Please check and try again");
ValidFacet = false;
}
}
//IFeatureLayer pFLayer;
IGeoFeatureLayer pSearchLayer;
IFeatureClass pSearchFC;
IFeatureCursor pFCursor;
IQueryFilter pQueryFilter;
//pFLayer = pSearchLayer;
pSearchLayer = (IGeoFeatureLayer)pFLayer;
pSearchFC = pSearchLayer.DisplayFeatureClass;
//Set queryfilter and search for pages to update
pQueryFilter = new QueryFilter();
String strSelField = "qfname";
pQueryFilter.WhereClause = strSelField + " like '" + facetStr + "%'";
pFCursor = pSearchFC.Search(pQueryFilter, false);
if (pSearchFC.FeatureCount(pQueryFilter) < 1)
{
ValidFacet = false;
}
}
Solved! Go to Solution.
I took a stab at taking your code and trying to mimic what I thought the Facet search code was looking to do, I've converted a LOT of VB code to C# over the years so hopefully this helps get pointed in the right direction. I tried to pepper in some comments to show what I think the original code was doing. Hope this helps!
// Check if textbox was filled if (string.IsNullOrEmpty(facetNumbertxt.Text)) { MessageBox.Show(new Form {TopMost = true}, "You must enter a value for the facet."); facetNumbertxt.Focus(); } // Check if a combobox item was selected but the 'wFacetrb' checkbox was not checked else if (string.IsNullOrEmpty(qFacetCmb.Text) && !(wFacetrb.Checked)) { MessageBox.Show(new Form {TopMost = true}, "You must enter a value for the facet letter."); qFacetCmb.Focus(); } // We have fulfilled the textbox being filled, and combobox item chosen // perform search for Facet using the combination of textbox and combobox text as a single string // If not found, display messagebox. else if(!FacetClass.ValidFacet(facetNumbertxt.Text + qFacetCmb.Text)) { MessageBox.Show(new Form {TopMost = true}, "The facet you entered does not exist." + Environment.NewLine + "Please check and try again."); qFacetCmb.Text = ""; facetNumbertxt.Text = ""; facetNumbertxt.Focus(); }
And my take on the ValidFacet method:
/// <summary>
/// Searches the Facet feature class to find a feature matching 'facetstr'.
/// Returns true if at least 1 feature is found, otherwise false.
/// </summary>
public static bool ValidFacet(string facetStr)
{
IMxDocument pMxDoc = ArcMap.Document;
IMap pMap = pMxDoc.FocusMap;
bool validFacet = true;
IFeatureLayer pFLayer = null;
// Loop through all layers until we find facet feature layer
for (int y = 0; y <= pMap.LayerCount - 1; y++)
{
if (pMap.get_Layer(y).Name == "Facet")
{
pFLayer = pMap.get_Layer(y) as IFeatureLayer;
break; // stop looking, we found it
}
}
if (pFLayer == null)
{
MessageBox.Show("Failed to find the Facet Layer." + Environment.NewLine + "Please check and try again");
validFacet = false;
}
else
{
IGeoFeatureLayer pSearchLayer = pFLayer as IGeoFeatureLayer;
if (pSearchLayer != null)
{
IFeatureClass pSearchFC = pSearchLayer.DisplayFeatureClass;
//Set queryfilter and search for pages to update
IQueryFilter pQueryFilter = new QueryFilter();
const string strSelField = "qfname";
pQueryFilter.WhereClause = strSelField + " like '" + facetStr + "%'";
if (pSearchFC.FeatureCount(pQueryFilter) < 1)
{
// We didn't find anything
validFacet = false;
}
}
}
return validFacet;
}
I have encountered another instance where the same situation arises; ValidFacet is used in a different class and with a string parameter. I still cannot figure out exactly what the original vba code is trying to say or how to convert the vba to C#.
If Not ValidFacet(pTopFac) Then pTopFac = "END OF DATA" End If
So far I have this (which doesn't work):
if (FacetClass.ValidFacet() != pTopFac) { pTopFac = "END OF DATA"; }
Since the statement seems to be checking to see if the variable's value exists in the ValidFacet, I have also tried
if (!FacetClass.ValidFacet.Contains(pTopFac))
The statement does not work but perhaps it is closer to what is needed?
Confusing....
Since VBA was used and VBA converts/casts anything to a variant data type that does not have a strict DIM statement could be your problem?
ValidFacet() ==> True, False, "Variant String"
If this is the case you may have to accommodate this additional situation..... VBA will try an convert any failed datatype to variant. Some other programmer, being on the lazy side or employing a quick fix used this leniency of VBA to create additional functionality without having to rip apart code to create additional logic.
Just a thought that may trigger some additional ideas for you?
Ted,
Thank you for your help. I was not aware of VBA's automatic conversion to variant. It is something I am now trying to make sure I consider as the problem when encountering other errors.
I cannot tell you how many times that variant has bit me....
Sneaky example: Dim i,j,k,l as integer
You would expect i,j,k,l to be integers but no ... i is an integer, j,k,l will be variants. (This one is a killer!)
I am glad you mentioned that example. I never would have thought that to be the case.
I took a stab at taking your code and trying to mimic what I thought the Facet search code was looking to do, I've converted a LOT of VB code to C# over the years so hopefully this helps get pointed in the right direction. I tried to pepper in some comments to show what I think the original code was doing. Hope this helps!
// Check if textbox was filled if (string.IsNullOrEmpty(facetNumbertxt.Text)) { MessageBox.Show(new Form {TopMost = true}, "You must enter a value for the facet."); facetNumbertxt.Focus(); } // Check if a combobox item was selected but the 'wFacetrb' checkbox was not checked else if (string.IsNullOrEmpty(qFacetCmb.Text) && !(wFacetrb.Checked)) { MessageBox.Show(new Form {TopMost = true}, "You must enter a value for the facet letter."); qFacetCmb.Focus(); } // We have fulfilled the textbox being filled, and combobox item chosen // perform search for Facet using the combination of textbox and combobox text as a single string // If not found, display messagebox. else if(!FacetClass.ValidFacet(facetNumbertxt.Text + qFacetCmb.Text)) { MessageBox.Show(new Form {TopMost = true}, "The facet you entered does not exist." + Environment.NewLine + "Please check and try again."); qFacetCmb.Text = ""; facetNumbertxt.Text = ""; facetNumbertxt.Focus(); }
And my take on the ValidFacet method:
/// <summary>
/// Searches the Facet feature class to find a feature matching 'facetstr'.
/// Returns true if at least 1 feature is found, otherwise false.
/// </summary>
public static bool ValidFacet(string facetStr)
{
IMxDocument pMxDoc = ArcMap.Document;
IMap pMap = pMxDoc.FocusMap;
bool validFacet = true;
IFeatureLayer pFLayer = null;
// Loop through all layers until we find facet feature layer
for (int y = 0; y <= pMap.LayerCount - 1; y++)
{
if (pMap.get_Layer(y).Name == "Facet")
{
pFLayer = pMap.get_Layer(y) as IFeatureLayer;
break; // stop looking, we found it
}
}
if (pFLayer == null)
{
MessageBox.Show("Failed to find the Facet Layer." + Environment.NewLine + "Please check and try again");
validFacet = false;
}
else
{
IGeoFeatureLayer pSearchLayer = pFLayer as IGeoFeatureLayer;
if (pSearchLayer != null)
{
IFeatureClass pSearchFC = pSearchLayer.DisplayFeatureClass;
//Set queryfilter and search for pages to update
IQueryFilter pQueryFilter = new QueryFilter();
const string strSelField = "qfname";
pQueryFilter.WhereClause = strSelField + " like '" + facetStr + "%'";
if (pSearchFC.FeatureCount(pQueryFilter) < 1)
{
// We didn't find anything
validFacet = false;
}
}
}
return validFacet;
}
Daniel,
Thanks for your help, the code appears to work! I have other code I am working on that are tied-in to that code so I can't currently test it but all the errors are gone and other areas that were also using a ValidFacet reference are no longer showing errors.
I am interested in the logic and reasoning behind the changes you made. If you don't mind, I know (and appreciate) that you have already spend quite a bit of time translating the code, I have a few questions about some of your modifications.
First, what made you decide to change from 'void' to 'bool'? I have other class programs that use boolean in the code but I have as 'void' in the return type.
Second, I noticed you are not using the IFeatureCursor. Why is it no longer needed; ie. what code modifications made IFeatureCursor obsolete?
Lastly, why were you able to define pFlayer as null instead of using pFLayer = (IFeatureLayer)pMap.get_Layer(0); . Is it because you upgraded the else if to an if and included in the logic statement else for pSearchLayer = pFlayer and set it to for a non-blank pSearchLayer?
1. Regarding using bool instead of void, I see that you are trying to use it in an if statement, so the return type will have to be bool in C# to be contained within the if block. In VBA, I'd presume it looked something like
Public Function ValidFacet(ByVal sFacetNumber As String, ByVal sFacetLetter as String) As Boolean
which should imply the same thing, the function itself returns a Boolean value.
2. When looking at what the ValidFacet code was doing, it looked like it was only checking the count, which is accomplished with just the call
pSearchFC.FeatureCount(pQueryFilter)
If you wanted to use the actual features associated with that search, you'd use the results from the feature cursor itself, but since we were just checking count, we can omit the feature cursor call, and just get the count.
3. My thought process around the changes here were to try to optimize the bit of code to exit out as soon as it finds the layer. I initalize the layer to null, so that if we go through all of the layers and don't find it, we can check the layer for null and exit. Another option would look like this
for (int y = 0; y <= pMap.LayerCount - 1; y++) { pFLayer = pMap.get_Layer(y) as IFeatureLayer; if (pFLayer != null && pFLayer.Name == "Facet") { break; // stop looking, we found it } }
In either case, I am using whether or not pFLayer is null to decide whether to continue looking for the feature.
I'm hoping that helps give some background as to why I made the choices I did, always happy to share any knowledge I may have.