2010-10-07 13 views
4

J'ai ce que je pense être une question de liaison de données très simple (je suis encore nouveau à WPF). J'ai une classe (simplifiée pour cette question)WPF Databinding TextBox pour intégrer la propriété dans un autre objet

public class ConfigurationData 
{ 
    public int BaudRate { get; set; } 
} 

Dans MainWindow.Xaml.cs J'ai un membre privé:

private ConfigurationData m_data; 

et une méthode

void DoStuff() 
{ 
    // do a bunch of stuff (read serial port?) which may result in calling... 
    m_data.BaudRate = 300; // or some other value depending on logic 
} 

Dans mon MainWindow gui, je voudrais avoir un TextBox qui affiche m_data.BaudRate ET permet une liaison bidirectionnelle. L'utilisateur devrait pouvoir entrer une valeur dans la zone de texte, et la zone de texte devrait afficher les nouvelles valeurs que nous avons provoquées par la méthode "DoStuff()". J'ai vu des tonnes d'exemples sur la liaison à une autre propriété d'un contrôle sur MainWindow, et la liaison à une collection de données, mais pas d'exemples de liaison à une propriété d'un autre objet. Je pense que mon exemple est à peu près aussi simple que cela, avec l'ennui tenace que je lie à un entier, pas une chaîne, et si possible, je voudrais que l'utilisateur puisse uniquement entrer des nombres entiers.
BTW J'ai envisagé d'utiliser un numérique haut/bas, mais j'ai décidé de ne pas y recourir car il ne semblait pas y avoir beaucoup de support/exemples de commandes numériques haut-bas non commerciales. De plus, il pourrait être un très grand nombre de numéros à passer. Je pense qu'un pointeur vers un bon exemple me mettrait sur la bonne voie. Un grand merci à l'avance, Dave

+1

J'aurais dû dire que je pense qu'un pointeur vers un bon exemple me mettrait sur mon chemin. – Dave

+0

Cela ne fonctionne pas (erreur syntac) J'ai vu qu'on peut configurer une "ressource" dans le Xaml. Cela semble être exagéré pour moi. Je ne peux pas le faire en ligne? C'est seulement une fois que je vais lier à m_data. A part: Est-il possible de mettre en forme du code ou d'utiliser la touche de retour dans les commentaires :)? – Dave

+0

Je voulais juste noter qu'un contrôle numérique haut-bas (ou spinner) aide également à empêcher la saisie au clavier non-numérique et les validations min/max, pas seulement la rotation réelle des nombres. Je pense qu'il y en a un dans Bag of Tricks qui fait le travail décemment (il suffit de le styler correctement). –

Répondre

0

Je suis sûr qu'il ya une meilleure façon (s'il vous plaît me dire!), Mais voici une façon que je bricolé qui fonctionne. Il semble qu'il devrait y avoir un moyen plus facile. Pour l'utilisation BaudRate de la propriété:

public int BaudRate 
    { 
     get 
     { 
      return m_baudRate; 
     } 
     set 
     { 
      if (value != m_baudRate) 
      { 
       m_baudRate = value; 
       OnPropertyChanged("BaudRate");//OnPropertyChanged definition left out here, but it's pretty standard 
      } 
     } 
    } 

Pour le XAML, je n'ai pas de balisage significatif:

<TextBox Height="23" Margin="137,70,21,0" Name="textBox1" VerticalAlignment="Top" /> 

Maintenant, c'est la partie en désordre ... Créer une classe pour la validation:

public class IntRangeRule : ValidationRule 
{ 
    // See ValidationRule Class 
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) 
    { 
     try 
     { 
      if (value is int) // replace with your own logic or more robust handling... 
      { 
       return new ValidationResult(true, "Fine"); 
      } 
      else 
      { 
       return new ValidationResult(false, "Illegal characters or "); 
      } 
     } 

     catch (Exception e) 
     { 
      return new ValidationResult(false, "Illegal characters or " + e.Message); 
     } 


    } 
} 

Et puis dans le constructeur de Window1 (MainWindow), ont:

Binding myBinding = new Binding("BaudRate"); 
     myBinding.NotifyOnValidationError = true; 
     myBinding.Mode = BindingMode.TwoWay; 
     ValidationRule rule = new IntRangeRule(); 
        myBinding.ValidationRules.Add(rule); 
     myBinding.Source = m_data; // where m_data is the member variable of type ConfigurationData 
     textBox1.SetBinding(TextBox.TextProperty, myBinding); 

Toutes mes tentatives de tout faire dans le balisage ont échoué. De meilleures façons?

Dave

16

Bien que cette question est vieux, il est un bon, et est rarement répondu succinctement. Permettez-moi d'offrir une solution simplifiée pour les autres qui viennent sur cette page.

Afin de prendre en charge la liaison bidirectionnelle, votre classe initiale ConfigurationData doit être développée pour prendre en charge les modifications de propriété. Sinon, les modifications dans DoStuff() ne seront pas reflétées dans la zone de texte de l'interface utilisateur.Voici une façon typique de le faire:

using System.ComponentModel; 
public class ConfigurationData : INotifyPropertyChanged 
{ 
    private int _BaudRate; 
    public int BaudRate 
    { 
     get { return _BaudRate; } 
     set { _BaudRate = value; OnPropertyChanged("BaudRate"); } 
    } 

    //below is the boilerplate code supporting PropertyChanged events: 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected void OnPropertyChanged(string name) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 
} 

je choisis de mettre le textbox droit dans le XAML (je l'ai également ajouté un bouton pour DoStuff), comme suit:

<Canvas> 
    <TextBox Width="96" Name="textBox1" Text="{Binding BaudRate}" /> 
    <Button Width="96" Canvas.Top="25" Content="ChangeNumber" Click="DoStuff"/> 
</Canvas> 

Le partie difficile est de coller tout cela ensemble. Pour cela, vous devrez définir votre DataContext. Je préfère le faire dans le constructeur de ma fenêtre principale. Voici le code:

public partial class MainWindow : Window 
{ 
    private ConfigurationData m_data; 
    public MainWindow() 
    { 
     InitializeComponent(); 
     m_data = new ConfigurationData(); 
     this.DataContext = m_data; // This is the glue that connects the 
            // textbox to the object instance 
    } 

    private void DoStuff(object sender, RoutedEventArgs e) 
    { 
     m_data.BaudRate += 300; 
    } 
}