绑定到itemsSource后,LongListSelector不会刷新

时间:2014-01-09 07:53:52

标签: windows-phone-7 windows-phone-8 windows-phone async-await longlistselector

  1. 从网络获取数据并显示
  2. 我使用LongListSelector(articleList)来显示数据,web api可以通过设置断点在visual studio中验证。
  3. [ISSUE]将ItemSource设置为viewModel.ArticleCollection,从web api检索数据后,LongListSelector不刷新。
  4. 但是在MainPage.xaml.cs中的OnNavigatedTo方法中的chenge代码之后,FROM“_viewModel.LoadPage(_ searchTerm,_ pageNumber ++);” TO“articleList.ItemsSource = await CollectionHttpClient.GetAllArticlesAsync();”它显示web api数据。
  5. 任何人都可以帮助我吗?提前谢谢!

    MainPage.xaml中

    <phone:PhoneApplicationPage
    x:Class="CollectionApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:vm="clr-namespace:CollectionApp.ViewModels"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait"  Orientation="Portrait"
    shell:SystemTray.IsVisible="True">
    
    <phone:PhoneApplicationPage.Resources>
    
        <vm:ArticleListViewModel x:Key="viewModel"/>
    
        <DataTemplate x:Key="ResultItemTemplate">
            <Grid Margin="0,6,0,0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Rectangle Fill="Gray" Height="50" Width="50" Grid.Row="0" Grid.Column="0" 
                         VerticalAlignment="Top" Margin="0,7,7,0"
                       Grid.RowSpan="2">
    
                </Rectangle>
                <Image Height="50" Width="50" Grid.Row="0" Grid.Column="0" 
                         VerticalAlignment="Top" Margin="0,7,7,0"
                       Grid.RowSpan="2">
                    <Image.Source>
                        <BitmapImage UriSource="{Binding ImagePath}"
                                     CreateOptions="BackgroundCreation"/>
                    </Image.Source>
                </Image>
                <TextBlock Text="{Binding Subject}" Grid.Row="0" Grid.Column="1"
                                 Foreground="{StaticResource PhoneAccentBrush}" VerticalAlignment="Top"/>
    
                <TextBlock Text="{Binding Words}" TextWrapping="Wrap"
                               Grid.Row="1" Grid.Column="1"
                               VerticalAlignment="Top"
                               />
    
            </Grid>
        </DataTemplate>
    
    </phone:PhoneApplicationPage.Resources>
    
    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
    
        <!-- LOCALIZATION NOTE:
            To localize the displayed strings copy their values to appropriately named
            keys in the app's neutral language resource file (AppResources.resx) then
            replace the hard-coded text value between the attributes' quotation marks
            with the binding clause whose path points to that string name.
    
            For example:
    
                Text="{Binding Path=LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}"
    
            This binding points to the template's string resource named "ApplicationTitle".
    
            Adding supported languages in the Project Properties tab will create a
            new resx file per language that can carry the translated values of your
            UI strings. The binding in these examples will cause the value of the
            attributes to be drawn from the .resx file that matches the
            CurrentUICulture of the app at run time.
         -->
    
        <!--Pivot Control-->
        <phone:Pivot Title="{Binding Path=LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}">
            <!--Pivot item one-->
            <phone:PivotItem Header="Articles">
                <!--Double line list with text wrapping-->
                <phone:LongListSelector 
                    x:Name="articleList"
                    Grid.Row="1"   
                    Margin="0,0,-12,0" 
                    DataContext="{StaticResource viewModel}"
                    ItemTemplate="{StaticResource ResultItemTemplate}"   
                    ItemsSource="{Binding viewModel.ArticleCollection}"
                    >
    
                </phone:LongListSelector>
            </phone:PivotItem>
    
            <!--Pivot item two-->
            <phone:PivotItem Header="second">
                <!--Double line list no text wrapping-->
                <phone:LongListSelector Margin="0,0,-12,0" ItemsSource="{Binding Items}">
                    <phone:LongListSelector.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Margin="0,0,0,17">
                                    <TextBlock Text="{Binding LineOne}" TextWrapping="NoWrap" Margin="12,0,0,0" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                                    <TextBlock Text="{Binding LineThree}" TextWrapping="NoWrap" Margin="12,-6,0,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
                                </StackPanel>
                            </DataTemplate>
                    </phone:LongListSelector.ItemTemplate>
                </phone:LongListSelector>
            </phone:PivotItem>
        </phone:Pivot>
    
        <!--Uncomment to see an alignment grid to help ensure your controls are
            aligned on common boundaries.  The image has a top margin of -32px to
            account for the System Tray. Set this to 0 (or remove the margin altogether)
            if the System Tray is hidden.
    
            Before shipping remove this XAML and the image itself.-->
        <!--<Image Source="/Assets/AlignmentGrid.png" VerticalAlignment="Top" Height="800" Width="480" Margin="0,-32,0,0" Grid.Row="0" IsHitTestVisible="False" />-->
    </Grid>
    
    </phone:PhoneApplicationPage>
    

    MainPage.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Navigation;
    using Microsoft.Phone.Controls;
    using Microsoft.Phone.Shell;
    using CollectionApp.Resources;
    using CollectionApp.Network;
    using CollectionApp.Models;
    using CollectionApp.ViewModels;
    using System.Windows.Data;
    using System.Diagnostics;
    using Windows.UI.Core;
    
    namespace CollectionApp
    {
        public partial class MainPage : PhoneApplicationPage
        {
            int _pageNumber = 1;
            string _searchTerm = "";
            ArticleListViewModel _viewModel = new ArticleListViewModel();
            int _offsetKnob = 1;
    
            // Constructor
            public MainPage()
            {
                InitializeComponent();
    
                //_viewModel = new ArticleListViewModel();
                _viewModel = (ArticleListViewModel)Resources["viewModel"];
                DataContext = _viewModel;
    
                articleList.ItemRealized += articleList_ItemRealized;
                this.Loaded += new RoutedEventHandler(MainPage_Loaded);
    
                //_viewModel = new ArticleListViewModel();
                articleList.ItemsSource = _viewModel.ArticleCollection;
    
                // Set the data context of the listbox control to the sample data
                //DataContext = App.ViewModel;
    
                // Sample code to localize the ApplicationBar
                //BuildLocalizedApplicationBar();
            }
    
            void MainPage_Loaded(object sender, RoutedEventArgs e)
            {
                var progressIndicator = SystemTray.ProgressIndicator;
                if(progressIndicator != null)
                {
                    return;
                }
    
                progressIndicator = new ProgressIndicator();
    
                SystemTray.SetProgressIndicator(this, progressIndicator);
    
                Binding binding = new Binding("IsLoading") { Source = _viewModel };
                BindingOperations.SetBinding(progressIndicator, ProgressIndicator.IsVisibleProperty, binding);
    
                binding = new Binding("IsLoading") { Source = _viewModel};
                BindingOperations.SetBinding(progressIndicator, ProgressIndicator.IsIndeterminateProperty, binding);
    
                progressIndicator.Text = "Loading new Articles....";            
    
            }
    
            private void articleList_ItemRealized(object sender, ItemRealizationEventArgs e)
            {
                if (!_viewModel.IsLoading && articleList.ItemsSource != null && articleList.ItemsSource.Count >= _offsetKnob)
                {
                    if (e.ItemKind == LongListSelectorItemKind.Item)
                    {
                        if ((e.Container.Content as Article).Equals(articleList.ItemsSource[articleList.ItemsSource.Count - _offsetKnob]))
                        {
                            Debug.WriteLine("Searching for {0}", _pageNumber);
                            //_viewModel.LoadPage(_searchTerm, _pageNumber++);
                        }
                    }
                }
            }
    
    
            // Load data for the ViewModel Items
            protected async override void OnNavigatedTo(NavigationEventArgs e)
            {
                try
                {
                    if (CollectionHttpClient.IsDirty)
                    {
                        _viewModel.LoadPage(_searchTerm, _pageNumber++);
                        // articleList.ItemsSource = await CollectionHttpClient.GetAllArticlesAsync(); ;
    
                    }
                }
                catch
                {
                    MessageBox.Show("sorry, no data.");
                }
            }
    
            // Sample code for building a localized ApplicationBar
            //private void BuildLocalizedApplicationBar()
            //{
            //    // Set the page's ApplicationBar to a new instance of ApplicationBar.
            //    ApplicationBar = new ApplicationBar();
    
            //    // Create a new button and set the text value to the localized string from AppResources.
            //    ApplicationBarIconButton appBarButton = new ApplicationBarIconButton(new Uri("/Assets/AppBar/appbar.add.rest.png", UriKind.Relative));
            //    appBarButton.Text = AppResources.AppBarButtonText;
            //    ApplicationBar.Buttons.Add(appBarButton);
    
            //    // Create a new menu item with the localized string from AppResources.
            //    ApplicationBarMenuItem appBarMenuItem = new ApplicationBarMenuItem(AppResources.AppBarMenuItemText);
            //    ApplicationBar.MenuItems.Add(appBarMenuItem);
            //}
    
            private void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                LongListSelector selector = sender as LongListSelector;
    
                // verifying sender is actually a LongListSelector
                if (selector == null)
                {
                    return;
                }
    
                NavigationService.Navigate(new Uri("Pages/DetailsPage.xaml?id=" + (selector.SelectedItem as Article).ID, UriKind.RelativeOrAbsolute));
    
                //
                selector.SelectedItem = null;
    
            }
    
    
        }
    }
    

    ArticleListViewModel.cs

    using CollectionApp.Models;
    using CollectionApp.Network;
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    
    namespace CollectionApp.ViewModels
    {
        public class ArticleListViewModel : INotifyPropertyChanged
        {
            private bool _isLoading = false;
    
            public bool IsLoading
            {
                get
                {
                    return _isLoading;
                }
                set
                {
                    _isLoading = value;
                    NotifyPropertyChanged("IsLoading");
                }
            }
    
            public ArticleListViewModel()
            {
                this.ArticleCollection = new ObservableCollection<Article>();
                this.IsLoading = false;
            }
    
    
            public ObservableCollection<Article> ArticleCollection
            {
                get;
                private set;
            }
    
            public void LoadPage(string searchTerm, int pageNumber)
            {
                if (pageNumber == 1)
                {
                    this.ArticleCollection.Clear();
                }
    
                IsLoading = true;
                ReadArticleList();
    
            }
    
            public async void ReadArticleList()
            {
                try
                {
                    if (CollectionHttpClient.IsDirty)
                    {
                        ArticleCollection = await CollectionHttpClient.GetAllArticlesAsync();
                        IsLoading = false;
    
                    }
    
                }
                catch
                {                
                    MessageBox.Show("sorry, no data.");
                    IsLoading = false;
                }
    
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void NotifyPropertyChanged(String propertyName)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (null != handler)
                {
                    handler(this, new PropertyChangedEventArgs(propertyName));
                }
            }
    
        }
    }
    

