WPF验证装饰器 - 仅显示控件之前是否保持焦点

时间:2011-02-23 21:33:39

标签: .net wpf validation adorner

在我的WPF应用程序中,我想仅在用户编辑/输入/聚焦控件后显示验证装饰器。通过这种方式,用户有机会在该字段中提供有效输入,并且只有在他们选择不这样做时,才会显示验证。

我们希望鼓励每个字段完成,以便在表单首次打开时指示必填字段可以规避,因为用户将立即倾向于完成他们需要的东西以便摆脱大红色验证错误也可能绕过表格的流动。

有没有办法知道控件是否已经保持焦点?附加属性是否有效?

如果它有助于提供更具体的响应:这是我当前的验证样式,显示红色边框[如果控件有边框]和带有错误消息工具提示的小感叹号(非常标准):< / p>

<Style TargetType="Control">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="true">
            <Setter Property="ToolTip"
                    Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                    Path=(Validation.Errors).CurrentItem.ErrorContent}"/>

            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <DockPanel LastChildFill="true">
                            <Image Source="../Resources/Icons/Error.ico" Margin="4" Width="15" ToolTip="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}" />
                            <AdornedElementPlaceholder Name="customAdorner" VerticalAlignment="Center" >
                                <Border BorderBrush="red" BorderThickness="1" Visibility="{Binding ElementName=customAdorner, Path=AdornedElement.BorderThickness, Converter={StaticResource hasBorderToVisibilityConverter}}" />
                            </AdornedElementPlaceholder>
                        </DockPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Trigger>
        <Trigger Property="IsVisible" Value="False">
            <Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
        </Trigger>
    </Style.Triggers>
</Style>

1 个答案:

答案 0 :(得分:8)

您可以将附加行​​为与附加属性相结合来执行此操作。附加行为,ObserveFocus将订阅GotFocus事件,并在事件处理程序中将HasHeldFocus附加属性设置为True

它可用于在ViewModel中设置属性,如此

<Button local:HasHeldFocusBehavior.ObserveFocus="True"
        local:HasHeldFocusBehavior.HasHeldFocus="{Binding HasHeldFocus, 
                                                          Mode=OneWayToSource}"/>

以下是一个示例,说明如何将Background更改为Button一旦重点关注

<Style TargetType="Button">
    <Setter Property="Background" Value="Red"/>
    <Setter Property="local:HasHeldFocusBehavior.ObserveFocus" Value="True"/>
    <Style.Triggers>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},
                                       Path=(local:HasHeldFocusBehavior.HasHeldFocus)}"
                        Value="True">
            <Setter Property="Background" Value="Green"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

<强> HasHeldFocusBehavior

public static class HasHeldFocusBehavior
{
    public static readonly DependencyProperty ObserveFocusProperty =
        DependencyProperty.RegisterAttached("ObserveFocus",
                                            typeof(bool),
                                            typeof(HasHeldFocusBehavior),
                                            new UIPropertyMetadata(false, OnObserveFocusChanged));
    public static bool GetObserveFocus(DependencyObject obj)
    {
        return (bool)obj.GetValue(ObserveFocusProperty);
    }
    public static void SetObserveFocus(DependencyObject obj, bool value)
    {
        obj.SetValue(ObserveFocusProperty, value);
    }
    private static void OnObserveFocusChanged(DependencyObject dpo,
                                              DependencyPropertyChangedEventArgs e)
    {
        UIElement element = dpo as UIElement;
        element.Focus();
        if ((bool)e.NewValue == true)
        {
            SetHasHeldFocus(element, element.IsFocused);
            element.GotFocus += element_GotFocus;
        }
        else
        {
            element.GotFocus -= element_GotFocus;
        }
    }
    static void element_GotFocus(object sender, RoutedEventArgs e)
    {
        UIElement element = sender as UIElement;
        SetHasHeldFocus(element, true);
    }

    private static readonly DependencyProperty HasHeldFocusProperty =
        DependencyProperty.RegisterAttached("HasHeldFocus",
                                            typeof(bool),
                                            typeof(HasHeldFocusBehavior),
                                            new UIPropertyMetadata(false));
    public static void SetHasHeldFocus(DependencyObject element, bool value)
    {
        element.SetValue(HasHeldFocusProperty, value);
    }
    public static bool GetHasHeldFocus(DependencyObject element)
    {
        return (bool)element.GetValue(HasHeldFocusProperty);
    }
}

<强>更新

在您的情况下,您可以使用MultiTrigger替换Validation.HasError触发器

<Style TargetType="Control">
    <Style.Triggers>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding RelativeSource={RelativeSource Self},
                                             Path=(Validation.HasError)}"
                           Value="True"/>
                <Condition Binding="{Binding RelativeSource={RelativeSource Self},
                                             Path=(local:HasHeldFocusBehavior.HasHeldFocus)}"
                           Value="True"/>
            </MultiDataTrigger.Conditions>
            <!-- Setters.. -->
        </MultiDataTrigger>
        <!-- ... -->
    </Style.Triggers>
</Style>