WPF在运行时使用“ Validation.HasError”作为路径添加边距绑定

时间:2018-12-07 09:57:44

标签: c# wpf

我有以下XAML代码,表示带有验证的TextBox,当发生错误时,边距增加,因此消息不会与此TextBox下的其他UI元素重叠。 在XAML中,每个部分的工作方式都与我打算的一样。 验证是通过IDataErrorInfo接口

实现的
<TextBox 
    Grid.Column="1" 
    Validation.ErrorTemplate="{StaticResource validationErrorTemplate}"         
    Style="{StaticResource baseMargins}"
    Margin="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.HasError), Converter={StaticResource MarginConv}}" 
    Padding="{StaticResource basePadding}">
    <TextBox.Text>
        <Binding 
            Path="Email" 
            Mode="TwoWay" 
            UpdateSourceTrigger="PropertyChanged" 
            ValidatesOnDataErrors="True"/>
    </TextBox.Text>
</TextBox>

现在,我希望在运行时创建相同的内容。页面上有一个ItemsControl,我用生成的TextBoxes填充。

以下代码显示了我如何创建此TextBox

private static void CreateForStackOverflow()
{
    TextBox textBox = new TextBox();

    Binding textBinding = new Binding();
    textBinding.Path = new PropertyPath("Email");
    textBinding.Mode = BindingMode.TwoWay;
    textBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
    textBinding.ValidatesOnDataErrors = true;
    textBinding.NotifyOnValidationError = true;

    textBox.SetBinding(TextBox.TextProperty, textBinding);

    var valTemplate = (ControlTemplate)Application.Current.FindResource("validationErrorTemplate");
    Validation.SetErrorTemplate(textBox, valTemplate);

    Binding valBinding = new Binding();
    valBinding.RelativeSource = new RelativeSource(RelativeSourceMode.Self);
    valBinding.Path = new PropertyPath("Validation.HasError");
    valBinding.Converter = new Converters.BoolMarginConverter();

    textBox.SetBinding(FrameworkElement.MarginProperty, valBinding);
}

现在验证有效,将创建错误,但是唯一不起作用的是MarginProperty的绑定。这是永远不会触发的。

“输出”窗口中显示以下错误:

BindingExpression path error: 'Validation' property not found on 'object' ''TextBox' (Name='')'. BindingExpression:Path=Validation.HasError; 
DataItem='TextBox' (Name=''); 
target element is 'TextBox' (Name=''); 
target property is 'Margin' (type 'Thickness')

我发现它可能与我的`DataContext]有关,但是它是在XAML中设置的,并且设置Context是所有这些人的解决方案,而不是我的解决方案。

使用窥探(2.10.0.0),我可以看到TextBox具有Validation属性。

Snoop Validation Property

以下是Snoop在Margin属性上显示的内容。 Snoop Margin Property

这是重叠错误的样子。 Overlapping errors

BoolMarginConverter的代码如下:

public class BoolMarginConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool hasError = (bool)value;
        return hasError ? new Thickness(2, 2, 2, 20) : new Thickness(2, 2, 2, 2);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

但这从未执行过,因为找不到Validation.HasError

我在这里想念什么?

谢谢。

编辑:错误模板

<ControlTemplate x:Key="validationErrorTemplate">
    <DockPanel>
        <StackPanel 
            Orientation="Horizontal" DockPanel.
            Dock="Bottom" 
            ClipToBounds="True">
            <Grid
                Width="12" 
                Height="12">
                <Ellipse 
                    Width="12" 
                    Height="12" 
                    Fill="Red" 
                    HorizontalAlignment="Center"    
                    VerticalAlignment="Center"/>
                <TextBlock 
                    Foreground="White" 
                    FontWeight="Heavy" 
                    FontSize="8" 
                    HorizontalAlignment="Center"     
                    VerticalAlignment="Center" 
                    TextAlignment="Center"
                    Text="X"
                    ToolTip="{Binding ElementName=ErrorAdorner, UpdateSourceTrigger=PropertyChanged,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"  />
            </Grid>
            <TextBlock 
                Foreground="Red" 
                FontWeight="Bold" 
                TextWrapping="NoWrap" 
                TextTrimming="WordEllipsis"
                Margin="2,0,0,0"
                Text="{Binding ElementName=ErrorAdorner, Path=AdornedElement.(Validation.Errors),           Converter=converters:ValidationErrorsToStringConverter}}" 
                />
        </StackPanel>
        <AdornedElementPlaceholder x:Name="ErrorAdorner"/>
    </DockPanel>
</ControlTemplate>

2 个答案:

答案 0 :(得分:1)

我错过了(Validation.HasError)上的括号...

Validation.HasError ==> (Validation.HasError)

valBinding.Path = new PropertyPath("(Validation.HasError)");

也许有一天这会帮助某人。

谢谢

答案 1 :(得分:0)

我不会使用代码来完成所有这些工作,即使那样,您似乎还有些复杂。 以下标记对我有效。 我在代码的后面有一个公共Int属性,只需输入一个字符即可进行测试。

很显然,如果您想通过代码应用此样式,请在样式上放置一个x:Key,然后可以获取它的资源并应用它。我的适用于所有文本框。我真的不明白为什么你不希望那样。

我还建议像这样移动ui是有限制的。我希望边框和轮廓的颜色发生变化,并在工具提示中查看所有错误。您只能以这种方式适合一个人。

    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    >
<Window.Resources>
    <Style TargetType="{x:Type TextBox}">
        <Setter Property="Validation.ErrorTemplate">
            <Setter.Value>
                <ControlTemplate>
                    <DockPanel>
                        <StackPanel 
        Orientation="Horizontal" DockPanel.Dock="Bottom" 
        ClipToBounds="True">
                            <Grid
            Width="12" 
            Height="12">
                                <Ellipse 
                Width="12" 
                Height="12" 
                Fill="Red" 
                HorizontalAlignment="Center"    
                VerticalAlignment="Center"/>
                                <TextBlock 
                Foreground="White" 
                FontWeight="Heavy" 
                FontSize="8" 
                HorizontalAlignment="Center"     
                VerticalAlignment="Center" 
                TextAlignment="Center"
                Text="X"
                ToolTip="{Binding ElementName=ErrorAdorner, UpdateSourceTrigger=PropertyChanged,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"  />
                            </Grid>
                            <TextBlock 
            Foreground="Red" 
            FontWeight="Bold" 
            TextWrapping="NoWrap" 
            TextTrimming="WordEllipsis"
            Margin="2,0,0,0"
            Text="{Binding ElementName=ErrorAdorner, Path=AdornedElement.(Validation.Errors)/ErrorContent}" 
            />
                        </StackPanel>
                        <AdornedElementPlaceholder x:Name="ErrorAdorner"/>
                    </DockPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
                <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)/ErrorContent}"/>
                <Setter Property="Margin" Value="0,0,0,20"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Grid>
    <StackPanel>
        <TextBox Text="{Binding MyNum, UpdateSourceTrigger=PropertyChanged}"/>
        <TextBlock Text="Banana"/>
        <Button Content="Some Button"/>
    </StackPanel>
</Grid>