web-dev-qa-db-fra.com

Pourquoi WPF Style affiche-t-il des erreurs de validation dans les info-bulles mais fonctionne pour une zone de texte mais échoue pour une zone de liste déroulante?

J'utilise un style typique pour afficher les erreurs de validation sous forme d'infobulle de IErrorDataInfo pour une zone de texte, comme illustré ci-dessous, et tout fonctionne correctement.

    <Style TargetType="{x:Type TextBox}">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
                <Setter Property="ToolTip"
                Value="{Binding RelativeSource={RelativeSource Self},
            Path=(Validation.Errors)[0].ErrorContent}"/>
            </Trigger>
        </Style.Triggers>
    </Style>

Mais quand j'essaie de faire la même chose pour un ComboBox comme celui-ci, il échoue

    <Style TargetType="{x:Type ComboBox}">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
                <Setter Property="ToolTip"
                Value="{Binding RelativeSource={RelativeSource Self},
            Path=(Validation.Errors)[0].ErrorContent}"/>
            </Trigger>
        </Style.Triggers>
    </Style>

L'erreur que je reçois dans la fenêtre de sortie est:

System.Windows.Data Erreur: 17: Impossible d'obtenir la valeur 'Item []' (type 'ValidationError') à partir de '(Validation.Errors)' (type 'ReadOnlyObservableCollection`1'). BindingExpression: Path = (0) [0] .ErrorContent; DataItem = 'ComboBox' (Name = 'ownerComboBox'); l'élément cible est 'ComboBox' (Name = 'ownerComboBox'); propriété cible est 'ToolTip' (type 'Object') ArgumentOutOfRangeException: 'System.ArgumentOutOfRangeException: l'argument spécifié était en dehors de la plage de valeurs valides. Nom du paramètre: index'

Bizarrement, il tente également d’apporter des modifications de base de données non valides lorsque je ferme la fenêtre si je modifie une valeur de ComboBox (c’est aussi le moment où l’erreur de liaison se produit) !!!

Impossible d'insérer la valeur NULL dans la colonne 'EmpFirstName', table 'OITaskManager.dbo.Employees'; La colonne n'autorise pas les valeurs NULL. INSERT échoue. La déclaration a été terminée.

Simplement en commentant le style, tout fonctionne parfaitement. Comment puis-je réparer ça?

Juste au cas où quelqu'un en aurait besoin, l'un des xaml de la comboBox 'suit:

<ComboBox ItemsSource="{Binding Path=Employees}" 
                  SelectedValuePath="EmpID"                       
                  SelectedValue="{Binding Path=SelectedIssue.Employee2.EmpID,
                     Mode=OneWay, ValidatesOnDataErrors=True}" 
                  ItemTemplate="{StaticResource LastNameFirstComboBoxTemplate}"
                  Height="28" Name="ownerComboBox" Width="120" Margin="2" 
                  SelectionChanged="ownerComboBox_SelectionChanged" />


<DataTemplate x:Key="LastNameFirstComboBoxTemplate">
    <TextBlock> 
         <TextBlock.Text> 
             <MultiBinding StringFormat="{}{1}, {0}" > 
                   <Binding Path="EmpFirstName" /> 
                   <Binding Path="EmpLastName" /> 
             </MultiBinding>
         </TextBlock.Text>
    </TextBlock>
</DataTemplate>

SelectionChanged: (je prévois d’implémenter le commandement, mais comme il s’agit de mon premier projet WPF, je n’ai pas encore atteint le MVVM complet. J'essaie de prendre les choses par petites et moyennes entreprises.)

// This is done this way to maintain the DataContext Integrity 
// and avoid an error due to an Object being "Not New" in Linq-to-SQL
private void ownerComboBox_SelectionChanged(object sender, 
                                            SelectionChangedEventArgs e)
{
    Employee currentEmpl = ownerComboBox.SelectedItem as Employee;
    if (currentEmpl != null && 
        currentEmpl != statusBoardViewModel.SelectedIssue.Employee2)
    {
        statusBoardViewModel.SelectedIssue.Employee2 = currentEmpl;
    }
}
35
Mike B

Vous obtenez cette erreur parce que lorsque la validation constate qu'il n'y a pas de problèmes, la collection Errors est renvoyée sans éléments et la logique de liaison suivante échoue:

Path=(Validation.Errors)[0].ErrorContent}"

vous accédez à la collection de validation par un index spécifique. Je travaille actuellement sur une suggestion DataTemplate pour remplacer ce texte.

J'adore le fait que Microsoft ait répertorié cette option dans son exemple standard de modèle de validation.

update so remplace le code ci-dessus par le texte suivant et la logique de liaison saura comment gérer la collection vide validationresult:

Path=(Validation.Errors).CurrentItem.ErrorContent}"

(xaml suivant a été ajouté en tant que commentaire)

<ControlTemplate x:Key="ValidationErrorTemplate" TargetType="Control">
    <StackPanel Orientation="Horizontal">
        <TextBlock Foreground="Red" FontSize="24" Text="*" 
                   ToolTip="{Binding .CurrentItem}">
        </TextBlock>
        <AdornedElementPlaceholder>
        </AdornedElementPlaceholder>
    </StackPanel>
</ControlTemplate>
101
Nathan Tregillus

Je pense que c'est la meilleure façon:

Path=(Validation.Errors)/ErrorContent

/ est en fait égal à CurrentItem par @Nathan

Dans mon cas, CurrentItem est un non-lieu.

6
Altiano Gerung

Essayez le convertisseur pour convertir en une chaîne multiligne comme décrit ici

2
djamwal

Dans mon cas, je recevais cette exception lorsque j'ai essayé d'appliquer la solution @Nation Tregillus ':

Impossible de résoudre la propriété 'CurrentItem' dans le contexte de données de type 'System.Collections.ObjectModel.ReadOnlyObservableCollection'

Je suis donc allé avec la solution de -Altiano Gerung , où mon code a fini par être:

<ControlTemplate x:Key="ValidationErrorTemplate">
    <DockPanel Margin="5,0,36,0">
        <StackPanel Orientation="Horizontal" VerticalAlignment="Top" DockPanel.Dock="Right"
                    Margin="5,0,36,0"
                    ToolTip="{Binding ElementName=ErrorAdorner, Path=AdornedElement.(Validation.Errors)/ErrorContent}"
                    ToolTipService.ShowDuration="300000"
                    ToolTipService.InitialShowDelay="0"
                    ToolTipService.BetweenShowDelay="0"
                    ToolTipService.VerticalOffset="-75"
                    >
1
user8128167

J'ai vu le code que vous utilisez posté à plusieurs endroits, mais il me semble étrange que 

Path=(Validation.Errors)[0].ErrorContent}

ne soulève pas de drapeaux rouges. Mais je suis également nouveau dans WPF et il existe peut-être un secret pour que cela fonctionne dans tous les cas. 

Plutôt que d'essayer d'indexer une collection éventuellement vide avec un index de tableau, ajoutez un convertisseur qui renvoie la première erreur de la liste.

1
David

CurrentItem n'a pas fonctionné pour moi non plus Mais @ La réponse de Nathtan a fonctionné dans mon cas où j'ai une ressource textBox personnalisée. Merci @Nathan j'ai passé une heure à ce sujet.

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