lhan
lhan

Reputation: 4635

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?

Upvotes: 8

Views: 20126

Answers (2)

Ramashankar
Ramashankar

Reputation: 1658

It looks like value of items collection is not being refreshed on UI.

Try this-

Code in MainPage.cs

   private ViewModel _viewModel;

MainPage Constructor

  _viewModel = new ViewModel();
  this.DataContext = _viewModel ;

Binding in MainPage XAML

<views:ItemView x:Name="ItemsOnPage" DataContext="{Binding Path=Items,UpdateSourceTrigger=PropertyChanged}"/>

Upvotes: 0

AlexisXu
AlexisXu

Reputation: 126

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.

Upvotes: 5

Related Questions