28
votes

I am new in Binding and WPF recently I've learned how to create a listBox with multiple columns using Binding tech

 <ListView ItemsSource="{Binding Items}" Margin="306,70,22,17" MouseDoubleClick="listBoxSS_MouseDoubleClick" Name="listBoxSS" >           
    <ListView.View>
            <GridView>
                <GridView.Columns>
                    <GridViewColumn Header="first_name " Width="100" DisplayMemberBinding="{Binding Path=First_name}" />
                    <GridViewColumn Header="last_name" Width="100" DisplayMemberBinding="{Binding Path=Last_name}" />
                    <GridViewColumn Header="phone_number" Width="100" DisplayMemberBinding="{Binding Path=Phones[0]}" />
                    <GridViewColumn Header="notes" Width="100" DisplayMemberBinding="{Binding Path=Notes}" />
                </GridView.Columns>
            </GridView>
        </ListView.View>
    </ListView>

and this is the code:

List<Student> arr = search.students();
        listBoxSS.ItemsSource = arr;

but the problem was when I tried to use add or remove item or clear

 listBoxSS.Items.Clear();

Please I need an example for using the items source or the way that I can ADD or Remove Item or Clear the list.

EDIT:

<ListView ItemsSource="{Binding Items}" Margin="306,70,22,17" MouseDoubleClick="listBoxSS_MouseDoubleClick" Name="listBoxSS" >
    <ListView.View>
        <GridView>
            <GridView.Columns>
                <GridViewColumn Header="first_name " Width="100" DisplayMemberBinding="{Binding Path=First_name}" />
                <GridViewColumn Header="last_name" Width="100" DisplayMemberBinding="{Binding Path=Last_name}" />
                <GridViewColumn Header="phone_number" Width="100" DisplayMemberBinding="{Binding Path=Phones[0]}" />
                <GridViewColumn Header="notes" Width="100" DisplayMemberBinding="{Binding Path=Notes}" />
            </GridView.Columns>
        </GridView>
    </ListView.View>
</ListView>

and here is the code:

 ObservableCollection<Employee> Gemployees;
var employees = new ObservableCollection<Employee>(search.employees());

search.employees() get the list of all employees in my DB

 listBoxPE.ItemsSource = employees;
        Gemployees = employees;

now I can perform all the methods on Gemployees

 Gemployees.Remove((Student)listBoxSS.SelectedItem);
 Gemployees.Add((Student)listBoxSS.SelectedItem);

The ListView perform a refresh whenever I add or remove an Item from Gemployees!! Cool but still a little hard work on binding. Now I am doing an interface class to every ListView so I can put my stuff into it. It wont perform any flexibility in Adding Items.

11

11 Answers

32
votes

You're binding the ItemsSource to a property in the DataContext called Items, so to update the collection, you need to go to the Items property in the DataContext and clear it.

In addition, the Items property needs to be of type ObservableCollection, not List if you want it to update the UI whenever the underlying collection changes.

Your bit of code that sets the ItemsSource in the code behind is not needed and should be removed. You only need to set the ItemsSource in one place, not both.

Here's a simple example of how it can work:

// Using Students instead of Items for the PropertyName to clarify
public ObservableCollection<Student> Students { get; set; }

public MyConstructor()
{
    ...

    Students = search.students();
    listBoxSS.DataContext = this;
}

Now when you have:

<ListView ItemsSource="{Binding Students}" ... />

you're binding the ItemsSource to the ObservableCollection<Student>, and when you want to clear the list you can call:

Students.Clear()
16
votes

I know this question has been answered about 2 years ago, however I had this problem myself as well and thought of a possible solution myself, which works. Maybe this doesn't work in certain scenarios and maybe I'm simply not seeing something, but it worked for me so I'm sharing it here:

listView.ClearValue(ItemsControl.ItemsSourceProperty);
listView.ItemsSource = NewSource;

I sincerely hope this helps someone.

16
votes

Weird but true: the following errant keystrokes in my XAML file produced the error "Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead.":

</ItemsControl.ItemTemplate>x`

Note the "x`" characters after the closing element tag.

13
votes

I think the answer above isn't quite clear. Related to the rogue characters, this also causes the exception:

<ItemsControl ItemsSource="{Binding AnObservableCollection}">
    <Label Content="{Binding Name}"/>
</ItemsControl>

When what you meant was:

<ItemsControl ItemsSource="{Binding AnObservableCollection}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Label Content="{Binding Name}"/>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Its easy to think the first is correct and the exception in no way explains what is wrong.

3
votes

You need to work against the collection that is data-bound to your ItemsSource. In order to get collection change notifications (when items get added or removed), you should use an ObservableCollection<T>:

var students = new ObservableCollection<Student>(search.students());
listBoxSS.ItemsSource = students;

students.Clear();
students.Add(new Student("ABC"));

And you should remove the ItemsSource="{Binding Items}" declaration from your XAML.

2
votes

I had the same error message appear, resulting from a syntax error. It turns out I was accidentally defining an item in a TreeView that had an ItemsSource defined. I had defined a DataTemplate for the tree view, but accidentally put it directly in <TreeView> instead of <TreeView.Resources>, causing the error.

What I had:

<TreeView ItemSource ="{Binding Items}">
  <HierarchicalDataTemplate> ... </HierarchicalDataTemplate>
  <DataTemplate> ... </DataTemplate>
</TreeView>

What I should have had:

<TreeView ItemSource ="{Binding Items}">
  <TreeView.Resources>
    <HierarchicalDataTemplate> ... </HierarchicalDataTemplate>
    <DataTemplate> ... </DataTemplate>
  </TreeView.Resources>
</TreeView>
1
votes

Assign the ItemsSource property of the listbox to a public property inside the form's class. Then try adding a removing from that, calling PropertyChanged inside the setter, instead of calling clear directly on the listbox items source.

1
votes

Always bind an ItemsSource to an ObservableCollection to avoid memory leaks. An ObservableCollection will also cause the display to update automatically with Add/Remove. I used to always bind to arrays before I learned this.

A useful source: https://onewindowsdev.com/2016/09/22/a-memory-leak-may-occur-when-you-use-data-binding-in-windows-presentation-foundation/

1) For DataBinding in general the class you bind to should implement INotifyPropertyChanged. The exception to this is to use Mode=OneTime bindings.

2) An ItemsSource should always be a class that implements INotifyCollectionChange. The easiest way to do this is to use an ObservableCollection. ObservableCollection does have a constructor that takes in an IEnumerable which I've found useful.

3) If the ItemsControl is an ObservableCollection < SomeClass > than SomeClass should implement INotifyPropertyChange. You can then safely bind to individual properties of SomeClass.

0
votes

I had this same problem, and I eventually realized that I was trying to add a new item directly to the control's ItemsSource, rather than to the ObservableCollection that served as the ItemsSource.

I figured I'd post this, as it might help other novice wpfers.

0
votes

For me, it was totally unrelated issue. It was a silly syntax error where I forgot to wrap my <style> </style> with a <DataGrid.Style> </DataGrid.Style>.

Thanks Microsoft for the totally confusing error message.

0
votes

For me, the issue was that I misunderstood the directions for a control and accidentally put it inside the datagrid control instead of outside.

    <DataGrid> 
        <mytag the tag for the open source control />
    </DataGrid>

Someone above mentioned extraneous characters, and all of the sudden I realized maybe DataGrid did not like it there. I moved it and voila, the error

Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead.

was gone! It really had NOTHING to do with an ItemsSource, but it was confusing whatever parser is generating that Microsoft error.