Common_CustomEditorTask_CSharp\CustomEditorTask_CSharp\SearchAttributesPanel.cs
// Copyright 2010 ESRI // // All rights reserved under the copyright laws of the United States // and applicable international laws, treaties, and conventions. // // You may freely redistribute and use this sample code, with or // without modification, provided you include the original copyright // notice and use restrictions. // // See the use restrictions. // namespace CustomEditorTask_CSharp { [AjaxControlToolkit.ClientScriptResource("SearchAttributesPanel.js", "CustomEditorTask_CSharp.javascript.SearchAttributesPanel.js")] class SearchAttributesPanel : ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditorPanel { #region Instance Variable Declarations private System.Web.UI.HtmlControls.HtmlGenericControl m_panelDiv; private System.Collections.Specialized.NameValueCollection m_callbackArgsCollection; #endregion #region Constructor public SearchAttributesPanel(ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditorTask editorTask) : base("Search", editorTask, "searchAttributesPanel") { // Add a handler that fires when a new editor layer is selected this.ParentEditor.LayerChanged += new ESRI.ArcGIS.ADF.ArcGISServer.Editor.Editor.LayerChangedHandler(ParentEditor_LayerChanged); } #endregion #region WebControl Life Cycle Event Overrides protected override void CreateChildControls() { base.CreateChildControls(); // Create a container div for the client-side UI component m_panelDiv = new System.Web.UI.HtmlControls.HtmlGenericControl("div"); m_panelDiv.ID = "searchAttributesPanelDiv"; Controls.Add(m_panelDiv); } protected override void OnPreRender(System.EventArgs e) { base.OnPreRender(e); // Register the JavaScript file containing the SearchAttributesPanel JavaScript UI // component and functions to control interaction between the client panel and the server //System.Web.UI.ScriptManager.RegisterClientScriptResource((System.Web.UI.Control)this, // this.GetType(), "CustomEditorTask_CSharp.javascript.SearchAttributesPanel.js"); //this.Page.ClientScript.RegisterClientScriptResource(this.GetType(), "CustomEditorTask_CSharp.javascript.SearchAttributesPanel.js"); // Get a reference to the editor task's layers drop-down list System.Web.UI.WebControls.DropDownList editorLayerList = null; editorLayerList = CustomUtilities.FindControl( "editTaskLayerList", this.ParentEditor as System.Web.UI.Control) as System.Web.UI.WebControls.DropDownList; // Get strings containing the numeric and text fields for the current layer string numericFields = CustomUtilities.GetFields(CustomEditorInstance, CustomUtilities.FieldType.Numeric); string textFields = CustomUtilities.GetFields(CustomEditorInstance, CustomUtilities.FieldType.Text); // Get the URL of the activity_indicator image file string activityIndicatorUrl = this.Page.ClientScript.GetWebResourceUrl( typeof(CustomEditorTask), "CustomEditorTask_CSharp.images.activity_indicator.gif"); string csname1 = this.ClientID + "_init"; if (!Page.ClientScript.IsStartupScriptRegistered(this.GetType(), csname1)) { // Construct the JavaScript necessary to initialize the client-side search panel with // server-side properties string scriptBlock = @" function invokeSearchPanelInitialization(){{ initializeSearchPanel('{0}', '{1}', '{2}', '{3}', '{4}', ""{5}""); }} Sys.Application.add_init(invokeSearchPanelInitialization);"; scriptBlock = string.Format(scriptBlock, m_panelDiv.ClientID, editorLayerList.ClientID, numericFields, textFields, activityIndicatorUrl, this.CallbackFunctionString); // Register the initialization code as a startup script this.Page.ClientScript.RegisterStartupScript(this.GetType(), this.ClientID + "_init", scriptBlock, true); } // Initialize the OIDFieldName property this.OIDfieldName = CustomEditorInstance.FeatureLayer.FeatureClass.OIDFieldName; } protected override void RenderContents(System.Web.UI.HtmlTextWriter writer) { base.RenderContents(writer); // Create a callback result that will call the renderSearchPanel JavaScript function, which // will expicitly re-render the client-side search panel. This is necessary because the // server has no knowledge of the client-side panel's elements, so when the panel is rendered // (which is done with information stored in state on the server), these elements are lost. ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult renderSearchPanelCallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript("renderSearchPanel();"); this.ParentEditor.CallbackResults.Add(renderSearchPanelCallbackResult); } #endregion #region Web ADF Event Handlers // Fires when the user selects a different layer from the editor task's layers drop-down list void ParentEditor_LayerChanged(ESRI.ArcGIS.Carto.IFeatureLayer featureLayer) { // Get the object ID field of the newly selected layer this.OIDfieldName = featureLayer.FeatureClass.OIDFieldName; // Get the numeric and text fields of the new layer string numericFields = CustomUtilities.GetFields(CustomEditorInstance, CustomUtilities.FieldType.Numeric); string textFields = CustomUtilities.GetFields(CustomEditorInstance, CustomUtilities.FieldType.Text); // Construct a call to a JavaScript function that will update the client-side search // panel with the new layer's fields string jsUpdateFields = string.Format("updateSearchPanelFields('{0}', '{1}');", textFields, numericFields); ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult updateFieldsCallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsUpdateFields); this.ParentEditor.CallbackResults.Add(updateFieldsCallbackResult); } #endregion; #region Callback Handler public override void RaiseCallbackEvent(string eventArgs) { // Parse callback arguments using the CallbackUtility included with Web ADF. m_callbackArgsCollection = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackUtility.ParseStringIntoNameValueCollection(eventArgs); // Check whether the current event argument indicates that a search was initiated by the user if (m_callbackArgsCollection["EventArg"] == "search") { // Get the fields selected by the user, with aliases replaced by database field names string searchFieldsString = CustomUtilities.ReplaceAliases( m_callbackArgsCollection["Fields"], CustomEditorInstance); // Parse the fields string into an array char[] delimiter = { ';' }; string[] searchFieldsArray = searchFieldsString.Split(delimiter, System.StringSplitOptions.RemoveEmptyEntries); // Build a query string based on the selected fields, operator, and search value string queryString = this.BuildQuery(m_callbackArgsCollection["Operator"], searchFieldsArray, m_callbackArgsCollection["Value"]); // Get IDs of features satisfying query int[] matchingFeatureIDs = CustomUtilities.DoQuery(queryString, this.ParentEditor); // Get LayerDescription object for currently selected layer ESRI.ArcGIS.ADF.ArcGISServer.LayerDescription agsLayerDescription = ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditorUtilities.GetLayerDescription( this.ParentEditor.MapFunctionality, this.ParentEditor.SelectedLayerID); // Combine the feature IDs from the query with those currently selected. How this // is done will depend on the selection option currently specified in the editor // task's settings bool selectionChanged; System.Collections.Generic.List<int> selectedIDsList = CustomUtilities.UpdateSelection(agsLayerDescription.SelectionFeatures, matchingFeatureIDs, out selectionChanged, this.ParentEditor.EditorTask); // Check whether the selected IDs changed if (selectionChanged) { // Set selected features on layer currently being edited agsLayerDescription.SelectionFeatures = selectedIDsList.ToArray(); // Get attributes panel and set to edit the attributes of selected features ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditAttributesPanel editAttributesPanel = this.ParentEditor.AttributesEditor as ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditAttributesPanel; ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResultCollection editAttributesPanelResults = editAttributesPanel.SetSelectedFeatures(agsLayerDescription.SelectionFeatures); this.CallbackResults.CopyFrom(editAttributesPanelResults); // Refresh map ESRI.ArcGIS.ADF.ArcGISServer.Editor.EditorUtilities.RefreshMap(this.ParentEditor, this.CallbackResults); // Refresh toolbars this.ParentEditor.RefreshToolbars(this.CallbackResults); } // Create callback result that calls JavaScript to hide AJAX activity indicator string jsHideIndicator = "hideSearchingIndicator();"; ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult hideIndicatorCallbackResult = ESRI.ArcGIS.ADF.Web.UI.WebControls.CallbackResult.CreateJavaScript(jsHideIndicator); this.CallbackResults.Add(hideIndicatorCallbackResult); } else { base.RaiseCallbackEvent(eventArgs); } } public override string GetCallbackResult() { // If the callback was initiated by a search operation, return the panel's callback results if (m_callbackArgsCollection["EventArg"] == "search") return this.CallbackResults.ToString(); else return base.GetCallbackResult(); } #endregion #region Instance Properties // Name of object ID field of selected layer protected string OIDfieldName { get { return (string)StateManager.GetProperty("selectedLayerOIDfield"); } set { StateManager.SetProperty("selectedLayerOIDfield", value); } } // Easy access to the CustomEditor containing the panel instance protected CustomEditor CustomEditorInstance { get { return (CustomEditor)this.ParentEditor; } } #endregion #region Instance Methods // Builds a query string from search parameters private string BuildQuery(string searchType, string[] searchFields, string searchValue) { string queryString = ""; string[] searchWords; // Check the specified search type switch (searchType) { case "All words": // Parse the words contained in the search value and place them in an array. // The Split method uses the space character as a default delimiter. searchWords = searchValue.Split(); // Since we only want to find features that contain all the words of the search // value, we iterate through the search words and build the query to extract // features that contain each word in any field. for (int i = 0; i < searchWords.Length; i++) { queryString += "("; for (int j = 0; j < searchFields.Length; j++) { queryString += string.Format("({0} LIKE '%{1}%')", searchFields[j], searchWords[i]); if (j < searchFields.Length - 1) queryString += " OR "; } queryString += ")"; if (i < searchWords.Length - 1) queryString += " AND "; } break; case "Any words": // Parse the words contained in the search value and place them in an array. // The Split method uses the space character as a default delimiter. searchWords = searchValue.Split(); // Since we want to find features that contain any of the words of the search // value, we iterate through the search words and build the query to extract // features that contain any word in any field. for (int i = 0; i < searchWords.Length; i++) { for (int j = 0; j < searchFields.Length; j++) { queryString += string.Format("({0} LIKE '%{1}%')", searchFields[j], searchWords[i]); if ((j < searchFields.Length - 1) || (i < searchWords.Length - 1)) queryString += " OR "; } } break; case "Exact phrase": // Since we only want to find features that contain the entire search value as // specified by the user, we iterate through the search fields and build the // query to extract features that contain the whole search value in any field. for (int i = 0; i < searchFields.Length; i++) { queryString += string.Format("({0} LIKE '%{1}%')", searchFields[i], searchValue); if (i < searchFields.Length - 1) queryString += " OR "; } break; default: string queryOperator = null; // For numeric operators, check the search type and initialize a variable // storing the corresponding logical operator switch (searchType) { case "Equal to": queryOperator = "="; break; case "Greater than": queryOperator = ">"; break; case "Less than": queryOperator = "<"; break; } // Iterate through the search fields and build a query to extract features // that have at least one value satisfying the relationship to the search // value specified by the query operator for (int i = 0; i < searchFields.Length; i++) { queryString += string.Format("({0} {1} {2})", searchFields[i], queryOperator, searchValue); if (i < searchFields.Length - 1) queryString += " OR "; } break; } return queryString; } #endregion } }