更改内容后不会触发WPF文本框验证

时间:2019-04-08 15:48:13

标签: c# wpf validation textbox

我正在尝试在同时使用Textboxes和DataGrid的WPF应用程序中验证Textbox。

验证在加载时触发-显示文本框为空。但是,当我实际上在文本框中输入内容然后移到另一个时,它仍然显示为无效-验证不会再次触发。

数据网格和文本框都使用数据绑定,以便从数据库加载和写入数据。

我根据本教程https://docs.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-implement-binding-validation创建了一个验证规则。

大多数情况下,此解决方案对我有用-当我首先在datagrid中选择一行,然后开始更改文本框的内容时-验证有效。 但是,如前所述-当应用启动且未选择任何内容(且文本框为空)时,它无法正常工作。

XAML 文件的以下片段:

<Window.Resources>
    <CollectionViewSource x:Key="printLogViewSource" d:DesignSource="{d:DesignInstance {x:Type local:PrintLog}, CreateList=True}" >
        <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="Name"/>
        </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>
    <ControlTemplate x:Key="validationTemplate">
        <DockPanel>
            <TextBlock Foreground="Red" FontSize="20">!</TextBlock>
            <AdornedElementPlaceholder/>
        </DockPanel>
    </ControlTemplate>
</Window.Resources>
<Grid Background="#FFE5E5E5" Width="Auto"  DataContext="{StaticResource printLogViewSource}">
    <GroupBox x:Name="groupBox" Header="Add/Update/Remove" Margin="10,573,10,15">
        <Grid Margin="0,0,0,0">
            <Grid x:Name="grid1" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Label Content="Name:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="0" VerticalAlignment="Center"/>
                <TextBox x:Name="nameTextBox" Validation.ErrorTemplate="{StaticResource validationTemplate}"  Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="0" VerticalAlignment="Center" Width="120" AutomationProperties.IsRequiredForForm="True">
                    <TextBox.Text>
                        <Binding Path="Name"
                                 Mode="TwoWay"
                                 UpdateSourceTrigger="PropertyChanged">
                            <Binding.ValidationRules>
                                <local:ValRule ValidatesOnTargetUpdated="True"/>
                            </Binding.ValidationRules>
                        </Binding>
                    </TextBox.Text>
                </TextBox>
            </Grid>
            <Grid x:Name="grid2" HorizontalAlignment="Left" Margin="191,10,0,0" VerticalAlignment="Top">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Label Content="Person:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="0" VerticalAlignment="Center"/>
                <TextBox x:Name="personTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="0" Text="{Binding Person, Mode=OneWay, NotifyOnValidationError=true, ValidatesOnExceptions=true, UpdateSourceTrigger=Explicit}" VerticalAlignment="Center" Width="120"/>
            </Grid>
        </Grid>
    </GroupBox>
    <DataGrid x:Name="printLogDataGrid" AutoGenerateColumns="False" IsReadOnly="True" EnableRowVirtualization="True" ItemsSource="{Binding Source={StaticResource printLogViewSource}, UpdateSourceTrigger=PropertyChanged}" Margin="10,10,10,141" RowDetailsVisibilityMode="VisibleWhenSelected" CanUserAddRows="False">
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="printIDColumn" Binding="{Binding PrintID}" Header="Print ID" Width="Auto" IsReadOnly="True"/>
        <DataGridTextColumn x:Name="nameColumn" Binding="{Binding Name}" Header="Name" Width="Auto"/>
        <DataGridTextColumn x:Name="personColumn" Binding="{Binding Person}" Header="Person" Width="Auto"/>
    </DataGrid.Columns>
    <DataGrid.GroupStyle>
        <GroupStyle>
            <GroupStyle.HeaderTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <DataGridCell Content="{Binding Name}"/>
                    </StackPanel>
                </DataTemplate>
            </GroupStyle.HeaderTemplate>
        </GroupStyle>
    </DataGrid.GroupStyle>
</DataGrid>
</Grid>

这是我的 ValidationRule

class ValRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        if ((string)value == "")
        {
            return new ValidationResult(false, "Field cannot be empty");
        }
        else
        {
            return ValidationResult.ValidResult;
        }
    }
}

这是我的 MainWindow.xaml.cs 的片段:

public partial class MainWindow : Window
{
    private printDBEntities _context = new printDBEntities();

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {

        _context.PrintLogs.Load();


        System.Windows.Data.CollectionViewSource printLogViewSource = ((System.Windows.Data.CollectionViewSource)(this.FindResource("printLogViewSource")));
        printLogViewSource.Source = _context.PrintLogs.Local;

        printLogDataGrid.SelectedIndex = -1;
        //I'm setting this value to -1 so that on load my TextBoxes are empty. 
        //If i don't add this, on load my textboxes have value corrseponding to first row of datagrid.
    }

    protected override void OnClosing(CancelEventArgs e)
    {
        base.OnClosing(e);
        this._context.Dispose();
    }
    //Below normally are functions responsible for Add/Update/Remove buttons
}

在加载窗口时,行printLogDataGrid.SelectedIndex = -1;是否部分负责此问题? 如代码中所提到的-如果我跳过此步骤,则在开始时选择datagrid的第一行,这意味着文本框也将在开始时填充数据-这意味着用户必须从每个框中删除文本才能添加新的记录。

编辑

为弄清这种情况-不能正常工作的文本框是nameTextBox-目前唯一经过验证的文本框。

1 个答案:

答案 0 :(得分:0)

<TextBox x:Name="nameTextBox" Validation.ErrorTemplate="{StaticResource validationTemplate}"  Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="0" VerticalAlignment="Center" Width="120" AutomationProperties.IsRequiredForForm="True">
    <TextBox.Text>
        <Binding Path="Name"
                 Mode="TwoWay"
                 UpdateSourceTrigger="PropertyChanged"
                 NotifyOnValidationError="True"
                 ValidatesOnNotifyDataErrors="True">
            <Binding.ValidationRules>
                <local:ValRule ValidatesOnTargetUpdated="True"/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

NotifyOnValidationError和ValidatesOnNotifyDataErrors应该这样做。