95 votes

Faire en sorte qu'une liaison WPF TextBox se déclenche à chaque nouveau caractère ?

Comment faire en sorte qu'une liaison de données se mette à jour dès qu'un nouveau caractère est tapé dans un TextBox ?

Je suis en train de me familiariser avec les liaisons dans WPF et je me retrouve bloqué sur une question (que j'espère) simple.

J'ai une classe FileLister simple où vous pouvez définir une propriété Path, et ensuite elle vous donnera une liste de fichiers lorsque vous accédez à la propriété FileNames. Voici cette classe :

class FileLister:INotifyPropertyChanged {
    private string _path = "";

    public string Path {
        get {
            return _path;
        }
        set {
            if (_path.Equals(value)) return;
            _path = value;
            OnPropertyChanged("Path");
            OnPropertyChanged("FileNames");
        }
    }

    public List<String> FileNames {
        get {
            return getListing(Path);
        }
    }

    private List<string> getListing(string path) {
        DirectoryInfo dir = new DirectoryInfo(path);
        List<string> result = new List<string>();
        if (!dir.Exists) return result;
        foreach (FileInfo fi in dir.GetFiles()) {
            result.Add(fi.Name);
        }
        return result;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string property) {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) {
            handler(this, new PropertyChangedEventArgs(property));
        }
    }
}

J'utilise le FileLister comme une StaticResource dans cette application très simple :

<Window x:Class="WpfTest4.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfTest4"
    Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:FileLister x:Key="fileLister" Path="d:\temp" />
    </Window.Resources>
    <Grid>
        <TextBox Text="{Binding Source={StaticResource fileLister}, Path=Path, Mode=TwoWay}"
        Height="25" Margin="12,12,12,0" VerticalAlignment="Top" />
        <ListBox Margin="12,43,12,12" Name="listBox1" ItemsSource="{Binding Source={StaticResource ResourceKey=fileLister}, Path=FileNames}"/>
    </Grid>
</Window>

La reliure fonctionne. Si je modifie la valeur de la zone de texte et que je clique en dehors de celle-ci, le contenu de la zone de liste sera mis à jour (tant que le chemin existe).

Le problème est que je voudrais mettre à jour dès qu'un nouveau caractère est tapé, et ne pas attendre que la zone de texte perde le focus.

Comment puis-je faire ça ? Y a-t-il un moyen de le faire directement dans le xaml, ou dois-je gérer les événements TextChanged ou TextInput sur la boîte ?

166voto

Dave Points 5649

Dans votre liaison de zone de texte, tout ce que vous avez à faire est de mettre UpdateSourceTrigger=PropertyChanged .

38voto

Eduardo Brites Points 1007

Vous devez définir le UpdateSourceTrigger à la propriété PropertyChanged

<TextBox Text="{Binding Source={StaticResource fileLister}, Path=Path, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
         Height="25" Margin="12,12,12,0" VerticalAlignment="Top"/>

-2voto

sg6336 Points 1

Sans C#, c'est suffisant en XAML pour TextBox, pas pour la classe. Donc, surveiller la propriété de TextBlock, où écrire la longueur de TextBox : Lier Texte.Longueur

<StackPanel>
  <TextBox x:Name="textbox_myText" Text="123" />
  <TextBlock x:Name="tblok_result" Text="{Binding Text.Length, ElementName=textbox_myText}"/>
</StackPanel>

-3voto

Erhy Points 96

Soudain, la liaison de données entre le curseur et la TextBox associée a posé des problèmes. J'ai enfin trouvé la raison et j'ai pu la réparer. Le convertisseur que j'utilise :

using System;
using System.Globalization;
using System.Windows.Data;
using System.Threading;

namespace SiderExampleVerticalV2
{
    internal class FixCulture
    {
        internal static System.Globalization.NumberFormatInfo currcult
                = Thread.CurrentThread.CurrentCulture.NumberFormat;

        internal static NumberFormatInfo nfi = new NumberFormatInfo()
        {
            /*because manual edit properties are not treated right*/
            NumberDecimalDigits = 1,
            NumberDecimalSeparator = currcult.NumberDecimalSeparator,
            NumberGroupSeparator = currcult.NumberGroupSeparator
        };
    }

    public class ToOneDecimalConverter : IValueConverter
    {
        public object Convert(object value,
            Type targetType, object parameter, CultureInfo culture)
        {
            double w = (double)value;
            double r = Math.Round(w, 1);
            string s = r.ToString("N", FixCulture.nfi);
            return (s as String);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            string s = (string)value;
            double w;
            try
            {
                w = System.Convert.ToDouble(s, FixCulture.currcult);
            }
            catch
            {
                return null;
            }
            return w;
        }
    }
}

En XAML

<Window.Resources>
    <local:ToOneDecimalConverter x:Key="ToOneDecimalConverter"/>
</Window.Resources>

à la suite de la TextBox définie

<TextBox x:Name="TextSlidVolume"
    Text="{Binding ElementName=SlidVolume, Path=Value,
        Converter={StaticResource ToOneDecimalConverter},Mode=TwoWay}"
/>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X