简体   繁体   中英

Passing binded listbox data to pivot page? Windows Phone 7

I am having an absolute headache figuring this out. I badly need some help with this.

I have a listbox populated with items called with a public static void RSS feed class. Once the listbox populates with the databound items, I click on an item and it passes it through to my pivot page. However, when I flick left or right, all I get is the same image. That is my problem, and what I would like to have happen is if the user flicks left, it loads the previous RSS image. I would like it to also go to the next picture if the If the user scrolls right.

The community has been helpful in providing links to some things, or saying to not use the listbox, etc. However while I am new to all of this, I would just like concrete help with the code i have to achieve what I have in mind. It's nothing personal -- I just need to take babysteps with this before I get worked up with other things I have no clue about.

Here is all my relevant code.

Page 1 Xaml:

    <ListBox x:Name="listbox" HorizontalContentAlignment="Stretch" ItemsSource="{Binding items}" SelectionChanged="listbox_SelectionChanged">
            <ListBox.ItemTemplate>
                <DataTemplate>
                            <Image Stretch="Fill" Height="60" Width="85" Source="{Binding Url}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

Page1 C# Code Behind:

 namespace Imaged
 {
  public partial class UserSubmitted : PhoneApplicationPage
  {
    private const string Myrssfeed = "http://feeds.bbci.co.uk/news/rss.xml";

    public UserSubmitted()
    {
        InitializeComponent();

        //This next function calls the RSS service, and returns the (items) and binds it to 
        //{listbox.ItemsSource = items;}. I am unable to reference the count of the items, or 
        //the array of it for some reason? The images load once the page loads.
        RssService.GetRssItems(Myrssfeed, (items) => { listbox.ItemsSource = items; }, (exception) => { MessageBox.Show(exception.Message); }, null);
    }     
   }
  }

Once the listbox fills I am now trying to pass the selection by the user to a pivot page. I want that same image to show up in the pivot, and when the user pivots left or right, it shows the previous image or next image in the collection.

The Pivot Page I am trying to pass this to, XAML:

<Grid x:Name="LayoutRoot" Background="Transparent">
    <!--Pivot Control-->
    <controls:Pivot Title="{Binding Title}">

        <!--Pivot item one-->
        <controls:PivotItem x:Name="item1">
                <Image Source="{Binding Url}"/>  <!--I take it this is causing the pics to be the same?-->
        </controls:PivotItem>

        <!--Pivot item two-->
        <controls:PivotItem x:Name="item2">
                <Image Source="{Binding Url}"/>
        </controls:PivotItem>

        <!--Pivot item three-->
        <controls:PivotItem x:Name="item3">
                <Image Source="{Binding Url}"/>
        </controls:PivotItem>

    </controls:Pivot>
</Grid>

The RSS Service Class being called:

 namespace WindowsPhone.Helpers
 { 
  public class RssService
  {
    public static void GetRssItems(string rssFeed, Action<IList<RssItem>> onGetRssItemsCompleted = null, Action<Exception> onError = null, Action onFinally = null)
    {

        WebClient webClient = new WebClient();

        // register on download complete event
        webClient.OpenReadCompleted += delegate(object sender, OpenReadCompletedEventArgs e)
        {
            try
            {
                // convert rss result to model
                IList<RssItem> rssItems = new List<RssItem>();

                Stream stream = e.Result;
                XmlReader response = XmlReader.Create(stream);
                {
                    SyndicationFeed feeds = SyndicationFeed.Load(response);

                    foreach (SyndicationItem f in feeds.Items)
                    {
                        RssItem rssItem = new RssItem(f.Title.Text, f.Summary.Text, f.PublishDate.ToString(), f.Links[0].Uri.AbsoluteUri);
                        rssItems.Add(rssItem);
                    }
                }    

                // notify completed callback
                if (onGetRssItemsCompleted != null)
                {
                    onGetRssItemsCompleted(rssItems);
                }
            }
            finally
            {
                // notify finally callback
                if (onFinally != null)
                {
                    onFinally();
                }
            }
        };

        webClient.OpenReadAsync(new Uri(rssFeed));
     }
    }
  }

and finally the RSSItem Class:

namespace WindowsPhone.Helpers
{
  public class RssItem
  {
    public RssItem(string title, string summary, string publishedDate, string url)
    {
        Title = title;
        Summary = summary;
        PublishedDate = publishedDate;
        Url = url;

        // Get plain text from html
        PlainSummary = HttpUtility.HtmlDecode(Regex.Replace(summary, "<[^>]+?>", ""));
    }
    public string Title { get; set; }
    public string Summary { get; set; }
    public string PublishedDate { get; set; }
    public string Url { get; set; }
    public string PlainSummary { get; set; }
    }
  }