2 个答案:

答案 0 :(得分:0)

我怀疑,因为ArticleCollection设置时你不会提升属性更改事件。这就是为什么LongListSelector没有得到刷新的原因。 ObservableCollection仅在项目添加或从集合中删除时通知UI。但是当它自己被分配给新ObservableCollection对象的ObservableCollection属性时,您需要手动提升属性更改事件。尝试按照以下方式更改它,看看它现在是否有效:

private ObservableCollection<Article> _articleCollection;
public ObservableCollection<Article> ArticleCollection
{
    get
    {
        return _articleCollection;
    }
    set
    {
        _articleCollection = value;
        NotifyPropertyChanged("ArticleCollection");
    }
}

另一个选择是不要像{1}}方法那样重新分配ArticleCollection

ReadListArticle

而是清除集合并将每个新项目添加到集合中。

答案 1 :(得分:0)

终于,我来了。我每次都刷新ArticleCollection,这就是原因。 每次将项目分配给UI容器时,每次都会触发ItemRealized事件,直到没有新项目分配给UI容器。

最后一次,web api没有返回结果,因为最后一页没有结果。这次我将没有结果分配给ArticleCollection。这就是为什么longlistselector什么都不显示

更改方法

public async void ReadArticleList()
        {
            try
            {
                if (CollectionHttpClient.IsDirty)
                {
                    ArticleCollection = await CollectionHttpClient.GetAllArticlesAsync();
                    IsLoading = false;

                }

            }
            catch
            {                
                MessageBox.Show("sorry, no data.");
                IsLoading = false;
            }

        }

成:

private async void ReadArticleList(int pageNumber)
        {
            try
            {

                List<Article> articleList = new List<Article>();
                articleList = await CollectionHttpClient.GetArticlesByPageAsync(pageNumber);

                foreach (var item in articleList)
                {
                    this.ArticleCollection.Add(item);
                }

                IsLoading = false;


            }
            catch
            {
                MessageBox.Show("sorry, no data.");
                IsLoading = false;
            }

        }