绑定 ObservableCollection 不更新 ListView

Bound ObservableCollection doesn't update ListView

我在绑定和 INotifyPropertyChanged 方面遇到困难。 我有一个绑定到 ObservableCollection 的 ListView,启动时没有问题:数据已正确添加到 ListView。但是,当我向 collection 添加新项目时,它不会更新 UI。我确定 collection 包含 object 因为我添加了一个按钮来显示 collection.

的全部内容

这是我的 UI 代码:

<StackPanel>
                <Button Content="Show title" Tapped="Button_Tapped"/>
                <ListView ItemsSource="{Binding Subscriptions}">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <Image Grid.RowSpan="2" Margin="0 0 10 0"
                                    Source="{Binding IconUri.AbsoluteUri}"/>
                                <TextBlock Grid.Column="1"
                                    Text="{Binding Title.Text}" Style="{StaticResource BaseTextBlockStyle}"/>
                                <TextBlock Grid.Row="1" Grid.Column="1"
                                    Text="{Binding LastUpdatedTime.DateTime}"/>
                            </Grid>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackPanel>

这里是数据上下文 class:

class RssReaderData : INotifyPropertyChanged
{
    private string[] acceptContentTypes = {
                                              "application/xml",
                                              "text/xml"
                                          };

    private ObservableCollection<SyndicationFeed> _subscriptions;
    public ObservableCollection<SyndicationFeed> Subscriptions
    {
        get { return _subscriptions; }
        set { NotifyPropertyChanged(ref _subscriptions, value); }
    }

    public int SubscriptionsCount
    {
        get { return Subscriptions.Count; }
    }

    public RssReaderData()
    {
        Subscriptions = new ObservableCollection<SyndicationFeed>();
        AddFeedAsync(new Uri("http://www.theverge.com/rss/index.xml"));
        AddFeedAsync(new Uri("http://blogs.microsoft.com/feed/"));
    }

    public async Task<bool> AddFeedAsync(Uri uri)
    {
        // Download the feed at uri
        HttpClient client = new HttpClient();
        var response = await client.GetAsync(uri);

        // Check that we retrieved the resource without error and that the resource has XML content
        if (!response.IsSuccessStatusCode || !acceptContentTypes.Contains(response.Content.Headers.ContentType.MediaType))
            return false;

        var xmlFeed = await response.Content.ReadAsStringAsync();

        // Create a new SyndicationFeed and load the XML to it
        SyndicationFeed newFeed = new SyndicationFeed();
        newFeed.Load(xmlFeed);

        // If the title hasn't been set, the feed is invalid
        if (String.IsNullOrEmpty(newFeed.Title.Text))
            return false;

        Subscriptions.Add(newFeed);
        return true;
    }

    #region INotifyPropertyChanged management
    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public bool NotifyPropertyChanged<T> (ref T variable, T value, [CallerMemberName] string propertyName = null)
    {
        if (object.Equals(variable, value)) return false;
        variable = value;
        NotifyPropertyChanged(propertyName);
        return true;
    }
    #endregion
}

如您所见,我实现了 INotifyPropertyChanged 接口,而我认为我什至不必这样做(ObservableCollection 为我做了这件事)。我不关心通知我添加到我的项目的变化collection,我需要的是在添加新项目时通知它。

我会说我的代码按原样是可以的,但似乎不行,我不明白为什么:-/

另外,当我在做这件事的时候,我有两个快速的问题:ListView 和 ListBox 之间以及 Grid 和 GridView 之间有什么区别?

谢谢你的帮助:-)

编辑:根据要求,这是页面code-behind

 RssReaderData context = new RssReaderData();

    public FeedsPage()
    {
        this.InitializeComponent();

        this.NavigationCacheMode = NavigationCacheMode.Required;
    }

    private async void Button_Tapped(object sender, TappedRoutedEventArgs e)
    {
        string feedsTitles = "\n";
        foreach (var feed in context.Subscriptions)
        {
            feedsTitles += "\n " + feed.Title.Text;
        }

        MessageDialog d = new MessageDialog("There are " + context.SubscriptionsCount + " feeds:" + feedsTitles);
        await d.ShowAsync();
    }

    private async void NewFeedSubscribeButton_Tapped(object sender, TappedRoutedEventArgs e)
    {
        string feedUri = NewFeedUriInput.Text;
        if (String.IsNullOrEmpty(feedUri))
            return;

        if (!Uri.IsWellFormedUriString(feedUri, UriKind.Absolute))
        {
            MessageDialog d = new MessageDialog("The URL you entered is not valid. Please check it and try again.", "URL Error");
            await d.ShowAsync();
            return;
        }

        bool feedSubscribed = await context.AddFeedAsync(new Uri(feedUri));
        if (feedSubscribed)
        {
            NewFeedUriInput.Text = String.Empty;
            FeedsPivot.SelectedIndex = 0;
        }
        else
        {
            MessageDialog d = new MessageDialog("There was an error fetching the feed. Are you sure the URL is referring to a valid RSS feed?", "Subscription error");
            await d.ShowAsync();
            return;
        }
    }

    private void FeedsList_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (FeedsList.SelectedIndex > -1 && FeedsList.SelectedIndex < context.SubscriptionsCount)
        {
            Frame.Navigate(typeof(FeedDetailsPage), context.Subscriptions[FeedsList.SelectedIndex]);
        }
    }

事实证明,您已经创建了两个 RssReaderData 实例 - 一个在代码隐藏中,一个在 xaml 中,其中:

<Page.DataContext> 
     <DataModel:RssReaderData/> 
</Page.DataContext

在这种情况下,您的 ListView 绑定到的集合与您在后面的代码中引用的集合不同 - context.

简单的解决方案可能是从 XAML 中删除以上行并在后面的代码中设置 DataContext

public FeedsPage()
{
    this.InitializeComponent();
    this.NavigationCacheMode = NavigationCacheMode.Required;
    this.DataContext = context;
}

另一种情况是,它也可能无法正确更新 UI, - 最好先创建项目,然后将其添加到集合中。

你也可以看看at this question and its answers,它处理ObservableCollection.

中item变化时的问题