2010-01-17 4 views
4

Dans WPF, j'ai une collection de bool? valeurs et je veux lier chacun d'entre eux à une case à cocher séparée par programme. Je souhaite que les liaisons soient TwoWay afin que la modification de la valeur de l'élément individuel dans la collection dans le code mette à jour la case à cocher et vice versa.Lier un contrôle à une valeur unique dans une collection/tableau dans WPF

J'ai passé des heures à essayer de comprendre comment faire cela et je suis complètement coincé. Avec le code suivant, la case à cocher n'obtient la bonne valeur que lorsque la fenêtre est chargée et c'est tout. La modification de la case à cocher ne met même pas à jour la valeur dans la collection. (MISE À JOUR: cela semble être un bug dans .NET4 que la collection ne soit mis à jour dans un projet identique .NET3.5 MISE À JOUR:. Microsoft a confirmé le bug et qu'il sera corrigé dans la version .NET4.)

Merci beaucoup d'avance pour votre aide!

C#:

namespace MyNamespace 
{ 
    public partial class MyWindow : Window, INotifyPropertyChanged 
    { 
     public MyWindow() 
     { 
      InitializeComponent(); 
      DataContext = this; 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
     protected void OnPropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
      } 

     public List<bool?> myCollection = new List<bool?> 
      { true, false, true, false, true, false }; 

     public List<bool?> MyCollection 
     { 
      get { return myCollection; } 
      set { myCollection = value; } 
     } 
    } 
} 

XAML:

<CheckBox IsChecked="{Binding Path=MyCollection[0], Mode=TwoWay}"> 
+0

Je travaille toujours sur les 3 premières réponses, mais je suis déconcerté par la raison pour laquelle mon code semble fonctionner pour les deux premiers répondants (au moins dans la direction CheckBox -> MyCollection). Pour moi, cela ne se passe tout simplement pas. J'utilise VS2010 Beta 2 et .NET4 dans le cas où c'est pertinent. –

+0

Eh bien, je ne pensais certainement pas que cela serait pertinent: j'ai tout copié dans un projet .NET 3.5 et hop, le CheckBox met à jour la valeur dans MyCollection. Je me demande pourquoi cela ne fonctionne pas dans .NET 4? –

+0

Hmm, si vous avez un code comme celui-ci qui fonctionne dans .NET 3.5 mais le code identique ne fonctionne pas dans .NET 4, ce qui suggère un bug dans .NET 4. Cela pourrait valoir la peine de poster sur Connect. – itowlson

Répondre

5

Il y a quelques choses qui ont besoin de changer ici pour que cela fonctionne. Tout d'abord, vous devez placer votre valeur booléenne dans un objet qui implémente l'interface INotifyPropertyChanged afin d'obtenir la notification de modification que vous recherchez. Actuellement, vous liez les valeurs booléennes de votre collection qui n'implémentent pas l'interface. Pour ce faire, vous pouvez créer une classe wrapper comme ceci:

public class Wrapper: INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 
     protected void OnPropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 

     private bool val = false; 

     public bool Val 
     { 
      get { return val; } 
      set 
      { 
       val = value; 
       this.OnPropertyChanged("Val"); 
      } 
     } 

     public Wrapper(bool val) 
     { 
      this.val = val; 
     } 

    } 

Vous voulez ensuite créer ces objets dans votre formulaire au lieu d'une liste de booléens. Vous pouvez également utiliser une collection observable au lieu d'une liste afin que la notification des éléments ajoutés et supprimés soit envoyée.Ceci est illustré ci-dessous:

public Window1() 
    { 
     InitializeComponent(); 
     this.DataContext = this; 
    } 

    private ObservableCollection<Wrapper> myCollection = new ObservableCollection<Wrapper>() 
     {new Wrapper(true), new Wrapper(false), new Wrapper(true)}; 


    public ObservableCollection<Wrapper> MyCollection 
    { 
     get { return myCollection; } 
    } 

