Tworzenie powiązania WPF TextBox na każdym nowym znaku?


85

Jak mogę zaktualizować powiązanie danych, gdy tylko zostanie wpisany nowy znak w TextBox?

Uczę się o powiązaniach w WPF i teraz utknąłem w (miejmy nadzieję) prostej sprawie.

Mam prostą klasę FileLister, w której można ustawić właściwość Path, a następnie wyświetli listę plików, gdy uzyskasz dostęp do właściwości FileNames. Oto ta klasa:

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

Używam FileLister jako StaticResource w tej bardzo prostej aplikacji:

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

Wiązanie działa. Jeśli zmienię wartość w polu tekstowym, a następnie kliknę poza nim, zawartość pola listy zostanie zaktualizowana (o ile istnieje ścieżka).

Problem w tym, że chciałbym zaktualizować, gdy tylko zostanie wpisany nowy znak, a nie czekać, aż pole tekstowe straci fokus.

Jak mogę to zrobić? Czy istnieje sposób, aby to zrobić bezpośrednio w XAML, czy też muszę obsługiwać zdarzenia TextChanged lub TextInput w pudełku?

Odpowiedzi:


146

W oprawie Textbox wszystko, co musisz zrobić, to ustawić UpdateSourceTrigger=PropertyChanged.


1
Dzięki! Dokładnie takie proste rozwiązanie, na jakie
liczyłem

U mnie to nie zadziałało ... Chcę przywrócić tekst do poprzedniej wartości, na wypadek, gdyby nie była to liczba. Tylko po dodaniu IsAsync = True zadziałało.
ilans

Próbowałem ustawić to w projektancie Visual Studio (VS2015). W oknie dialogowym powiązania opcja jest wyświetlana, gdy rozwijam ekspander „Więcej ustawień”. Jednak UpdateSourceTrigger jest wyłączony, chyba że ustawię również BindingDirection na coś innego niż Default.
Martin Brown

32

Musisz ustawić UpdateSourceTriggerwłaściwość naPropertyChanged

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

-1

Bez C # wystarczy w języku XAML dla TextBox, a nie dla klasy. A więc monitorowanie właściwości TextBlock, gdzie zapisuje się długość 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>

-2

Nagle wiązanie danych między suwakiem a powiązanym TextBoxem spowodowało problemy. W końcu znalazłem przyczynę i mogłem to naprawić. Konwerter, którego używam:

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

W XAML

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

dalej zdefiniowany TextBox

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

2
Myślę, że umieściłeś swoją odpowiedź w złym pytaniu. Oryginalne pytanie nie zawiera żadnych informacji o suwaku.
GrantByrne
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.