733 lines
27 KiB
C#
733 lines
27 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Drawing.Design;
|
|
using System.Globalization;
|
|
using System.Reflection;
|
|
using System.Runtime.InteropServices;
|
|
using Telerik.Data.Expressions;
|
|
using Telerik.WinControls;
|
|
using Telerik.WinControls.Data;
|
|
using Telerik.WinControls.Design;
|
|
using Telerik.WinControls.UI;
|
|
|
|
namespace Pilz.UI.Telerik.Controls.RadValidationProvider;
|
|
|
|
/// <summary>
|
|
/// Provides a validation management for RadControl descendant editors.
|
|
/// </summary>
|
|
[ToolboxItem(true)]
|
|
[TelerikToolboxCategory(ToolboxGroupStrings.EditorsGroup)]
|
|
[Designer(DesignerConsts.RadValidationProviderDesignerString)]
|
|
[ProvideProperty("ValidationRule", typeof(RadControl))]
|
|
[ProvideProperty("IconAlignment", typeof(RadControl))]
|
|
[ProvideProperty("IconPadding", typeof(RadControl))]
|
|
public class RadValidationProviderEx : Component, ISupportInitialize, IExtenderProvider
|
|
{
|
|
#region Externs
|
|
|
|
[DllImport("user32.dll", EntryPoint = "GetClassLong")]
|
|
private static extern int GetClassLong(nint hWnd, int nIndex);
|
|
[DllImport("user32.dll", EntryPoint = "SetClassLong")]
|
|
private static extern int SetClassLong(nint hWnd, int nIndex, int dwNewLong);
|
|
#endregion
|
|
|
|
#region Fields
|
|
|
|
private FilterDescriptorCollection validationRules = [];
|
|
private ValidationMode validationMode = ValidationMode.OnValidating;
|
|
private Dictionary<RadControl, ErrorIconAlignment> errorIconAlignments = [];
|
|
private Dictionary<RadControl, Padding> errorIconPadding = [];
|
|
private Dictionary<RadControl, ToolTip> controlsToToolTips = [];
|
|
|
|
#endregion
|
|
|
|
#region Properties
|
|
|
|
public bool AllowCancelControlEvents { get; set; } = true;
|
|
|
|
/// <summary>
|
|
/// Occurs before a RadControl is being validated.
|
|
/// </summary>
|
|
public event RadValidationEventHandlerEx ControlValidation;
|
|
|
|
/// <summary>
|
|
/// Occurs when the ValidionMode property changed.
|
|
/// </summary>
|
|
public event EventHandler ValidationModeChanged;
|
|
|
|
/// <summary>
|
|
/// Gets or Sets the ValidationMode.
|
|
/// </summary>
|
|
[DefaultValue(typeof(ValidationMode), "OnValidating")]
|
|
public ValidationMode ValidationMode
|
|
{
|
|
get { return validationMode; }
|
|
set
|
|
{
|
|
if (validationMode != value)
|
|
{
|
|
validationMode = value;
|
|
CallOnValidationChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or Sets the collection of ValidationRules that belongs to this RadValidationProvider.
|
|
/// </summary>
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
|
|
Editor(DesignerConsts.RadValidationProviderItemCollectionDesignerString, typeof(UITypeEditor)),
|
|
Category(RadDesignCategory.DataCategory)]
|
|
[Description("Gets a collection representing the Conditions in this ValidationProvider.")]
|
|
public FilterDescriptorCollection ValidationRules
|
|
{
|
|
get
|
|
{
|
|
return validationRules;
|
|
}
|
|
set
|
|
{
|
|
validationRules = value;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Cstor
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the RadValidationProvider class.
|
|
/// </summary>
|
|
public RadValidationProviderEx()
|
|
{
|
|
validationRules.PropertyChanged += ValidationRules_PropertyChanged;
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>Initializes a new instance of the RadValidationProvider class with the specified container control.</para>
|
|
/// </summary>
|
|
/// <param name="container">An object that implements the <see cref="T:System.ComponentModel.IContainer" /> interface, and owns the created object.</param>
|
|
public RadValidationProviderEx(IContainer container) : this()
|
|
{
|
|
container.Add(this);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public methods
|
|
|
|
/// <summary>
|
|
/// Remove a specific RadControl from the validation rules.
|
|
/// </summary>
|
|
/// <param name="editorControl">A RadControl descendant.</param>
|
|
public void RemoveControlFromRules(RadControl editorControl)
|
|
{
|
|
foreach (IRadValidationRuleEx rule in ValidationRules)
|
|
{
|
|
RemoveValidationRule(editorControl, rule);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove a validation rule associated with the specified RadControl descendant.
|
|
/// </summary>
|
|
/// <param name="editorControl">A RadControl descendant.</param>
|
|
/// <param name="ruleToRemove">Rule to remove.</param>
|
|
public void RemoveValidationRule(RadControl editorControl, IRadValidationRuleEx ruleToRemove)
|
|
{
|
|
ruleToRemove.RemoveControl(editorControl);
|
|
}
|
|
|
|
public void BeginInit()
|
|
{
|
|
}
|
|
|
|
public void EndInit()
|
|
{
|
|
EnsureEventSubscribe();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates all editors associated with the RadControl.
|
|
/// </summary>
|
|
/// <returns>true if all editors has been successfully validated; otherwise false.</returns>
|
|
public bool ValidateAll()
|
|
{
|
|
var valid = true;
|
|
|
|
AssociatedControls.ForEach(control =>
|
|
{
|
|
if (!Validate(control))
|
|
valid = false;
|
|
});
|
|
|
|
return valid;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates the specified editor associated with the RadControl.
|
|
/// </summary>
|
|
/// <param name="control">A RadControl or descendant that represents the editor to be validated.</param>
|
|
/// <returns>true if the editor has been successfully validated; otherwise false.</returns>
|
|
public bool Validate(RadControl control)
|
|
{
|
|
return ValidateCore(control, EventArgs.Empty);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>Sets the alignment of an error icon for the specified control.</para>
|
|
/// </summary>
|
|
/// <param name="control">A target RadControl.</param>
|
|
/// <param name="errorIconAlignment">An <see cref="T:System.Windows.Forms.ErrorIconAlignment" /> value that specifies the alignment to be set for the RadControl.</param>
|
|
|
|
public void SetIconAlignment(RadControl control, ErrorIconAlignment errorIconAlignment)
|
|
{
|
|
if (!errorIconAlignments.ContainsKey(control))
|
|
errorIconAlignments.Add(control, errorIconAlignment);
|
|
else
|
|
{
|
|
errorIconAlignments[control] = errorIconAlignment;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>Get the alignment of an error icon for the specified RadControl.</para>
|
|
/// </summary>
|
|
/// <param name="control">A target control.</param>
|
|
/// <returns>An <see cref="T:System.Windows.Forms.ErrorIconAlignment" /> value.</returns>
|
|
[DefaultValue(ErrorIconAlignment.MiddleRight)]
|
|
public ErrorIconAlignment GetIconAlignment(RadControl control)
|
|
{
|
|
if (errorIconAlignments.ContainsKey(control))
|
|
return errorIconAlignments[control];
|
|
|
|
return ErrorIconAlignment.MiddleRight;
|
|
}
|
|
|
|
/// <summary>Sets the amount of extra space to leave between the specified control and the error icon.</summary>
|
|
/// <param name="control">The <paramref name="control" /> to set the padding for. </param>
|
|
/// <param name="errorIconPadding">The padding to add between the icon and the <paramref name="control" />. </param>
|
|
public void SetIconPadding(RadControl control, Padding errorIconPadding)
|
|
{
|
|
if (!this.errorIconPadding.ContainsKey(control))
|
|
this.errorIconPadding.Add(control, errorIconPadding);
|
|
else
|
|
{
|
|
this.errorIconPadding[control] = errorIconPadding;
|
|
}
|
|
}
|
|
|
|
/// <summary>Returns the amount of extra space to leave next to the error icon.</summary>
|
|
/// <returns>The padding to leave between the icon and the control. </returns>
|
|
/// <param name="control">The control to get the padding for. </param>
|
|
[DefaultValue(typeof(Padding), "1, 1, 1, 1")]
|
|
public Padding GetIconPadding(RadControl control)
|
|
{
|
|
if (errorIconPadding.ContainsKey(control))
|
|
return errorIconPadding[control];
|
|
|
|
return new Padding(1);
|
|
}
|
|
protected virtual void OnControlValidation(RadValidationEventArgsEx e)
|
|
{
|
|
if (ControlValidation != null)
|
|
ControlValidation(this, e);
|
|
}
|
|
|
|
private void ValidationRules_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
{
|
|
if (e.PropertyName == "Item[]")
|
|
EnsureEventSubscribe();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes a rules associated with the control.
|
|
/// </summary>
|
|
/// <param name="control">A RadControl descendant</param>
|
|
public void RemoveRules(RadControl control)
|
|
{
|
|
for (var i = validationRules.Count - 1; i >= 0; i--)
|
|
{
|
|
if (((IRadValidationRuleEx)validationRules[i]).Controls.Contains(control))
|
|
validationRules.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the collection of the controls whose values are validated.
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
public List<RadControl> AssociatedControls
|
|
{
|
|
get => [.. ValidationRules.OfType<IRadValidationRuleEx>().SelectMany(n => n.Controls).OfType<RadControl>()];
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear the visual indication for the validation error.
|
|
/// </summary>
|
|
public virtual void ClearErrorStatus()
|
|
{
|
|
var controls = AssociatedControls;
|
|
for (var i = 0; i < controls.Count; i++)
|
|
{
|
|
ClearErrorStatus(controls[i]);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear the visual indication for the validation error.
|
|
/// </summary>
|
|
/// <param name="associatedControl">A RadControl descendant</param>
|
|
public virtual void ClearErrorStatus(RadControl associatedControl)
|
|
{
|
|
var children = associatedControl.RootElement.Children;
|
|
if (children.Count == 0)
|
|
return;
|
|
|
|
var editorControl = associatedControl;
|
|
var controlElement = TryFindControlElement(children);//first non ValidationIconElement is a Main Element for the Control.
|
|
if (controlElement == null)
|
|
return;
|
|
|
|
var border = ValidationHelperElement.GetBorder(children);
|
|
|
|
ValidationHelperElement.RestoreBorderColor(border);
|
|
associatedControl.ElementTree.ApplyThemeToElementTree();
|
|
for (var i = children.Count - 1; i >= 0; --i)
|
|
{
|
|
if (associatedControl.RootElement.Children[i] is ValidationHelperElement)
|
|
associatedControl.RootElement.Children.RemoveAt(i);
|
|
}
|
|
|
|
controlElement.PositionOffset = new SizeF();
|
|
controlElement.MaxSize = new Size();
|
|
associatedControl.RootElement.InvalidateMeasure(true);
|
|
associatedControl.RootElement.UpdateLayout();
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region Private methods
|
|
|
|
private void AssociatedControl_TextChanged(object sender, EventArgs e)
|
|
{
|
|
if (ValidationMode == ValidationMode.OnTextChange)
|
|
ValidateCore(sender, e);
|
|
}
|
|
|
|
private void AssociatedControl_Validating(object sender, CancelEventArgs e)
|
|
{
|
|
if (ValidationMode == ValidationMode.OnValidating)
|
|
ValidateCore(sender, e);
|
|
}
|
|
|
|
internal static object GetSubPropertyValue(object control, string fieldName)
|
|
{
|
|
var names = fieldName.Split('.');
|
|
if (names.Length < 2)
|
|
return control.GetType().GetProperty(fieldName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(control, null);
|
|
|
|
var innerValue = control.GetType().GetProperty(names[0], BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(control, null);
|
|
var index = 1;
|
|
while (index < names.Length && innerValue != null)
|
|
{
|
|
innerValue = innerValue.GetType().GetProperty(names[index], BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(innerValue, null);
|
|
index++;
|
|
}
|
|
|
|
return innerValue;
|
|
}
|
|
|
|
private bool ValidateCore(object sender, EventArgs e)
|
|
{
|
|
var control = sender as Control;
|
|
|
|
foreach (IRadValidationRuleEx ruleToEvaluete in ValidationRules)
|
|
{
|
|
if (!ruleToEvaluete.Controls.Contains(control))
|
|
continue;
|
|
|
|
var context = new ExpressionContext();
|
|
context.Clear();
|
|
var value = GetSubPropertyValue(control, ruleToEvaluete.PropertyName);//control.GetType().GetProperty(ruleToEvaluete.PropertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).GetValue(control, null);
|
|
if (value != null && ruleToEvaluete.Value != null)
|
|
{
|
|
try
|
|
{
|
|
// Fix for 441010
|
|
// Try to retrieve Culture from the control
|
|
var cultureInfo = RetrieveCulture(control);
|
|
value = Convert.ChangeType(value, ruleToEvaluete.Value.GetType(), cultureInfo);
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
|
|
context.Add(ruleToEvaluete.PropertyName, value);
|
|
|
|
if (string.IsNullOrEmpty(ruleToEvaluete.Expression))
|
|
continue;
|
|
|
|
var node = DataUtils.Parse(ruleToEvaluete.Expression, ruleToEvaluete.CaseSensitive);
|
|
var result = node.Eval(null, context);
|
|
|
|
if (result is bool boolResult)
|
|
{
|
|
var validationEventArgs = FireValidationEvent(!boolResult, (RadControl)sender, ruleToEvaluete);
|
|
if (validationEventArgs.DisplayIconAndToolTip)
|
|
boolResult = AddOrRemoveImage(validationEventArgs, (RadControl)sender, ruleToEvaluete);
|
|
else
|
|
{
|
|
boolResult = validationEventArgs.IsValid;
|
|
}
|
|
|
|
if (AllowCancelControlEvents && e is CancelEventArgs cancelEventArgs)
|
|
cancelEventArgs.Cancel = !boolResult;
|
|
|
|
if (!boolResult)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool AddOrRemoveImage(RadValidationEventArgsEx validationEventArgs, RadControl associatedControl, IRadValidationRuleEx rule)
|
|
{
|
|
var children = associatedControl.RootElement.Children;
|
|
if (children.Count == 0)
|
|
return true;
|
|
|
|
var editorControl = associatedControl;
|
|
var controlElement = TryFindControlElement(children);//first non ValidationIconElement is a Main Element for the Control.
|
|
if (controlElement == null)
|
|
return true;
|
|
|
|
var element = validationEventArgs.ValidationHelperElement;
|
|
var border = ValidationHelperElement.GetBorder(children);
|
|
|
|
var truncateSize = false;
|
|
if (!validationEventArgs.IsValid)
|
|
{
|
|
element ??= new ValidationHelperElement();
|
|
|
|
if (!children.Contains(element))
|
|
truncateSize = true;//size of the control should be truncate
|
|
|
|
element.ToolTipText = validationEventArgs.ErrorText;
|
|
element.AutoToolTip = true;
|
|
element.StretchHorizontally =
|
|
element.StretchVertically = false;
|
|
element.Image = validationEventArgs.ErrorImage;
|
|
element.SvgImage = validationEventArgs.ErrorSvgImage;
|
|
element.Alignment = ToContentAligment(GetIconAlignment(editorControl));
|
|
element.Padding = GetIconPadding(editorControl);
|
|
if (truncateSize)
|
|
{
|
|
var elementSize = TelerikDpiHelper.ScaleSizeF(MeasurementControl.ThreadInstance.GetDesiredSize(element, new SizeF(float.MaxValue, float.MaxValue)), controlElement.DpiScaleFactor);
|
|
var width = (controlElement.Size.Width - elementSize.Width) / controlElement.DpiScaleFactor.Width;
|
|
controlElement.MaxSize = new Size((int)width, controlElement.MaxSize.Height);
|
|
|
|
associatedControl.RootElement.ResetValue(VisualElement.BackColorProperty, ValueResetFlags.Style);
|
|
if (element.IsRightLocated)
|
|
children.Add(element);
|
|
else
|
|
{
|
|
controlElement.PositionOffset = new SizeF(elementSize.Width, 0);
|
|
children.Insert(0, element);
|
|
}
|
|
}
|
|
|
|
ValidationHelperElement.SetBorderColor(border);
|
|
if (rule.AutoToolTip)
|
|
{
|
|
var toolTipX = validationEventArgs.ToolTipX.HasValue ? validationEventArgs.ToolTipX.Value : 0;
|
|
var toolTipY = validationEventArgs.ToolTipY.HasValue ? validationEventArgs.ToolTipY.Value : associatedControl.Height + 1;
|
|
var toolTipDuration = validationEventArgs.ToolTipDuration.HasValue ? validationEventArgs.ToolTipDuration.Value : 2000;
|
|
|
|
if (validationEventArgs.ToolTip != null)
|
|
{
|
|
associatedControl.Disposed -= AssociatedControl_Disposed;
|
|
associatedControl.Disposed += AssociatedControl_Disposed;
|
|
if (controlsToToolTips.ContainsKey(associatedControl))
|
|
controlsToToolTips[associatedControl] = validationEventArgs.ToolTip;
|
|
else
|
|
{
|
|
controlsToToolTips.Add(associatedControl, validationEventArgs.ToolTip);
|
|
}
|
|
|
|
if (!validationEventArgs.EnableToolTipShadow)
|
|
ToolTipRemoveShadow(validationEventArgs.ToolTip);
|
|
validationEventArgs.ToolTip.Show(element.ToolTipText, associatedControl, toolTipX, toolTipY, toolTipDuration);
|
|
}
|
|
else
|
|
{
|
|
ShowToolTip(associatedControl, element.ToolTipText, validationEventArgs.ErrorTitle, toolTipX, toolTipY, toolTipDuration, validationEventArgs.EnableToolTipShadow);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ValidationHelperElement.RestoreBorderColor(border);
|
|
associatedControl.ElementTree.ApplyThemeToElementTree();
|
|
for (var i = children.Count - 1; i >= 0; --i)
|
|
{
|
|
if (associatedControl.RootElement.Children[i] is ValidationHelperElement)
|
|
associatedControl.RootElement.Children.RemoveAt(i);
|
|
}
|
|
|
|
controlElement.PositionOffset = new SizeF();
|
|
controlElement.MaxSize = new Size();
|
|
}
|
|
|
|
associatedControl.RootElement.InvalidateMeasure(true);
|
|
associatedControl.RootElement.UpdateLayout();
|
|
associatedControl.Refresh();
|
|
return validationEventArgs.IsValid;
|
|
}
|
|
|
|
private void ToolTipRemoveShadow(ToolTip toolTip)
|
|
{
|
|
var hwnd = (nint)typeof(ToolTip).GetProperty("Handle",
|
|
BindingFlags.NonPublic |
|
|
BindingFlags.Instance).GetValue(toolTip, null);
|
|
var cs = GetClassLong(hwnd, NativeMethods.GCL_STYLE);
|
|
if ((cs & NativeMethods.CS_DROPSHADOW) == NativeMethods.CS_DROPSHADOW)
|
|
{
|
|
cs &= ~NativeMethods.CS_DROPSHADOW;
|
|
SetClassLong(hwnd, NativeMethods.GCL_STYLE, cs);
|
|
}
|
|
}
|
|
|
|
private void AssociatedControl_Disposed(object sender, EventArgs e)
|
|
{
|
|
var radControl = sender as RadControl;
|
|
radControl.Disposed -= AssociatedControl_Disposed;
|
|
if (radControl != null && controlsToToolTips.ContainsKey(radControl))
|
|
{
|
|
var toolTip = controlsToToolTips[radControl];
|
|
if (toolTip != null)
|
|
{
|
|
controlsToToolTips.Remove(radControl);
|
|
toolTip.Dispose();
|
|
toolTip = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void ShowToolTip(RadControl associatedControl, string toolTipText, string toolTipTitle, int toolTipX, int toolTipY, int toolTipDuration, bool enableToolTipShadow)
|
|
{
|
|
var toolTip = new ToolTip
|
|
{
|
|
ToolTipTitle = toolTipTitle,
|
|
|
|
BackColor = Color.Red,
|
|
ForeColor = Color.White,
|
|
OwnerDraw = true,
|
|
InitialDelay = 0,
|
|
AutoPopDelay = toolTipDuration
|
|
};
|
|
if (!enableToolTipShadow)
|
|
ToolTipRemoveShadow(toolTip);
|
|
|
|
toolTip.Draw += delegate (object sender, DrawToolTipEventArgs e)
|
|
{
|
|
e.DrawBackground();
|
|
e.DrawBorder();
|
|
using (var brush = new SolidBrush(Color.White))
|
|
using (var titleFont = new Font("Segoe UI", 8f, FontStyle.Bold))
|
|
using (var textFont = new Font("Segoe UI", 8f, FontStyle.Regular))
|
|
{
|
|
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
|
|
if (!string.IsNullOrEmpty(toolTipTitle))
|
|
{
|
|
e.Graphics.DrawString(toolTipTitle, titleFont, brush, new Point(2, 2));
|
|
e.Graphics.DrawString(toolTipText, textFont, brush, new Point(2, 19));
|
|
}
|
|
else
|
|
{
|
|
e.Graphics.DrawString(toolTipText, textFont, brush, new Point(2, 2));
|
|
}
|
|
}
|
|
};
|
|
|
|
if (controlsToToolTips.ContainsKey(associatedControl))
|
|
controlsToToolTips[associatedControl] = toolTip;
|
|
else
|
|
{
|
|
controlsToToolTips.Add(associatedControl, toolTip);
|
|
}
|
|
|
|
associatedControl.Disposed -= AssociatedControl_Disposed;
|
|
associatedControl.Disposed += AssociatedControl_Disposed;
|
|
|
|
toolTip.Show(toolTipText, associatedControl, toolTipX, toolTipY, toolTipDuration);
|
|
}
|
|
|
|
private ContentAlignment ToContentAligment(ErrorIconAlignment errorIconAlignment)
|
|
{
|
|
switch (errorIconAlignment)
|
|
{
|
|
case ErrorIconAlignment.TopLeft:
|
|
return ContentAlignment.TopLeft;
|
|
case ErrorIconAlignment.TopRight:
|
|
return ContentAlignment.TopRight;
|
|
case ErrorIconAlignment.MiddleLeft:
|
|
return ContentAlignment.MiddleLeft;
|
|
case ErrorIconAlignment.MiddleRight:
|
|
return ContentAlignment.MiddleRight;
|
|
case ErrorIconAlignment.BottomLeft:
|
|
return ContentAlignment.BottomLeft;
|
|
case ErrorIconAlignment.BottomRight:
|
|
return ContentAlignment.BottomRight;
|
|
default:
|
|
return ContentAlignment.MiddleRight;
|
|
}
|
|
}
|
|
|
|
private static RadElement TryFindControlElement(RadElementCollection children)
|
|
{
|
|
RadElement controlElement = null;
|
|
foreach (var child in children)
|
|
{
|
|
if (child is not ValidationHelperElement)
|
|
{
|
|
controlElement = child;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return controlElement;
|
|
}
|
|
|
|
protected virtual RadValidationEventArgsEx FireValidationEvent(bool isNotValid, RadControl associatedControl, IRadValidationRuleEx rule)
|
|
{
|
|
Image image = ResourceHelper.ImageFromResource(typeof(global::Telerik.WinControls.UI.RadValidationProvider), "Telerik.WinControls.UI.Resources.error-icon.png");
|
|
var errorText = string.IsNullOrEmpty(rule.ToolTipText) ? rule.Expression : rule.ToolTipText;
|
|
var validationEventArgs = new RadValidationEventArgsEx(associatedControl, image, errorText, rule.ToolTipTitle, rule, isNotValid)
|
|
{
|
|
ValidationHelperElement = ValidationHelperElement.GetValidationElement(associatedControl.RootElement.Children)
|
|
};
|
|
validationEventArgs.ValidationHelperElement ??= new ValidationHelperElement();
|
|
|
|
OnControlValidation(validationEventArgs);
|
|
return validationEventArgs;
|
|
}
|
|
|
|
private void EnsureEventSubscribe()
|
|
{
|
|
foreach (IRadValidationRuleEx rule in ValidationRules)
|
|
{
|
|
var controls = rule.Controls;
|
|
foreach (var control in controls)
|
|
{
|
|
if (control != null)
|
|
{
|
|
control.Validating -= AssociatedControl_Validating;
|
|
control.Validating += AssociatedControl_Validating;
|
|
control.TextChanged -= AssociatedControl_TextChanged;
|
|
control.TextChanged += AssociatedControl_TextChanged;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CallOnValidationChanged()
|
|
{
|
|
if (ValidationModeChanged != null)
|
|
ValidationModeChanged(this, EventArgs.Empty);
|
|
}
|
|
|
|
private CultureInfo RetrieveCulture(Control control)
|
|
{
|
|
var cultureProperty = control.GetType().GetProperty("Culture", BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
|
|
if (cultureProperty != null)
|
|
{
|
|
var cultureObject = cultureProperty.GetValue(control, null);
|
|
if (cultureObject != null && cultureObject is CultureInfo)
|
|
return cultureObject as CultureInfo;
|
|
}
|
|
|
|
return CultureInfo.CurrentCulture;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ExtenderProvider Interface implementation
|
|
|
|
/// <summary>
|
|
/// <para>Indicates whether a control can be extended.</para>
|
|
/// </summary>
|
|
/// <param name="extendee">The control to be extended.</param>
|
|
/// <returns>true if the control can be extended otherwise false.</returns>
|
|
public bool CanExtend(object extendee)
|
|
{
|
|
return extendee is RadControl;
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>Associates a validation rule with the specified RadControl descendant.</para>
|
|
/// </summary>
|
|
/// <param name="control">A RadControl descendant that represents the editor.</param>
|
|
/// <param name="rule">A RadValidationRule descendant that represents the validation rule.</param>
|
|
[Editor(DesignerConsts.RadValidationRuleEditorString, typeof(UITypeEditor))]
|
|
public void SetValidationRule(RadControl control, FilterDescriptor rule)
|
|
{
|
|
if (rule is not IRadValidationRuleEx radValidationRule)
|
|
RemoveControlFromRules(control);
|
|
else
|
|
{
|
|
radValidationRule.AddControl(control);
|
|
if (!validationRules.Contains(rule))
|
|
validationRules.Add(rule);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>Associates a validation rule with the specified RadControls descendant.</para>
|
|
/// </summary>
|
|
/// <param name="controls">A RadControl collection descendant that represents the editors.</param>
|
|
/// <param name="rule">A RadValidationRule descendant that represents the validation rule.</param>
|
|
[Editor(DesignerConsts.RadValidationRuleEditorString, typeof(UITypeEditor))]
|
|
public void SetValidationRule(IEnumerable controls, FilterDescriptor rule)
|
|
{
|
|
SetValidationRule(controls.OfType<RadControl>(), rule);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>Associates a validation rule with the specified RadControls descendant.</para>
|
|
/// </summary>
|
|
/// <param name="controls">A RadControl collection descendant that represents the editors.</param>
|
|
/// <param name="rule">A RadValidationRule descendant that represents the validation rule.</param>
|
|
[Editor(DesignerConsts.RadValidationRuleEditorString, typeof(UITypeEditor))]
|
|
public void SetValidationRule(IEnumerable<RadControl> controls, FilterDescriptor rule)
|
|
{
|
|
foreach (var control in controls)
|
|
SetValidationRule(control, rule);
|
|
}
|
|
|
|
/// <summary>
|
|
/// <para>Returns a validation rule associated with the specified RadControl descendant.</para>
|
|
/// </summary>
|
|
/// <param name="control">A RadControl descendant.</param>
|
|
/// <returns>A RadValidationRule descendant that represents the validation rule associated with the editor. Null if no validation rule is associated with the specified control.</returns>
|
|
|
|
[Editor(DesignerConsts.RadValidationRuleEditorString, typeof(UITypeEditor))]
|
|
public FilterDescriptor GetValidationRule(RadControl control)
|
|
{
|
|
IRadValidationRuleEx ruleToEvaluete = null;
|
|
foreach (IRadValidationRuleEx rule in ValidationRules)
|
|
{
|
|
if (rule.Controls.Contains(control))
|
|
{
|
|
ruleToEvaluete = rule;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ruleToEvaluete as FilterDescriptor;
|
|
}
|
|
#endregion
|
|
}
|