TemplateBinding不适用于ValidationRules依赖项属性

时间:2012-01-16 21:10:25

标签: c# wpf xaml

我正在尝试制作cutom验证器控件,但不知道为什么我想在ValidationRules上绑定到模板化父级的Message Property。它运行但每次都是空的。不知道为什么每次都是空的。

可以找到示例项目here

风格

   <Style TargetType="{x:Type local:RequiredFieldBox}">
    <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="{x:Type local:RequiredFieldBox}">
                <StackPanel Orientation="Vertical">

                    <TextBox>
                        <Binding  RelativeSource="{RelativeSource TemplatedParent}" Path="Text">
                        <Binding.ValidationRules>
                            <rule:RequiredFieldRule>
                                <rule:RequiredFieldRule.Params>
                                    <rule:ValidationParams 
                                        Message="{TemplateBinding Msg}"
                                        ValidationType="{TemplateBinding Type}"/>
                                </rule:RequiredFieldRule.Params>
                            </rule:RequiredFieldRule> 
                        </Binding.ValidationRules>
                    </Binding>
                        <TextBox.Style>
                    <Style TargetType="{x:Type TextBox}">
                      <Style.Triggers>
                           <Trigger Property="Validation.HasError" Value="true" >
                           <Setter Property="Foreground" Value="Red"/>
                           <Setter Property="Background" Value="MistyRose"/>
                           <Setter Property="BorderBrush" Value="Red"/>
                           <Setter Property="BorderThickness" Value="1.0"/>
                            <Setter Property="VerticalContentAlignment" Value="Center"/>
                           </Trigger>
                       </Style.Triggers>
                      <Setter Property="Validation.ErrorTemplate">
                         <Setter.Value>
                            <ControlTemplate>
                               <StackPanel>
                                  <StackPanel Orientation="Horizontal" VerticalAlignment="Top" Margin="40">
                                    <AdornedElementPlaceholder x:Name="Holder"/>
                                    <Image Height="{Binding Height, ElementName=Holder}" Width="20" Margin="10,0"
                                        Source="/Images/restricted.png" ToolTip="{Binding ElementName=Holder, 
                                        Path=AdornedElement.(Validation.Errors)
                     [0].ErrorContent}"/>
                                 </StackPanel>
                               </StackPanel>
                            </ControlTemplate>
                         </Setter.Value>
                    </Setter>
                 </Style>
             </TextBox.Style>
          </TextBox>
         </StackPanel>
        </ControlTemplate>
   </Setter.Value>
</Setter>

验证参数类

public class ValidationParams : DependencyObject
{

    public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
      "Message",
      typeof(string),
      typeof(ValidationParams),
      new FrameworkPropertyMetadata(null));
    // Dependency Properties

    public static readonly DependencyProperty ValidationTypeProperty = DependencyProperty.Register("ValidationType",
                                                                                          typeof(RequiredFieldRule.EnmValidationType),
                                                                                          typeof(ValidationParams),
                                                                                          new FrameworkPropertyMetadata(RequiredFieldRule.EnmValidationType.FieldNotEmpty));
    public static readonly DependencyProperty FieldNameProperty = DependencyProperty.Register("FieldName",
                                                                                         typeof(string),
                                                                                         typeof(ValidationParams),
                                                                                         new FrameworkPropertyMetadata(string.Empty));
    public string FieldName
    {
        get { return (string)GetValue(FieldNameProperty); }
        set { SetValue(FieldNameProperty, value); }
    }
    // Properties
    public string Message
    {
        get { return (string)GetValue(MessageProperty); }
        set { SetValue(MessageProperty, value); }
    }

    [Category("ValidationType")]
    public RequiredFieldRule.EnmValidationType ValidationType
    {
        get { return (RequiredFieldRule.EnmValidationType)GetValue(ValidationTypeProperty); }
        set { SetValue(ValidationTypeProperty, value); }

    }
}

CustomControl类

public class RequiredFieldBox : Control
{

