【问题标题】:Bound ObservableCollection doesn't update ListViewBound ObservableCollection 不更新 ListView
【发布时间】:2015-04-08 09:11:21
【问题描述】:

我在绑定和 INotifyPropertyChanged 方面遇到困难。 我有一个绑定到 ObservableCollection 的 ListView,并且在启动时没有问题:数据已正确添加到 ListView。但是,当我向集合中添加新项目时,它不会更新 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 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 为我做到了)。我不关心通知我添加到我的收藏中的项目的更改,我需要的是在添加新项目时通知。

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

另外,我有两个简单的问题:ListView 和 ListBox 之间以及 Grid 和 GridView 之间有什么区别?

感谢您的帮助:-)

编辑:根据要求,这是页面的代码隐藏

 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]);
        }
    }

【问题讨论】:

  • 我发现您的代码没有明显错误。您能否显示向集合中添加新项目的代码部分?
  • 当然,我编辑了我的消息以包含我在 AddFeedAsync 方法中省略的代码。这是我实际将对象添加到 ObservableCollection 的地方。
  • 换一种方式:填充您的项目,然后添加到列表中。 var newFeed = new SyndicationFeed(); newFeed.Load(xmlFeed); Subscriptions.Add(newFeed); 我的理论是您的项目已正确添加到列表中,但显示为空项目,因为 SyndicationFeed 类未实现 INotifyPropertyChanged。如果我的理论是正确的,那么这个简单的更改应该可以修复您的应用。
  • 您的代码对我来说也很好。你能分享代码隐藏文件中的代码吗?另外(只是确保),您是否尝试过调试它,您是否 100% 确定到达并成功执行了 Subscriptions.Add(newFeed); 行?
  • @Jeahel xaml 中的这一行是指两个不同的 RssReaderData 类。尝试在您的 Page 构造函数中添加这一行:this.DataContext = context;,从 xaml 中删除 DataContext 并检查是否有帮助。

标签: c# listview windows-phone windows-phone-8.1


【解决方案1】:

事实证明,您已经创建了 RssReaderData 的两个实例 - 一个在代码后面,一个在 xaml 中:

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

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

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

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

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

你也可以看看at this question and its answers,它处理ObservableCollection中项目变化时的问题。

【讨论】:

  • 非常感谢您的精彩总结!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-15
  • 2014-11-02
  • 2019-10-25
  • 2016-04-22
相关资源
最近更新 更多