La prochaine chose à faire est d'afficher une liste de cases à cocher dans votre interface utilisateur. Pour ce faire, WPF fournit des contrôles d'éléments. ListBox est un itemscontrol donc nous pouvons l'utiliser comme point de départ. Définissez la source d'éléments d'une zone de liste à MyCollection. Nous devons ensuite définir comment chaque objet Wrapper va être affiché dans la zone de liste et cela peut être fait avec un datatemplate qui est créé dans les ressources de Windows. Ceci est illustré ci-dessous:

<Window.Resources> 
    <DataTemplate x:Key="myCollectionItems"> 
     <CheckBox IsChecked="{Binding Path=Val, Mode=TwoWay}"></CheckBox> 
    </DataTemplate> 
</Window.Resources> 
<Grid> 
    <ListBox ItemsSource="{Binding Path=MyCollection}" ItemTemplate="{StaticResource myCollectionItems}"></ListBox> 
</Grid> 

Cela devrait vous lever et courir avec une simple démo de cases qui ont des valeurs liées à une liste de booléens.

+0

-1 Bien que vos suggestions puissent être valides, une seule chose est nécessaire pour que le code de l'affiche originale fonctionne, en changeant le type de collection de 'Liste 'to' ObservableCollection' - Votre réponse peut être bonne, mais pas à la question à portée de main. –

+0

La question indique qu'il est nécessaire de se lier à une liste de cases à cocher, cela est clairement préférable en utilisant un itemscontrol que la liaison à chaque élément. La question indique également que les modifications du code doivent entraîner la modification de la case, ce qui a été démontré en implémentant la notification de modification dans l'objet wrapper. Autant que je sache, les modifications ne seront pas transmises à l'interface utilisateur sans cela. – mattythomas2000

+0

Merci beaucoup pour ce Matt - cette approche sera certainement utile car j'ai l'intention de créer les cases à cocher par programme et votre réponse fournit une solution élégante pour cela. –

0

Ce que vous fait penser cela ne fonctionne pas? Cela fonctionne pour moi :)

Voici mon test de XAML:

<UniformGrid> 
    <CheckBox IsChecked="{Binding Path=MyCollection[0], Mode=TwoWay}"/> 
    <ListBox ItemsSource="{Binding MyCollection}"/> 
    <Button Content="Test" Click="Button_Click"/> 
</UniformGrid> 

Voici mon code derrière:

private void Button_Click(object sender, RoutedEventArgs e) 
{ 

} 

(le reste est le même que le vôtre)

j'ai placé une point d'arrêt sur Button_Click et vérifié MyCollection[0] il a été mis à jour en fonction de la IsChecked valeur de la CheckBox. Essayez de changer votre type de collection de List<bool?> à ObservableCollection<bool?> peut-être que c'est la raison pour laquelle vous pensez que cela ne fonctionne pas pour vous (le fait que les modifications de la collection ne sont pas reflétées ailleurs dans votre vue).

+0

Merci pour votre réponse Aviad. J'ai essayé à nouveau mon code dans un nouveau projet juste pour être sûr mais pas de chance. Je ne sais pas comment vous l'avez fait! Cependant, quand j'ai changé List <> en ObservableCollection <>, les changements de la valeur dans le code ont été immédiatement reflétés sur la case - mais pas vice versa. Mais c'est un début au moins. –

+0

Voir mon commentaire ci-dessus que CheckBox-> MyCollection fonctionne dans .NET3.5 mais pas .NET4 –

1

Changer votre List<bool?> à un ObservableCollection<bool?>. Une liste n'augmente pas les notifications de modification dont WPF a besoin pour mettre à jour l'interface utilisateur. Une ObservableCollection fait. Cela gère le cas où l'entrée de la liste est modifiée et le CheckBox doit mettre à jour en conséquence.

Dans l'autre sens, cela fonctionne pour moi même avec un List<bool?> - c.-à-d. En basculant la case à cocher modifie la valeur dans la collection. Votre syntaxe de liaison est certainement correcte.

+0

Merci pour votre réponse. Si vous passez à ObservableCollection, l'interface utilisateur est mise à jour lorsque les valeurs changent dans le code. Mais bizarrement l'autre direction ne fonctionne pas avec le reste de mon code laissé tel quel. –

+0

Voir mon commentaire ci-dessus que CheckBox-> MyCollection fonctionne dans .NET3.5 mais pas .NET4 –

Questions connexes