2010-06-16 2 views
6

Je veux savoir quel caractère est supprimé par l'utilisateur à l'aide de la touche Suppr ou BackSpace.Comment faire pour savoir quel caractère est supprimé dans TextBox dans WPF?

Je gère TextBox_ChangedEvent de textbox.

Puis-je extraire le caractère supprimé de TextChangedEventArgse.Changes et si oui, comment puis-je faire?

Je souhaite empêcher l'utilisateur de supprimer des caractères du TextBox. Je veux que l'utilisateur puisse supprimer seulement deux caractères (disons "(" ou ")")

Veuillez nous suggérer.

Répondre

9

Ci-dessous vous trouverez le code pour une propriété jointe qui peut être utilisée comme ceci pour empêcher tout sauf "(" ou ")" d'être supprimé du TextBox, point.

<TextBox my:TextBoxRestriction.RestrictDeleteTo="()" ... /> 

Cela gérer correctement toutes les mises à jour de la souris et du clavier, tels que:

  1. Utilisation de la touche Suppr avec plusieurs caractères sélectionnés
  2. Utilisation de la touche Retour arrière
  3. Utilisation de Ctrl- X pour couper
  4. En cliquant sur le bouton "Couper" de votre barre de menu

Pour cette raison, il est beaucoup plus puissant que d'intercepter simplement PreviewKeyDown.

Ceci empêche également la suppression de tout BYT « (» ou «) » en attribuant directement à la propriété .Text, donc cela échouera:

textBox.Text = "Good morning"; 

En raison de cette classe TextBoxRestriction contient également une autre propriété attachée appelé UnrestrictedText qui, lorsqu'il est défini, peut mettre à jour la propriété Text en ignorant les restrictions.Cela peut être définie dans le code à l'aide TextBoxRestriction.SetUnrestrictedText ou liée aux données comme ceci: Dans la mise en œuvre ci-dessous, UnrestrictedText ne fonctionne que

<TextBox my:TextBoxRestriction.RestrictDeleteTo="()" 
     my:TextBoxRestriction.UnrestrictedText="{Binding PropertyNameHere}" /> 

lorsque RestrictDeleteTo est également définie. Une implémentation complète peut être effectuée qui enregistre le gestionnaire d'événements chaque fois que la propriété est définie et enregistre le gestionnaire dans une troisième propriété jointe pour un désenregistrement ultérieur. Mais pour vos besoins actuels, c'est probablement inutile.

Voici la mise en œuvre comme promis:

public class TextBoxRestriction : DependencyObject 
{ 
    // RestrictDeleteTo: Set this to the characters that may be deleted 
    public static string GetRestrictDeleteTo(DependencyObject obj) { return (string)obj.GetValue(RestrictDeleteToProperty); } 
    public static void SetRestrictDeleteTo(DependencyObject obj, string value) { obj.SetValue(RestrictDeleteToProperty, value); } 
    public static readonly DependencyProperty RestrictDeleteToProperty = DependencyProperty.RegisterAttached("RestrictDeleteTo", typeof(string), typeof(TextBoxRestriction), new PropertyMetadata 
    { 
    PropertyChangedCallback = (obj, e) => 
     { 
     var box = (TextBox)obj; 
     box.TextChanged += (obj2, changeEvent) => 
      { 
      var oldText = GetUnrestrictedText(box); 
      var allowedChars = GetRestrictDeleteTo(box); 
      if(box.Text==oldText || allowdChars==null) return; 

      foreach(var change in changeEvent.Changes) 
       if(change.RemovedLength>0) 
       { 
       string deleted = box.Text.Substring(change.Offset, change.RemovedLength); 
       if(deleted.Any(ch => !allowedChars.Contains(ch))) 
        box.Text = oldText; 
       } 
      SetUnrestrictedText(box, box.Text); 
      }; 
     } 
    }); 

    // UnrestrictedText: Bind or access this property to update the Text property bypassing all restrictions 
    public static string GetUnrestrictedText(DependencyObject obj) { return (string)obj.GetValue(UnrestrictedTextProperty); } 
    public static void SetUnrestrictedText(DependencyObject obj, string value) { obj.SetValue(UnrestrictedTextProperty, value); } 
    public static readonly DependencyProperty UnrestrictedTextProperty = DependencyProperty.RegisterAttached("UnrestrictedText", typeof(string), typeof(TextBoxRestriction), new PropertyMetadata 
    { 
    DefaultValue = "", 
    PropertyChangedCallback = (obj, e) => 
     { 
     var box = (TextBox)obj; 
     box.Text = (string)e.NewValue; 
     } 
    }); 

} 

Comment ça marche: Lorsque vous définissez UnrestrictedText il définit texte et vice versa. Le gestionnaire TextChanged vérifie si Text est différent de UnrestrictedText. Si tel est le cas, il sait que le texte a été mis à jour par un autre mécanisme que la définition de UnrestrictedText de sorte qu'il analyse les modifications pour une suppression illégale. Si l'un d'eux est trouvé, il rétablit Text à la valeur encore stockée dans UnrestrictedText, empêchant la modification.

+0

Aide énorme! Je l'ai légèrement modifié pour éviter la suppression du dernier caractère qu'un utilisateur tente de supprimer. – alan

0

Je ne connais pas WPF mais en supposant que c'est la même chose que WinForms pour cela (semble probable). La seule façon dont je sache est que vous gardez le texte actuel dans une variable et sur le texte, si ce n'est pas une suppression ou un retour arrière, vous mettez ce texte à jour, sinon vous pouvez comparer ce qui a changé.

Edit: En regardant TextChangedEventArgs.Changes il semble que la façon dont je décris ci-dessus pourrait encore être le chemin à parcourir, mais vous pourriez peut-être utiliser la Changes de comparer les textes plus efficacement.

Vous avez peut-être déjà pensé à cela, mais sinon, n'oubliez pas de gérer aussi couper et coller (et que l'utilisateur pourrait le faire avec la souris plutôt que le clavier).

1

Un comportement attaché à le manipuler

public static class TextInputBehaviour 
{ 
    public static bool GetIsDeleteRestricted(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(IsDeleteRestrictedProperty); 
    } 

    public static void SetIsDeleteRestricted(DependencyObject obj, bool value) 
    { 
     obj.SetValue(IsDeleteRestrictedProperty, value); 
    } 

    public static readonly DependencyProperty IsDeleteRestrictedProperty=DependencyProperty.RegisterAttached("IsDeleteRestricted", typeof(bool), typeof(TextInputBehaviour), new UIPropertyMetadata(false, OnIsDeleteRestrictedChanged)); 
} 

private static void OnIsDeleteRestrictedChanged(object sender, DependencyPropertyChangedEventArgs e) 
{  
    TextBox textBox = (TextBox)sender; 
    bool isDeleteRestricted = (bool)(e.NewValue); 

    if (isDeleteRestricted) 
    textBox.PreviewKeyDown += RestrictDeleteKey; 
    else 
    textBox.PreviewKeyDown -= RestrictDeleteKey; 
} 

private static void RestrictDeleteKey(object sender, KeyEventArgs e) 
{ 
     e.Handled = (e.Key == Key.Delete); 
} 

Baisse le comportement dans la section Ressources

Ensuite, dans votre bloc de balisage zone de texte, définissez le comportement

<TextBox local:TextInputBehaviour.IsDeleteRestricted="True" /> 
+0

@Ashish: Si vous avez une exception dans la suppression de caractères tels que '(' et ')', ajoutez ces conditions dans la méthode RestrictDeletedKey. – Amsakanna