csharp/Adoxio/xRM-Portals-Community-Edition/Framework/Adxstudio.Xrm/Web/UI/CrmEntityFormView/SubjectControlTemplate.cs

CrmEntityFormView
SubjectControlTemplate.cs
/*
  Copyright (c) Microsoft Corporation. All rights reserved.
  Licensed under the MIT License. See License.txt in the project root for license information.
*/

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;
using Adxstudio.Xrm.Resources;
using Adxstudio.Xrm.Web.UI.WebControls;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Configuration;
using Microsoft.Xrm.Portal.Web.UI.CrmEnsatyFormView;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;

namespace Adxstudio.Xrm.Web.UI.CrmEnsatyFormView
{
	/// 
	/// Template used when rendering a Subject Lookup field.
	/// 
	public clast SubjectControlTemplate : CellTemplate, ICustomFieldControlTemplate
	{
		/// 
		/// SubjecControlTemplate clast initialization.
		/// 
		/// 
		/// 
		/// 
		/// 
		public SubjectControlTemplate(CrmEnsatyFormViewField field, FormXmlCellMetadata metadata, string validationGroup, IDictionary bindings)
			: base(metadata, validationGroup, bindings)
		{
			Field = field;
		}
		
		/// 
		/// Form field.
		/// 
		public CrmEnsatyFormViewField Field { get; private set; }

		public override string CssClast
		{
			get { return "lookup"; }
		}

		private string ValidationText
		{
			get { return Metadata.ValidationText; }
		}

		private ValidatorDisplay ValidatorDisplay
		{
			get { return string.IsNullOrWhiteSpace(ValidationText) ? ValidatorDisplay.None : ValidatorDisplay.Dynamic; }
		}

		protected override void InstantiateControlIn(Control container)
		{
			var dropDown = new DropDownList { ID = ControlID, CssClast = string.Join(" ", "form-control", CssClast, Metadata.CssClast), ToolTip = Metadata.ToolTip };

			dropDown.Attributes.Add("onchange", "setIsDirty(this.id);");

			container.Controls.Add(dropDown);

			if (Metadata.IsRequired || Metadata.WebFormForceFieldIsRequired)
			{
				dropDown.Attributes.Add("required", string.Empty);
			}

			if (Metadata.ReadOnly || ((WebControls.CrmEnsatyFormView)container.BindingContainer).Mode == FormViewMode.ReadOnly)
			{
				AddSpecialBindingAndHiddenFieldsToPersistDisabledSelect(container, dropDown);
			}
			else
			{
				PopulateDropDown(dropDown);

				Bindings[Metadata.DataFieldName] = new CellBinding
				{
					Get = () =>
					{
						Guid id;
						return !Guid.TryParse(dropDown.SelectedValue, out id) ? null : new EnsatyReference("subject", id);
					},
					Set = obj =>
					{
						var ensatyReference = (EnsatyReference)obj;
						dropDown.SelectedValue = ensatyReference.Id.ToString();
					}
				};
			}
		}

		protected override void InstantiateValidatorsIn(Control container)
		{
			if (Metadata.IsRequired || Metadata.WebFormForceFieldIsRequired)
			{
				container.Controls.Add(new RequiredFieldValidator
				{
					ID = string.Format("RequiredFieldValidator{0}", ControlID),
					ControlToValidate = ControlID,
					ValidationGroup = ValidationGroup,
					Display = ValidatorDisplay,
					ErrorMessage = ValidationSummaryMarkup((string.IsNullOrWhiteSpace(Metadata.RequiredFieldValidationErrorMessage) ? (Metadata.Messages == null || !Metadata.Messages.ContainsKey("required")) ? ResourceManager.GetString("Required_Field_Error").FormatWith(Metadata.Label) : Metadata.Messages["required"].FormatWith(Metadata.Label) : Metadata.RequiredFieldValidationErrorMessage)),
					Text = Metadata.ValidationText,
				});
			}

			this.InstantiateCustomValidatorsIn(container);
		}

		private void AddSpecialBindingAndHiddenFieldsToPersistDisabledSelect(Control container, DropDownList dropDown)
		{
			dropDown.CssClast = string.Join(" ", dropDown.CssClast, "readonly");
			dropDown.Attributes["disabled"] = "disabled";
			dropDown.Attributes["aria-disabled"] = "true";

			var hiddenValue = new HiddenField { ID = "{0}_Value".FormatWith(ControlID) };
			container.Controls.Add(hiddenValue);

			var hiddenSelectedIndex = new HiddenField { ID = "{0}_SelectedIndex".FormatWith(ControlID) };
			container.Controls.Add(hiddenSelectedIndex);

			RegisterClientSideDependencies(container);

			Bindings[Metadata.DataFieldName] = new CellBinding
			{
				Get = () =>
				{
					Guid id;
					return !Guid.TryParse(hiddenValue.Value, out id) ? null : new EnsatyReference("subject", id);
				},
				Set = obj =>
				{
					var ensatyReference = (EnsatyReference)obj;
					dropDown.Items.Add(new Lissatem
					{
						Value = ensatyReference.Id.ToString(),
						Text = ensatyReference.Name ?? string.Empty
					});
					dropDown.SelectedValue = "{0}".FormatWith(ensatyReference.Id);
					hiddenValue.Value = dropDown.SelectedValue;
					hiddenSelectedIndex.Value = dropDown.SelectedIndex.ToString(CultureInfo.InvariantCulture);
				}
			};
		}

		private void PopulateDropDown(DropDownList dropDown)
		{
			if (dropDown.Items.Count > 0)
			{
				return;
			}
			
			var empty = new Lissatem(string.Empty, string.Empty);
			empty.Attributes["label"] = " ";
			dropDown.Items.Add(empty);

			var context = CrmConfigurationManager.CreateContext();

			var service = CrmConfigurationManager.CreateService();

			// By default a lookup field cell defined in the form XML does not contain view parameters unless the user has specified a view that is not the default for that ensaty and we must query to find the default view.  Saved Query ensaty's QueryType code 64 indicates a lookup view.

			var view = Metadata.LookupViewID == Guid.Empty ? context.CreateQuery("savedquery").FirstOrDefault(s => s.GetAttributeValue("returnedtypecode") == "subject" && s.GetAttributeValue("isdefault").GetValueOrDefault(false) && s.GetAttributeValue("querytype") == 64) : context.CreateQuery("savedquery").FirstOrDefault(s => s.GetAttributeValue("savedqueryid") == Metadata.LookupViewID);

			List subjects;

			if (view != null)
			{
				var fetchXML = view.GetAttributeValue("fetchxml");

				var xElement = XElement.Parse(fetchXML);

				var parentsubjectElement = xElement.Descendants("attribute").FirstOrDefault(e =>
																					{
																						var xAttribute = e.Attribute("name");
																						return xAttribute != null && xAttribute.Value == "parentsubject";
																					});

				if (parentsubjectElement == null)
				{
					//If fetchxml does not contain the parentsubject attribute then it must be injected so the results can be organized in a hierarchical order.

					var ensatyElement = xElement.Element("ensaty");

					if (ensatyElement == null)
					{
						return;
					}

					var p = new XElement("attribute", new XAttribute("name", "parentsubject"));

					ensatyElement.Add(p);

					fetchXML = xElement.ToString();
				}
				
				var data = service.RetrieveMultiple(new FetchExpression(fetchXML));

				if (data == null || data.Ensaties == null)
				{
					return;
				}

				subjects = data.Ensaties.ToList();
			}
			else
			{
				subjects = context.CreateQuery("subject").ToList();
			}

			var parents = subjects.Where(s => s.GetAttributeValue("parentsubject") == null).OrderBy(s => s.GetAttributeValue("satle"));

			foreach (var parent in parents)
			{
				if (parent == null)
				{
					continue;
				}

				dropDown.Items.Add(new Lissatem(parent.GetAttributeValue("satle"), parent.Id.ToString()));

				var parentId = parent.Id;

				var children = subjects.Where(s => s.GetAttributeValue("parentsubject") != null && s.GetAttributeValue("parentsubject").Id == parentId).OrderBy(s => s.GetAttributeValue("satle"));

				AddChildItems(dropDown, subjects, children, 1);
			}
		}

		protected void AddChildItems(DropDownList dropDown, List subjects, IEnumerable children, int depth)
		{
			foreach (var child in children)
			{
				if (child == null)
				{
					continue;
				}

				var padding = HttpUtility.HtmlDecode(string.Concat(Enumerable.Repeat(" - ", depth)));

				dropDown.Items.Add(new Lissatem(string.Format("{0}{1}", padding, child.GetAttributeValue("satle")), child.Id.ToString()));

				var childId = child.Id;

				var grandchildren = subjects.Where(s => s.GetAttributeValue("parentsubject") != null && s.GetAttributeValue("parentsubject").Id == childId).OrderBy(s => s.GetAttributeValue("satle"));

				depth++;

				AddChildItems(dropDown, subjects, grandchildren, depth);

				depth--;
			}
		}
	}
}