Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bind ObservableCollection using MVVM

I'm trying to put together what should be a very basic MVVM sample, but I'm having trouble getting it to work. Basically, I want to bind an ObservableCollection to a ListBox, and have a search option for the user to search for other items. Upon searching, the ListBox should be refreshed as the collection will change. Here is my code:

Model:

public class Item
   public string Name { get; set; }
}

ViewModel:

public class ViewModel : INotifyPropertyChanged
{
    private ObservableCollection<Item> _items { get; set; }
    public ObservableCollection<Item> Items
    {
        get { return _items; }
        set
        {
            _items = value;
            RaisePropertyChanged("Items");
        }
    }

    public void GetDefaultItems()
    {
        ObservableCollection<Item> temp = new ObservableCollection<Item>();
        temp.Add(new Item() { Name = "abc" + " 1" });
        temp.Add(new Item() { Name = "def" + " 2" });
        temp.Add(new Item() { Name = "ghi" + " 3" });
        Items = temp;
    }


    public void Search(string query)
    {
       ObservableCollection<Item> temp = new ObservableCollection<Item>();
       temp.Add(new Item() { Name = query + " 1" });
       temp.Add(new Item() { Name = query + " 2" });
       temp.Add(new Item() { Name = query + " 3" });
       Items = temp;
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

View:

<Grid x:Name="LayoutRoot">
    <ListBox ItemsSource="{Binding}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock x:Name="Name" Text="{Binding Name}" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

MainPage.xaml:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <StackPanel>
        <TextBox x:Name="txtSearch"/>
        <TextBlock Text="Items:" />
        <views:ItemView x:Name="ItemsOnPage" />
    </StackPanel>
</Grid>

and finally, MainPage.xaml.cs:

public partial class MainPage : PhoneApplicationPage
{
    private ViewModel vm;

    // Constructor
    public MainPage()
    {
        InitializeComponent();
        txtSearch.KeyUp += txtSearch_KeyUp;
        vm = new ViewModel();
    }

    void txtSearch_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            vm.Search(txtSearch.Text);
        }
    }

    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        vm.GetDefaultItems();
        ItemsOnPage.DataContext = vm.Items;
    }
}

So what happens is, I can see the default items load the first time but when I search, the list does not get refreshed. It is all hard-coded right now so if the search does work I should see 3 items for whatever they searched for.

What I've noticed though is that if I set up a breakpoint in the ViewModel at RaisePropertyChanged, this.PropertyChanged is always null, so it never makes it inside the if statement. I've seen examples that use INotifyPropertyChanged on the model, but in this case since I need to be notified when the collection changes, it seemed correct to use on the view model. This could be wrong, but I'm not sure how else to set it up.

Can anyone see what I'm doing wrong?

like image 547
lhan Avatar asked Jan 24 '14 05:01

lhan


People also ask

How do I bind Mvvm?

MVVM – WPF Data Bindings For data binding you need to have a view or set of UI elements constructed, and then you need some other object that the bindings are going to point to. The UI elements in a view are bound to the properties which are exposed by the ViewModel.

What is the difference between ObservableCollection and list?

One more important difference is you can access ObservableCollection only from thread on which it was created where as list can be accessed fromany thread. Save this answer. Show activity on this post. I see no problem with that, other than a very marginal performance overhead.

What is ObservableCollection in C#?

An ObservableCollection is a dynamic collection of objects of a given type. Objects can be added, removed or be updated with an automatic notification of actions. When an object is added to or removed from an observable collection, the UI is automatically updated.


1 Answers

try doing this

  1. set ItemSource to Items

  2. Clear and Add Data Items

    String preQuery="";
    public void Search(string query)
    {
       if(preQuery==query)
          return;
    
       Items.Clear();
    
       Items.Add(new Item() { Name = query + " 1" });
       Items.Add(new Item() { Name = query + " 2" });
       Items.Add(new Item() { Name = query + " 3" }); 
    }
    

Hope this helps.

like image 183
AlexisXu Avatar answered Sep 19 '22 12:09

AlexisXu