    static RequiredFieldBox()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(RequiredFieldBox), new FrameworkPropertyMetadata(typeof(RequiredFieldBox)));
    }
    public static readonly DependencyProperty MsgProperty = DependencyProperty.Register(
     "Msg",
     typeof(string),
     typeof(RequiredFieldBox),
     new FrameworkPropertyMetadata(null)
   );
    public enum EnmValidationType
    {
        FieldNotEmpty,
        FieldNumeric,
        FieldIPAddress
    }
    public static readonly DependencyProperty TypeProperty = DependencyProperty.Register("Type",
                                                                                         typeof(RequiredFieldBox.EnmValidationType),
                                                                                         typeof(RequiredFieldBox),
                                                                                         new FrameworkPropertyMetadata(RequiredFieldBox.EnmValidationType.FieldNotEmpty));
    public EnmValidationType Type
    {
        get { return (EnmValidationType) GetValue(TypeProperty); }
        set { SetValue(TypeProperty, value);}
    }
    private static void MessageChanaged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        RequiredFieldBox sh = (RequiredFieldBox)d;
        if (sh.Msg != (string)e.OldValue)
            sh.Msg = (string)e.NewValue;
    }
    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
    "Text",                               //Property name
    typeof( object ),                           //Property type
    typeof( RequiredFieldBox ));

    public string Msg
    {
        get { return (string)GetValue(MsgProperty); }
        set { SetValue(MsgProperty, value); }
    }

    public object Text
    {
        get { return GetValue(TextProperty);}
        set { SetValue(TextProperty, value); }
    }
}

验证规则类

public class RequiredFieldRule:ValidationRule     {

    public enum EnmValidationType
    {
        FieldNotEmpty,
        FieldNumeric,
        FieldIPAddress
    }

    // Local variables and objects
    private ValidationParams mParams = new ValidationParams();

    public ValidationParams Params
    {
        get { return mParams; }
        set { mParams = value;}
    }

    // Override
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        ValidationResult objResult = null;
        string sValue = value as string;
        objResult = new ValidationResult(true, null);
        switch (Params.ValidationType)
        {
            case EnmValidationType.FieldNotEmpty:
                if (string.IsNullOrEmpty(sValue) == true)
                    return new ValidationResult(false, Params.Message);
                break;
            case EnmValidationType.FieldNumeric:
                int iValue = 0;
                if (int.TryParse(sValue, out iValue) == false)
                    objResult = new ValidationResult(false, Params.Message);
                break;
            case EnmValidationType.FieldIPAddress:
                break;
        }
        return objResult;
    }

}

1 个答案:

答案 0 :(得分:1)

在验证规则中没有上下文或树连接,因为模板绑定大致相当于RelativeSource绑定它不起作用。你可能运气不好......

通常唯一可行的是SourceStaticResourcex:Referencex:Static的组合,因为您无法通过名称来引用模板化的父级也许可以通过另一个控件进行隧道传输,例如类似的东西:

<TextBox x:Name="RequiredFieldBox"
         Tag="{Binding RelativeSource={RelativeSource TemplatedParent}}">
    <TextBox.Resources>
        <rule:RequiredFieldRule x:Key="rule">
            <rule:RequiredFieldRule.Params>
                <rule:ValidationParams 
                    Message="{Binding Tag.Msg, Source={x:Reference RequiredFieldBox}}"
                    ValidationType="{Binding Tag.Type, Source={x:Reference RequiredFieldBox}}"/>
            </rule:RequiredFieldRule.Params>
        </rule:RequiredFieldRule>
    </TextBox.Resources>
    <!-- ... --->
         <Binding.ValidationRules>
             <StaticResource ResourceKey="rule"/>
         </Binding.ValidationRules>

(如果保留ValidationRule,x:Reference很可能会抱怨周期性依赖)


使用StaticResource和隧道元素的替代方法:

<StackPanel Orientation="Vertical">
    <StackPanel.Resources>
        <FrameworkElement x:Key="Tunnel"
                Tag="{Binding RelativeSource={RelativeSource AncestorType=local:RequiredFieldBox}}" />
    </StackPanel.Resources>
    <StaticResource ResourceKey="Tunnel" />
    <TextBox x:Name="RequiredFieldBox">
        <TextBox.Text>
            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Text">
                <Binding.ValidationRules>
                    <rule:RequiredFieldRule>
                        <rule:RequiredFieldRule.Params>
                            <rule:ValidationParams
                                    Message="{Binding Tag.Msg, Source={StaticResource Tunnel}}"
                                    ValidationType="{Binding Tag.Type, Source={StaticResource Tunnel}}" />
                        </rule:RequiredFieldRule.Params>
                    </rule:RequiredFieldRule>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>