如何为用户控件中的所有控件设置验证?

3
我正在寻找一种最佳方法来为用户控件中包含的所有控件设置验证组。在加载控件时,控件中的大多数控件是动态创建的。它有相当多的输入字段和验证器。
我想通过某种可以循环遍历所有内容并设置验证的函数来节省时间,以设置所有控件和验证器的验证。
然而,似乎没有包括所有具有该属性的不同控件的验证组的一致接口。
我应该使用反射来检查验证组吗?我知道我可以这样做,但是否有更好的方法?
顺便说一下,我们正在使用C#。
如果有帮助,谢谢!
3个回答

3

我只是想标记一下这个问题已经得到解决。

以下是我用来设置验证组的代码。我决定使用反射,因为我可以检查那些我知道具有ValidationGroup的类型,并进行强制转换和设置,但是有很多类型需要检查,而且可能会错过将来可能添加的新控件。如果ValidationGroup是某种接口的一部分,必须实现它,那就太好了。

/// <summary>
/// this is an extension method to iterate though all controls in a control collection
/// put this in some static library somewhere
/// </summary>
/// <param name="controls"></param>
/// <returns></returns>
public static IEnumerable<Control> All(this ControlCollection controls)
{
    foreach (Control control in controls)
    {
        foreach (Control grandChild in control.Controls.All())
            yield return grandChild;

        yield return control;
    }
}


/// <summary>
/// this function uses reflection to check if the validation group exists, and then set it to the 
/// specified string
/// </summary>
/// <param name="ValidationGroup"></param>
private void SetValidationGroup(string ValidationGroup)
{
    //set the validation group for all controls
    if (ValidationGroup.IsNotNullOrEmpty())
    {
        foreach (Control c in Controls.All())
        {
            var Properties = c.GetType().GetProperties();
            var vg = Properties.Where(p => p.Name == "ValidationGroup").SingleOrDefault();
            if (vg != null)
            {
                vg.SetValue(c, ValidationGroup, null);
            }

        }

    }
}

1

我最近遇到了一个非常类似的问题- 我使用的解决方案是创建了一些扩展方法,可以循环遍历控件的所有子/后代控件,找到特定类型的控件,然后在它们上调用一个子例程(例如,设置控件的任何属性)。下面是VB.Net中的代码(抱歉,这是我们在工作中使用的语言,但我相信代码转换器应该能够为您解决这个问题)。

Public Module ControlExtensionMethods

''' <summary>
''' Gets all validation controls used by a control.
''' </summary>
''' <param name="onlyGetVisible">If true, will only fetch validation controls that currently apply (i.e. that are visible). The default value is true.</param>
''' <returns></returns>
''' <remarks></remarks>
<Extension()>
Public Function GetAllValidationControls(ByVal target As Control, Optional ByVal onlyGetVisible As Boolean = True) As ReadOnlyCollection(Of BaseValidator)
    Dim validators As New List(Of BaseValidator)
    GetControlsOfType(Of BaseValidator)(target, Function(x) Not onlyGetVisible OrElse x.Visible = onlyGetVisible, validators)
    Return validators.AsReadOnly()
End Function

''' <summary>
''' Gets if the control is in a valid state (if all child/descendent validation controls return valid)
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
<Extension()>
Public Function IsValid(ByVal target As Control) As Boolean
    Return target.GetAllValidationControls().All(Function(x)
                                                     x.Validate()
                                                     Return x.IsValid
                                                 End Function)
End Function

''' <summary>
''' Iteratively fetches all controls of a specified type/base type from a control and its descendents.
''' </summary>
''' <param name="fromControl"></param>
''' <param name="predicate">If provided, will only return controls that match the provided predicate</param>
''' <remarks></remarks>
<Extension()>
Public Function GetControlsOfType(Of T As Control)(ByVal fromControl As Control, Optional ByVal predicate As Predicate(Of T) = Nothing) As IList(Of T)
    Dim results As New List(Of T)
    GetControlsOfType(fromControl, predicate, results)
    Return results
End Function

Private Sub GetControlsOfType(Of T As Control)(ByVal fromControl As Control, ByVal predicate As Predicate(Of T), ByVal results As IList(Of T))
    'create default predicate that always returns true if none is provided
    Dim cntrl As Control

    If predicate Is Nothing Then predicate = Function(x) True

    If fromControl.HasControls Then
        For Each cntrl In fromControl.Controls
            GetControlsOfType(Of T)(cntrl, predicate, results)
        Next
    End If

    If TypeOf fromControl Is T AndAlso predicate(fromControl) Then
        results.Add(fromControl)
    End If
End Sub
End Module

使用此代码禁用所有验证器的示例:

Array.ForEach(myUserControl.GetAllValidationControls().ToArray(), sub(x) x.Enabled = False)

这很好,但不完全是我需要的。我认为该代码仅返回一个验证器列表,但我要找的是所有具有ValidationGroup属性的内容,包括文本框、按钮、验证摘要等等。 - Chris Mullins
在GetControlsOfType()函数中,您可以指定一个谓词。因此,请执行以下操作:userControl.GetControlsOfType(Of Control)(sub(x) x.ValidationGroup = "myValidationGroup") - WiseGuyEh
真的。我必须为每个可能具有ValidationGroup属性的控件类型调用该函数,这可能是许多不同的类型。 - Chris Mullins
啊,我以为“ValidationGroup”是从WebControl继承而来的。在这种情况下,只需添加一个基于反射的谓词,检查ValidationGroup属性是否存在,如下所示:userControl.GetControlsOfType(Of Control)(sub(x) x.GetType().GetProperty("ValidationGroup") IsNot Nothing). 我知道你说你正在寻找更好的方法,但似乎确实没有更好的方法了。如果你想要更快的方法,你可以记录你已经检查过的类型,以及它们是否具有ValidationGroup属性-至少这样你可以减少昂贵的GetProperty调用。 - WiseGuyEh

0

我刚刚也遇到了这个问题,但是想出了一个不需要鸭子类型的替代方案:

string newGroup = "foo";
IEnumerable<BaseValidator> validators = this.Controls.OfType<BaseValidator>();
IEnumerable<Button> buttons = this.Controls.OfType<Button>();

foreach (var validator in validators)
    validator.ValidationGroup = newGroup;

foreach (var button in buttons)
    button.ValidationGroup = newGroup;

这也可能是一种替代方案:

foreach (var c in this.Controls)
{
    if (c is BaseValidator)
        (c as BaseValidator).ValidationGroup = newGroup;
    else if (c is Button)
        (c as Button).ValidationGroup = newGroup;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接