2011-07-11 1 views
3

Mon but est de faire ceci: L'utilisateur sélectionne le fichier de paramètres, les paramètres sont lus et l'interface utilisateur est mise à jour en conséquence. L'épargne devrait également être possible évidemment.Comment mettre à jour WPF UI à la désérialisation de l'objet "settings"

Mon programme n'est actuellement pas WPF/XAML et faire ceci maintenant signifierait beaucoup de répétition et de travail supplémentaire quand de nouveaux réglages sont requis. Alors quelqu'un m'a dit que WPF/XAML était le chemin à parcourir, je l'ai regardé et j'ai aimé, mais je ne sais toujours pas comment faire ce que je veux. L'avantage de WPF/XAML est bien sûr les liaisons de données, mais si je veux lire un fichier de paramètres complet, je remplacerai probablement l'ancien objet settings par un nouveau. Puis-je faire réagir un programme WPF et mettre à jour des champs en fonction de certaines liaisons de données?

Je m'intéresse surtout à savoir si c'est un bon design et si ce n'est pas le cas.

+0

les liaisons de données existaient bien avant wpf/xaml - * Personnellement * J'aurais besoin de plus de raisons que les "paramètres" pour se déplacer entre les piles ... –

Répondre

2

Bien sûr que vous le pouvez. Tout d'abord, votre objet settings doit implémenter l'interface INotifyPropertyChanged. Cela ajoute essentiellement un événement, appelé chaque fois que vous appelez un accesseur de propriété. Ainsi, la liaison aux propriétés de non dépendance fonctionne dans les deux sens. Vous n'avez pas vraiment besoin de cette interface. Mais si vous voulez que vos changements après le premier ensemble (où toutes les propriétés sont lues) soient reflétés dans l'interface utilisateur, vous avez besoin de cette interface.

i utilisent généralement une classe de base pour cette

public class PropertyChangedNotifier : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged 
    { 
     add { mPropertyChanged += value; } 
     remove { mPropertyChanged -= value; } 
    } 

    protected virtual void RaisePropertyChanged(string aPropertyName) 
    { 
     PropertyChangedEventHandler handler = mPropertyChanged; 
     if (handler != null) 
     { 
      var e = new PropertyChangedEventArgs(aPropertyName); 
      handler(this, e); 
     } 
    } 

    private PropertyChangedEventHandler mPropertyChanged; 
} 

Vos paramètres doivent maintenant être dérivés de cette classe.

class MySettings : PropertyChangedNotifier 
{ 
public string UserName 
{ 
    get{return mUserName;} 
    set{mUserName=value; RaisePropertyChanged("UserName");} 
} 
} 

Maintenant, pour l'interface, DataBinding est toujours liée à l'ensemble DataContext.

<Window 
    x:Class="MyApp.MainWindow"> 

<StackPanel> 
    <TextBox Text="{Binding UserName}"/> 
</StackPanel> 

</Window> 

La zone de texte tente d'obtenir sa valeur à partir du setacontext défini actuellement à partir de la propriété "UserName". Maintenant, pour définir le DataContext, nous pourrions le faire dans le code mainwindow derrière.

public MainWindow() 
{ 
    InitializeComponent(); 
    DataContext = ReadMyUserSettings(); 
} 

Si vous modifiez votre Datacontext à tout moment, l'interface utilisateur se met automatiquement à jour. Et vos modifications dans la zone de texte seront réécrites dans vos paramètres. Cela peut également être amélioré en ajoutant une sorte d'annulation et enregistrer le flux de travail, de sorte que les paramètres ne sont pas modifiés si l'utilisateur clique sur annuler. Voir IEditableObject et BindingGroup pour cela.

Espérons que cela vous donne une idée approximative, comment cela fonctionne.

0

Voici comment je le ferais, en utilisant un exemple très simple dans un pseudocode semblable à C# en utilisant le modèle MVVM. D'abord, je définirais mes modèles, qui définissent ma configuration et sont sérialisés/désérialisés. Je préfère faire cela en utilisant le NetDataContractSerializer.

[DataContract] 
public sealed class Person 
{ 
    [DataMember] 
    public string Name {get;set;} 
    [DataMember] 
    public int Age {get;set;} 
} 

Mon ViewModel aurait une propriété publique qui détient l'instance actuelle de cette configuration

public sealed class ViewModel : DependencyObject 
{ 
    #region Person 
    /// <summary> 
    /// The <see cref="DependencyProperty"/> for <see cref="Person"/>. 
    /// </summary> 
    public static readonly DependencyProperty TextProperty = 
     DependencyProperty.Register(
      PersonPropertyName, 
      typeof(Person), 
      typeof(ViewModel), 
      new UIPropertyMetadata(null)); 

    /// <summary> 
    /// The name of the <see cref="Person"/> <see cref="DependencyProperty"/>. 
    /// </summary> 
    public const string PersonPropertyName = "Person"; 

    /// <summary> 
    /// The Person 
    /// </summary> 
    public string Person 
    { 
     get { return (Person)GetValue(PersonProperty); } 
     set { SetValue(PersonProperty , value); } 
    } 
    #endregion  

    // snip 

Dans mon ViewModel j'aurais aussi un ICommand pour le chargement et sauvegarde de la configuration.Il y a beaucoup de questions ici sur l'implémentation commune d'un ICommand qui délègue l'exécution de CanExecute et Execute au ViewModel.

Dans votre interface utilisateur, il vous suffit de lier les propriétés publiques de votre modèle de configuration via le ViewModel.

<Window x:Class="Herp.DerpWindow" SnipXamlForBrevity="true"> 
    <Window.DataContext> 
    <ViewModel xmlns="clr-namespace:Herp" /> 
    </Window.DataContext> 
    <!-- and later... --> 
    <Label>The Person in Question:</Label> 
    <TextBlock Text="{Binding Person.Name}" /> 
    <Label>Age</Label> 
    <TextBlock Text="{Binding Person.Age}" /> 

Parce que le modèle de configuration est maintenue dans une DependencyProperty publique du ViewModel, comme vous le remplacer l'interface utilisateur est automatiquement mis à jour avec les nouvelles valeurs. Vous pouvez, bien sûr, utiliser INotifyPropertyChanged comme méthode alternative pour notifier l'interface utilisateur des mises à jour de liaison, mais je préfère la garder simple.

Questions connexes