0
votes

my PropertyChanged event is not updatin my listview in xamarin. Could someone help me with that?

The Method RefreshListView is triggered when the searchbar text has changed.

My Viewmodel:

public class LebensmittelViewModel : INotifyPropertyChanged
{
    private ObservableCollection<Lebensmittel> lebensmittelList = new ObservableCollection<Lebensmittel>();
    public List<Lebensmittel> normalLebensmittelList = new List<Lebensmittel>();
    public event PropertyChangedEventHandler PropertyChanged;

    public LebensmittelViewModel()
    {
        normalLebensmittelList = App.LebensmittelDatabase.getAllLebensmittel();
    }

    public void RefreshListView(string searchBarText)
    {
        LebensmittelList = addItemInCollection(searchBarText);
    }

    public ObservableCollection<Lebensmittel> addItemInCollection(string searchBarText)
    {
        if (searchBarText != null)
        {
            foreach (var item in normalLebensmittelList)
            {
                if (item.Name.Contains(searchBarText) || item.Name.Contains(searchBarText.First().ToString().ToUpper()))
                {
                    LebensmittelList.Add(item);
                };
            }
        }
        return LebensmittelList;
    }

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public ObservableCollection<Lebensmittel> LebensmittelList
    {
        get
        {
            return lebensmittelList;
        }
        set
        {
            lebensmittelList = value;
            OnPropertyChanged("LebensmittelList");
        }
    }
}

Einkaufsliste.xaml

<ContentPage.Content>
    <StackLayout Spacing="10" Padding="10">
        <SearchBar x:Name="searchBar" Text="{Binding searchBarText}" Placeholder="Lebensmittel suchen..." VerticalOptions="StartAndExpand">
            <SearchBar.Behaviors>
                <behavior:TextChangedBehavior/>
            </SearchBar.Behaviors>
        </SearchBar>
        <ListView x:Name="listView" ItemsSource="{Binding LebensmittelList}" HasUnevenRows="True">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout VerticalOptions="FillAndExpand" Orientation="Horizontal" Padding="10">
                            <Label Text="{Binding Name}" YAlign="Center" Font="Large"/>
                            <ia:Checkbox HorizontalOptions="EndAndExpand"/>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage.Content>

Einkaufsliste.xaml.cs

public Einkaufsliste ()
    {
        InitializeComponent ();
        BindingContext = new LebensmittelViewModel();
    }

I think everything should be okay but it's not working. Hope someone could help me with this,

thanks

Edit for Tom:

public void RefreshListView(string searchBarText)
    {
        addItemInCollection(searchBarText);
    }

    public void addItemInCollection(string searchBarText)
    {
        if (searchBarText != null)
        {
            foreach (var item in normalLebensmittelList)
            {
                if (item.Name.Contains(searchBarText) || item.Name.Contains(searchBarText.First().ToString().ToUpper()))
                {
                    AddItemToList(item);
                };
            }
        }
    }

    private void AddItemToList(Lebensmittel item)
    {
        lebensmittelList.Add(item);
        LebensmittelList = lebensmittelList;
    }
5

5 Answers

0
votes

How it's implemented the behavior TextChangedBehavior? Do you cast the BindingContext as a LebensmittelViewModel in order to call RefreshListView?

I would get rid of the behavior :/ and add a TextChanged event, create the property SearchBarText, since I don't see where it's declared and you're binding it to the SearchBar, refactor the RefreshListView method... and I think that it should work... :)

Einkaufsliste.xaml.cs

private LebensmittelViewModel vm = new LebensmittelViewModel();
public Einkaufsliste ()
{
    InitializeComponent ();
    BindingContext = vm;
}

public void OnSeachBarTextChange(object e, TextChangedEventArgs args)
{
    vm.RefreshListView();
}

Einkaufsliste.xaml

<ContentPage.Content>
    <StackLayout Spacing="10" Padding="10">
        <SearchBar x:Name="searchBar" Text="{Binding SearchBarText, Mode=TwoWay}" Placeholder="Lebensmittel suchen..." VerticalOptions="StartAndExpand" TextChanged="OnSeachBarTextChange">
        </SearchBar>
        <ListView x:Name="listView" ItemsSource="{Binding LebensmittelList}" HasUnevenRows="True">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout VerticalOptions="FillAndExpand" Orientation="Horizontal" Padding="10">
                            <Label Text="{Binding Name}" YAlign="Center" Font="Large"/>
                            <ia:Checkbox HorizontalOptions="EndAndExpand"/>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage.Content>

Viewmodel

private string _searchBarText;

public string SearchBarText
{
    get
    {
        return _searchBarText;
    }
    set
    {
        _searchBarText = value;
        OnPropertyChanged("SearchBarText");
    }
}

public void RefreshListView()
{
    if (!string.IsNullOrEmpty(searchBarText))
    {
        var matches = normalLebensmittelList.Where(x => x.Name.Contains(searchBarText) || x.Name.Contains(searchBarText.First().ToString().ToUpper())
        foreach (var item in matches)
        {
          LebensmittelList.Add(item);
        }
    }
}
0
votes

Can you try replacing the Following method:

public void RefreshListView(string searchBarText)
{
    LebensmittelList.Clear();
    addItemInCollection(searchBarText);
}

Since you are already using the Observable Collection you dont need to replace the collection. You can add and it will automatically observed and binded. Let me know if it works!

0
votes

It looks like you have extra work with LebensmittelList. Try do the following:

public void RefreshListView(string searchBarText)
{
    // this can be list clearing, if you need it
    addItemInCollection(searchBarText);
    OnPropertyChanged("LebensmittelList");
}

public void addItemInCollection(string searchBarText)
{
    if (searchBarText != null)
    {
        foreach (var item in normalLebensmittelList)
        {
            if (item.Name.Contains(searchBarText) || item.Name.Contains(searchBarText.First().ToString().ToUpper()))
            {
                LebensmittelList.Add(item);
            };
        }
    }
}

Edit: I don't know if anyone can call this solution elegant, but it should work.

internal class MyCollection<T> : ObservableCollection<T> 
{
    public void DoCollectionChanged()
    {
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

}

    ... MyCollection<LebensmittelItem> LebensmittelList; // field and property declaration should be changed

public void RefreshListView(string searchBarText)
{
    // this can be list clearing, if you need it
    addItemInCollection(searchBarText);
    LebensmittelList.DoCollectionChanged();
}
0
votes

Is OnPropertyChanged in the property set called when you do the RefreshListView?

0
votes

In the addItemToCollection method, you are calling the following line:

LebensmittelList.Add(item);

In this case LebensmittelList is a property, not a variable. The line LebensmittelList.Add(item); is effectively doing the following:

var temporaryList = LebensmittelList; // Gets lebensmittelList and assigns to temporaryList
temporaryList.Add(item); // You add the item to the *variable temporaryList*

Essentially, you are adding to an instance of lebensmittelList (a temporary copy), and not the lebensmittelList variable. Once you have added that item to the temporary list, the whole (temporary) list gets discarded without "saving changes".

To actually update LebensmittelList, you would be better off calling a method like:

private void AddItemToList(object item)
{
    lebensmittelList.Add(item);
    LebensmittelList = lebensmittelList;
}