简体   繁体   中英

Binding ObservableCollection in viewmodel to listbox

I'm very new to MVVM and bindings and I'm trying to learn to work with it. I run into the problem of binding my viewmodel to the view in particular binding an observable collection to a listbox.

this is what my viewmodel looks like:

namespace MyProject
{
    using Model; 

public class NetworkViewModel: INotifyPropertyChanged
{

    private ObservableCollection<Person> _networkList1 = new ObservableCollection<Person>();
    public ObservableCollection<Person> NetworkList1 //Binds with the listbox
    {
        get { return _networkList1; }
        set { _networkList1 = value; RaisePropertyChanged("_networkList1"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public NetworkViewModel() 
    {
        _networkList1 = new ObservableCollection<Person>()
        {
            new Person(){FirstName="John", LastName="Doe"},
            new Person(){FirstName="Andy" , LastName="Boo"}
        };
   }
}

in the view I have

namespace MyProject
{
    public partial class Networking : Window
    {

        public Networking()
       {
            InitializeComponent();

            this.DataContext = new NetworkViewModel();

            lb1.ItemsSource = _networkList1;
        }
     }
}  

and in the XAML I have

<ListBox x:Name="lb1" HorizontalAlignment="Left" ItemsSource="{Binding NetworkList1}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock >
                         <Run Text="{Binding Path=FirstName}"/>
                         <Run Text="{Binding Path=LastName}"/>
                    </TextBlock>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

It seems like you might have a typo in your view model.

RaisePropertyChanged("_networkList1");

You want to raise the property changed notification for the public property not the private variable.

RaisePropertyChanged("NetworkList1");

This might be preventing your view from updating properly.

In addition to Gaurav answer, if _networkList1 is a private field in your NetworkViewModel class, how is it possible to get access to it in Networking window? I mean what's the meaning of the following line?

lb1.ItemsSource = _networkList1;

when you define a Property ( NetworkList1 ), you have to use it in order to get advantages of its features (eg to get RaisePropertyChanged working). Otherwise what's the point, you could have just defined a field ( _networklist1 ). So changing

_networkList1 = new ObservableCollection<Person>()

to

NetworkList1 = new ObservableCollection<Person>()

results in actually setting NetworkList1 and therefore RaisePropertyChanged("NetworkList1") to be fired. (however if you want to just show data in a your listbox this is unnecessary)

and if i'm getting it right, changing this:

public partial class Networking : Window
{

    public Networking()
   {
        InitializeComponent();

        this.DataContext = new NetworkViewModel();

        lb1.ItemsSource = _networkList1;
    }
 }

to

    public partial class Networking : Window
    {

        public NetworkViewModel MyViewModel { get; set; }
        public Networking()
        {
            InitializeComponent();

            MyViewModel = new NetworkViewModel();

            this.DataContext = MyViewModel;

        }
    }

should get your binding to work.

*Note that when you set DataContext to NetworkViewModel , then the binding in

<ListBox x:Name="lb1" HorizontalAlignment="Left" ItemsSource="{Binding NetworkList1}">

works, because NetworkList1 is a Property of NetworkViewModel .

Do not call RaisePropertyChanged() method on ObservableCollection<T> , for god's sake. This is a common mistake in a majority of cases (however, there are cases, where you need to reset ObservableCollection<T> using new keyword, but they are kinda rare). This is a special type of collection which notifies UI internally about all the changes of its content (like add, remove etc.). What you need is to set the collection using new keyword once in a lifetime of your ViewModel, and then manipulate your items via Add(T item) , Remove(T item) , Clear() methods etc. and UI will get notified about it and updated automatically.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM