2012-05-16 14 views
50

Jak mogę dokonać aktualizacji powiązania danych zaraz po wpisaniu nowego znaku w TextBox?

Uczę się o powiązaniach w WPF, a teraz utknąłem na (mam nadzieję) prostej rzeczy.Tworzenie powiązania TextBox WPF przy każdej nowej postaci?

Mam prostą klasę FileLister, w której można ustawić właściwość Path, a następnie wyświetli listę plików po uzyskaniu dostępu do właściwości FileNames. Tutaj jest to, że 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 ten 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 nią, zawartość listy będzie aktualizowana (o ile ścieżka istnieje).

Problem polega na tym, że chciałbym zaktualizować, gdy tylko zostanie wpisany nowy znak, i nie czekać, aż pole tekstowe straci ostrość.

Jak mogę to zrobić? Czy istnieje sposób, aby to zrobić bezpośrednio w Xaml, czy muszę obsługiwać zdarzenia TextChanged lub TextInput na polu?

Odpowiedz

84

W wiążący swoją tekstowe, wszystko co musisz zrobić, to ustawić UpdateSourceTrigger=PropertyChanged.

+1

Dzięki! Dokładnie tak proste rozwiązanie jak miałem nadzieję :) – luddet

+0

Dla mnie to nie działa ... Chcę przywrócić tekst do poprzedniej wartości, na wypadek, gdyby nie był liczbą. Dopiero po dodaniu IsAsync = True działało. – ilans

20

Musisz ustawić właściwość UpdateSourceTrigger do PropertyChanged

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

Nagle powiązanie danych między suwakiem i powiązanym TextBox spowodowało problemy. W końcu znalazłem przyczynę i mogłem to naprawić. Konwerter używać:

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}" 
/>