0

When trying to bind a ListView to an ObservableCollection via XAML, the ListView is not updated and is initially loaded with blank values.

Via XAML

History.xaml.cs

DataContext = this;

History.xaml:

<ListView x:Name="lvHistory" ItemsSource="{Binding Source=history}" BorderThickness="0" Margin="0,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="2" util:GridViewSort.AutoSort="True" SizeChanged="lvHistory_SizeChanged">

Via CODE

When doing the binding via code, the bindings work correctly.

History.xaml

<ListView x:Name="lvHistory" BorderThickness="0" Margin="0,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="2" util:GridViewSort.AutoSort="True" SizeChanged="lvHistory_SizeChanged">

History.xaml.cs

DataContext = this;
lvHistory.ItemsSource = history;

By simply adding the ItemsSource via code and removing it in XAML, the code works properly. What am I missing? How do I create the bindings via pure XAML?

history:

public ObservableCollection<LocateElement> history { get; private set; }

Code for updating the list:

    public void Update()
    {
        if (updater.IsBusy) updatePending = true;
        else
        {
            searchValue = txtSearch.Text.Trim();
            updatePending = false;
            updater.RunWorkerAsync();
        }
    }

    private void updateContent(object sender, DoWorkEventArgs e)
    {
        try
        {
            Globals.Variables.logger.Info("Locate History: Updating");

            using (var db = new Data.DataManager())
            {
                var history = db.LocateHistory.Where(o => o.ReceivedBy == Globals.Variables.loginDetails.UserID);

                e.Result = filterResults(history);
            }

        }
        catch (Exception er)
        {
            Globals.Variables.logger.Error(er);
        }
    }

    private void updateFinished(object sender, RunWorkerCompletedEventArgs e)
    {
        List<LocateElement> r = (List<LocateElement>)e.Result;

        history.Clear();
        foreach (LocateElement l in r)
        {
            history.Add(l);
        }

        if (updatePending) Update();
        //else Wpf.Util.GridViewSort.ReapplySort(lvHistory);
    }

    private List<LocateElement> filterResults(IQueryable<LocateElement> list)
    {
        List<LocateElement> history = new List<LocateElement>();

        foreach (LocateElement l in list)
        {
            if (searchValue != "")
            {
                // Use the parameters to filter the results.
                Regex reg = new Regex(WildcardToRegex(searchValue));


                if (reg.IsMatch(l.Serial) || reg.IsMatch(l.Asset) || reg.IsMatch(l.DeviceType) || reg.IsMatch(l.Company) || (l.ReceivedFrom != null && reg.IsMatch(l.ReceivedFrom.Name)) || (l.ReceivedTo != null && reg.IsMatch(l.ReceivedTo.Name)) || reg.IsMatch(l.Row) || reg.IsMatch(l.Shelf) || reg.IsMatch(l.Bin) || reg.IsMatch(l.DateReceived.ToString()))
                {
                    history.Add(l);
                }
            }
            else
            {
                history.Add(l);
            }
        }

        return history;
    }

2 Answers 2

2

When you assign data to your history collection you need to make sure you raise the property changed event.

For example:

    public class MyViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private ObservableCollection<LocateElement> _history;

        public ObservableCollection<LocateElement> history 
        {
            get { return _history; }
            set
            {
                if (_history != value)
                {
                    _history = value;

                    RaisePropertyChanged("history");
                }
            }
        }

        public MyViewModel()
        {
            _history = new ObservableCollection<LocateElement>();
        }

        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
Sign up to request clarification or add additional context in comments.

4 Comments

According to msdn.microsoft.com/en-us/library/ms668604(v=vs.110).aspx, Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed. This also doesn't make sense to me since the code works fine. It fails to update only when I do the binding via xaml, not code.
That is correct. But it does not notify you when you Replace the object. So if you assign history to object A, you need to notify the UI that history has changed. After that add/remove/refresh on object A will automatically notify the UI.
@TrueEddie - you're correct IF he's changing the history property outside his constructor. There's no evidence of that in the supplied code (though I admit the repeated usage of local variables with the same name is a little confusing)
@McAden Yep. It's hard to tell how it was being assigned since there was limited code, so I went on the basis that it was being done later. And good catch on Source being used instead of Path, can't believe I missed that (doh!)
1

The Source property of a Binding doesn't mean what you think it means. Use Path instead or let it assume you're talking about Path (default). This should do it.

<ListView ItemsSource="{Binding history}"  ...>

Additionally, if you're setting the history property outside your constructor it needs to notify of property changed. IF you're only setting it in your constructor you won't need to but you might want to make it backed by a readonly field instead of an auto getter/setter. (TrueEddie's solution describes this problem and supplies the solution for being able to swap out the actual variable).

2 Comments

Setting ItemsSource="{Binding history}" worked. The values were updated properly without adding a notify.
As @McAden explains, you may see the binding written like this ItemsSource="{Binding Path=history}.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.