Disclaimer: I don't think that binding this many items to a Pivot control is necessarily the right thing to do. Your mileage may vary, but I think a more virtualized solution would be more efficient. For my tests, it seemed to perform OK, but my little voice tells me that there be dragons here...

I recreated your project to the best of my ability and made some enhancements to get it to do what you wanted. Basically, the trick was using a ViewModel that was shared between both the main list page (UserSubmitted.xaml) and the page with the Pivot items on it (PivotPage1.xaml). By setting both page's DataContext property to the same object, we were able to bind both lists to the same source, thus eliminating the need to pass anything around.

In App.xaml.cs:

public static ViewData ViewModel { get; private set; }

private void Application_Launching(object sender, LaunchingEventArgs e)
{
     // note: you should properly Tombstone this data to prevent unnecessary network access
     ViewModel = new ViewData();
}

Here is how ViewData is defined:

public class ViewData : INotifyPropertyChanged
{
    private string _FeedTitle;
    private RssItem _SelectedItem = null;
    private ObservableCollection<RssItem> _feedItems = new ObservableCollection<RssItem>();

    private const string MyRssfeed = "http://feeds.bbci.co.uk/news/rss.xml";

    public ViewData()
    {
        RssService.GetRssItems(
            MyRssfeed,
            (title, items) =>
            {
                App.Current.RootVisual.Dispatcher.BeginInvoke(() =>
                {
                    FeedTitle = title;
                    FeedItems = new ObservableCollection<RssItem>(items);
                });
            },
            (exception) =>
            {
                MessageBox.Show(exception.Message);
            },
            null);
    }

    public ObservableCollection<RssItem> FeedItems
    {
        get { return _feedItems; }
        set
        {
            if (_feedItems == value)
                return;
            _feedItems = value;
            NotifyPropertyChanged(this, new PropertyChangedEventArgs("FeedItems"));
        }
    }

    public string FeedTitle
    {
        get { return _FeedTitle; }
        set
        {
            if (_FeedTitle == value)
                return;
            _FeedTitle = value;
            NotifyPropertyChanged(this, new PropertyChangedEventArgs("FeedTitle"));
        }
    }

    public RssItem SelectedItem
    {
        get { return _SelectedItem; }
        set
        {
            if (_SelectedItem == value)
                return;
            _SelectedItem = value;
            NotifyPropertyChanged(this, new PropertyChangedEventArgs("SelectedItem"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(object sender, PropertyChangedEventArgs args)
    {
        if (PropertyChanged != null)
            PropertyChanged(sender, args);
    }
}

Once this is established, it's relatively easy to wire up both page's data context properties to App.ViewModel.

Last item was the scrolling and positioning of the selected item when navigating. When you select an item from the list page, the SelectedItem property of the shared ViewModel is bound to the SelectedItem property on the ListBox. After navigation to the details page, we have to find the selected item in the pivot and make it visible:

public PivotPage1()
{
    InitializeComponent();
    Loaded += (sender, e) =>
        {
            this.DataContext = App.ViewModel;
            var selectedItem = App.ViewModel.SelectedItem;
            var pi = ItemPivot.Items.First(p => p == selectedItem);
            ItemPivot.SelectedItem = pi;
        };
}

Setting the SelectedItem property of the Pivot control scrolls the pivot to the proper item and makes it visible.

The full sample is posted at http://chriskoenig.net/upload/imaged.zip if you want to see it in action.

If I got you correctly, you need to bind listbox in following way:

<ListBox ItemsSource="{Binding items}" SelectedItem="{Binding SelectedFeed, Mode=TwoWay}" />

And then bind Pivot in same way:

<Pivot ItemsSource="{Binding items}" SelectedItem="{Binding SelectedFeed, Mode=TwoWay}" />

Try the following for the pivot (based on Alex's code)

<Pivot ItemsSource="{Binding items}" SelectedItem="{Binding SelectedFeed, Mode=TwoWay}">
    <Pivot.ItemTemplate>
            <DataTemplate>
                <Image Source="{Binding Url}"/>
            </DataTemplate>
        </Pivot.ItemTemplate>
</Pivot>

It assumes on the pivot page DataContext there is the same object "items" providing access to all the feeditems, and a property SelectedFeed which (as Alex mentioned) supports INotifyPropertyChanged

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM