4

In WPF I have a collection of bool? values and I want to bind each of these to a separate checkbox programmatically. I want the bindings to be TwoWay so that changing the value of the individual item in the collection in code updates the check box and vice versa.

I have spent ages trying to figure out how to do this and I am completely stuck. With the following code the checkbox only gets the right value when the window is loaded and that's it. Changing the check box doesn't even update the value in the collection. (UPDATE: this appears to be a bug in .NET4 as the collection does get updated in an identical .NET3.5 project. UPDATE: Microsoft have confirmed the bug and that it will be fixed in the .NET4 release.)

Many thanks in advance for your help!

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}">
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Matt Jenkins
  • 2,824
  • 1
  • 30
  • 34
  • I'm still working through the first 3 answers but I'm baffled as to why my code seems to work for the first two respondents (at least in the direction CheckBox -> MyCollection). For me, this is simply not happening. I'm using VS2010 Beta 2 and .NET4 in case that's relevant. – Matt Jenkins Jan 17 '10 at 23:14
  • Well I certaintly didn't think this would be relevant: I copied everything into a .NET 3.5 project and hey presto - the CheckBox updates the value in MyCollection. I wonder why it's not working in .NET 4? – Matt Jenkins Jan 17 '10 at 23:41
  • Hmm, if you have code like this that works in .NET 3.5 but the identical code doesn't work in .NET 4, that suggests a bug in .NET 4. Might be worth posting to Connect. – itowlson Jan 17 '10 at 23:59

3 Answers3

5

There are a few things that need changing here to get this to work. Firstly you'll need to wrap your boolean value in an object that implements the INotifyPropertyChanged interface in order to get the change notification that you are looking for. Currently you are binding to boolean values in your collection which do not implement the interface. To do this you could create a wrapper class like so :

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

    }

You'll then want to create these objects in your form instead of a list of booleans. You may also want to use an observable collection instead of a list so that notification of items being added and removed are sent. This is shown below:

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

The next thing to do is to display a list of check boxes in your ui. To do this WPF provides itemscontrols. ListBox is an itemscontrol so we can use this as a starting point. Set the itemssource of a listbox to be MyCollection. We then need to define how each Wrapper object is going to be displayed in the list box and this can be done with a datatemplate which is created in the windows resources. This is shown below :

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

This should get you up and running with a simple demo of checkboxes that have values bound to a list of booleans.

mattythomas2000
  • 599
  • 3
  • 9
  • -1 Though your suggestions may be valid, there's only one thing required for the original poster's code to work, changing the collection type from `List` to `ObservableCollection` - Your answer may be right, but not to the question at hand. – Aviad P. Jan 17 '10 at 20:46
  • The question states that there is a requirement to bind to a list of checkboxes, this is clearly better done using an itemscontrol than binding to each item. The question also states that changes in code should cause the checkbox to change, which was demonstrated by implementing the change notification in the wrapper object. As far as I'm aware changes won't be passed to the UI without doing this. – mattythomas2000 Jan 17 '10 at 22:10
  • Thank you very much for this Matt - this approach will definitely be useful as I intended to create the checkboxes programmatically and your answer provides an elegant solution for that. – Matt Jenkins Jan 17 '10 at 23:27
0

What makes you think it's not working? It's working for me :)

Here's my test XAML:

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

Here's my code behind:

private void Button_Click(object sender, RoutedEventArgs e)
{

}

(the rest is the same as yours)

I placed a breakpoint on Button_Click and checked MyCollection[0] it was updated according to the IsChecked value of the CheckBox.

Try changing your collection type from List<bool?> to ObservableCollection<bool?> perhaps that is the reason you think it's not working for you (the fact that changes to the collection are not reflected anywhere else in your view).

Aviad P.
  • 32,036
  • 14
  • 103
  • 124
  • Thanks for your response Aviad. I tried my code again in a new project just to be sure but no luck. Not sure how you did it! However, when I changed the List<> to ObservableCollection<>, changes to the value in code were instantly reflected on the checkbox - but not vice versa. But that's a start at least. – Matt Jenkins Jan 17 '10 at 22:57
  • See my comment above that CheckBox->MyCollection works in .NET3.5 but not .NET4 – Matt Jenkins Jan 17 '10 at 23:47
0

Change your List<bool?> to an ObservableCollection<bool?>. A List does not raise the change notifications that WPF needs to update the UI. An ObservableCollection does. This handles the case where the list entry is changed and the CheckBox needs to update accordingly.

In the other direction, it works for me even with a List<bool?> -- i.e. toggling the checkbox modifies the value in the collection. Your binding syntax is certainly correct.

itowlson
  • 73,686
  • 17
  • 161
  • 157
  • Thanks for your response. Changing to an ObservableCollection does cause the UI to be updated when the values change in code. But bizarrely the other direction does not work with the rest of my code left as-is. – Matt Jenkins Jan 17 '10 at 23:20
  • See my comment above that CheckBox->MyCollection works in .NET3.5 but not .NET4 – Matt Jenkins Jan 17 '10 at 23:43