Eine WPF-TextBox-Bindung für jeden neuen Charakter auslösen?

83

Wie kann ich eine Datenbindungsaktualisierung durchführen, sobald ein neues Zeichen in eine Textbox eingegeben wird?

Ich lerne etwas über Bindungen in WPF und bin jetzt in einer (hoffentlich) einfachen Sache festgefahren.

Ich habe eine einfache FileLister-Klasse, in der Sie eine Path-Eigenschaft festlegen können. Anschließend erhalten Sie eine Liste der Dateien, wenn Sie auf die FileNames-Eigenschaft zugreifen. Hier ist diese Klasse:

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));
        }
    }
}

Ich verwende den FileLister als StaticResource in dieser sehr einfachen App:

<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>

Die Bindung funktioniert. Wenn ich den Wert im Textfeld ändere und dann außerhalb klicke, wird der Inhalt des Listenfelds aktualisiert (solange der Pfad vorhanden ist).

Das Problem ist, dass ich aktualisieren möchte, sobald ein neues Zeichen eingegeben wird, und nicht warten möchte, bis das Textfeld den Fokus verliert.

Wie kann ich das machen? Gibt es eine Möglichkeit, dies direkt in der xaml zu tun, oder muss ich TextChanged- oder TextInput-Ereignisse auf der Box verarbeiten?

luddet
quelle

Antworten:

142

In Ihrer Textfeldbindung müssen Sie lediglich festlegen UpdateSourceTrigger=PropertyChanged.

Dave
quelle
1
Vielen Dank! Genau so einfache Lösung, wie ich es mir erhofft hatte :)
Luddet
Bei mir hat es nicht funktioniert ... Ich möchte den Text auf den vorherigen Wert zurücksetzen, falls es sich nicht um eine Zahl handelt. Nur wenn IsAsync = True hinzugefügt wurde, hat es funktioniert.
Ilans
Ich habe versucht, dies im Visual Studio-Designer (VS2015) festzulegen. Im Bindungsdialog wird die Option angezeigt, wenn ich den Expander "Weitere Einstellungen" erweitere. Der UpdateSourceTrigger ist jedoch deaktiviert, es sei denn, ich habe auch die BindingDirection auf etwas anderes als Standard festgelegt.
Martin Brown
32

Sie müssen die UpdateSourceTriggerEigenschaft auf setzenPropertyChanged

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

Ohne C # reicht es in XAML für TextBox, nicht für die Klasse. Überwachen Sie also die Eigenschaft von TextBlock, wobei die Schreiblänge von TextBox: Binding Text.Length

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

Plötzlich machte die Datenbindung zwischen dem Schieberegler und der zugehörigen TextBox Probleme. Endlich fand ich den Grund und konnte ihn beheben. Der Konverter, den ich benutze:

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;
        }
    }
}

In XAML

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

weiter die definierte TextBox

<TextBox x:Name="TextSlidVolume"
    Text="{Binding ElementName=SlidVolume, Path=Value,
        Converter={StaticResource ToOneDecimalConverter},Mode=TwoWay}"
/>
Erhy
quelle
2
Ich denke, Sie haben Ihre Antwort in der falschen Frage gepostet. Die ursprüngliche Frage enthält keine Informationen zu einem Schieberegler.
GrantByrne