I am both a freshman in WP7 and c# development .I confused with listbox removing operate. I want to remove a item through a click event(remove item data and refresh UI).I've searched in website,and knew first resource should extend ObservableCollection, but How to do next?Who can give me a more detail example.
Here is my code MainPage.xaml.Example source download
<phone:PhoneApplicationPage x:Class="WPListBoxImage.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="clr-namespace:WPListBoxImage"
mc:Ignorable="d"
d:DesignWidth="480"
d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait"
Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.Resources>
<data:Products x:Key="productCollection" />
<data:PriceConverter x:Key="priceConvert" />
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot"
Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel"
Grid.Row="0"
Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle"
Text="PDSA"
Style="{StaticResource PhoneTextNormalStyle}" />
<TextBlock x:Name="PageTitle"
Text="Products"
Margin="9,-7,0,0"
Style="{StaticResource PhoneTextTitle1Style}" />
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<ListBox x:Name="lstData"
ItemsSource="{Binding Source={StaticResource productCollection}, Path=DataCollection}" SelectionChanged="lstData_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Margin="8"
VerticalAlignment="Top"
Source="{Binding Path=ImageUri}"
Width="100"
Height="100" />
<StackPanel>
<TextBlock Margin="8"
Width="250"
TextWrapping="Wrap"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Text="{Binding Path=ProductName}" />
<TextBlock Width="100"
Margin="8,0,8,8"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Text="{Binding Path=Price, Converter={StaticResource priceConvert}}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</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.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
namespace WPListBoxImage
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
}
private void lstData_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBoxItem lbi = ((sender as ListBox).SelectedItem as ListBoxItem);
//delete a item,what should to do next?
}
}
}
Products.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace WPListBoxImage
{
//a ObservableCollection<T>,
public class Products : ObservableCollection<Product>
{
public Products()
{
DataCollection = new ObservableCollection<Product>();
BuildCollection();
}
private const string IMG_PATH = "../Images/";
public ObservableCollection<Product> DataCollection { get; set; }
public ObservableCollection<Product> BuildCollection()
{
//DataCollection = new ObservableCollection<Product>();
DataCollection.Add(new Product("Haystack Code Generator for .NET", 799, IMG_PATH + "Haystack.jpg"));
DataCollection.Add(new Product("Fundamentals of N-Tier eBook", Convert.ToDecimal(19.95), IMG_PATH + "FundNTier_100.jpg"));
DataCollection.Add(new Product("Fundamentals of ASP.NET Security eBook", Convert.ToDecimal(19.95), IMG_PATH + "FundSecurity_100.jpg"));
DataCollection.Add(new Product("Fundamentals of SQL Server eBook", Convert.ToDecimal(19.95), IMG_PATH + "FundSQL_100.jpg"));
DataCollection.Add(new Product("Fundamentals of VB.NET eBook", Convert.ToDecimal(19.95), IMG_PATH + "FundVBNet_100.jpg"));
DataCollection.Add(new Product("Fundamentals of .NET eBook", Convert.ToDecimal(19.95), IMG_PATH + "FundDotNet_100.jpg"));
DataCollection.Add(new Product("Architecting ASP.NET eBook", Convert.ToDecimal(19.95), IMG_PATH + "ArchASPNET_100.jpg"));
DataCollection.Add(new Product("PDSA .NET Productivity Framework", Convert.ToDecimal(2500), IMG_PATH + "framework.jpg"));
return DataCollection;
}
}
}
Product.cs
using System;
namespace WPListBoxImage
{
public class Product
{
#region Constructors
public Product()
{
}
public Product(string name, decimal price, string imageUri)
{
this.ProductName = name;
this.Price = price;
this.ImageUri = imageUri;
}
#endregion
public string ProductName { get; set; }
public decimal Price { get; set; }
public string ImageUri { get; set; }
}
}
Here is app screenshot.
thank's for your patience.
Your Products class shouldn't inherit anything.
public class Products
Accessing all the items in your collection is done through the DataCollection property of the Product class. For example,
Products myProducts = new Products();
ObservableCollection<Product> myData = myProducts.DataCollection;
It also depends on how you want to use Products. You may be able to totally do away with this class and then do something like:
ObservableCollection<Product> Products = new ObservableCollection<Product>();
Products.Add(new Product("Haystack Code Generator for .NET", 799, IMG_PATH + "Haystack.jpg"));
// etc...
Firstly you need to obtain a reference to your product collection:
Products productCollection = this.Resources["productCollection"] as Products;
Then find the item that was clicked, this will be the DataContext of the ListBoxItem:
ListBoxItem lbi = ((sender as ListBox).SelectedItem as ListBoxItem);
Product product = lbi.DataContext as Product;
(although, I think that as your listbox is databound, the SelectedItem should be a Product instance. You can check this yourself in the debugger)
Then simply remove it, the ObservableCollection will ensure that the UI is updated:
productCollection.Remove(product);
Related
I'm building a mobileApp with Xamarin forms. My problem is that I cannot get GroupHeader. I checked all platforms and websites. I couldn't find any solution for my problem. My fist listview works well and at second listview I want to show my values with groupheaders. My .xaml and .cs codes and scroonshots are below. I successfully got my all values from web service. And My values are shown at second listview except group headers.
<ListView x:Name="listview" HasUnevenRows="True" SeparatorVisibility="Default"
GroupDisplayBinding="{Binding Key}"
IsGroupingEnabled="True" ItemsSource="{Binding GroupedList}"
CachingStrategy="RecycleElement" Margin="0,0,0,15">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell Height="50" >
<Label Text ="{Binding Key}" Margin="0,20,0,0" FontSize="Medium" TextColor="Gray" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid BackgroundColor="White" Margin="0,0,0,1" >
<Grid.RowDefinitions>
<RowDefinition Height="0.4*"/>
<RowDefinition Height="0.6*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding PayDeskName}" Grid.Row="0" HorizontalOptions="Start" VerticalTextAlignment="Center" FontAttributes="Bold" TextColor="Gray"/>
<Label Grid.Column="0" Text="{Binding CollectionType}" Grid.Row="1" HorizontalOptions="Start" VerticalTextAlignment="Center" FontAttributes="Bold" TextColor="Blue"/>
<Label Grid.Column="1" Text="{Binding CollectionAmount, StringFormat='{0:N}'}" Grid.Row="1" HorizontalOptions="End" VerticalOptions="Center" FontSize="Large" TextColor="Blue"></Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
--
using MunIS.Parameters;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
namespace MunIS.AccrumentCollection
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CollectionPage : ContentPage
{
public CollectionPage()
{
InitializeComponent();
}
public PayDeskBaseCollectionParameters[] CollectionList { get; set; }
public ObservableCollection<Grouping<string, PayDeskBaseCollectionParameters>> GroupedList { get; set; }
public IEnumerable<IGrouping<string, PayDeskBaseCollectionParameters>> CollectionTypeBasedGroupedList { get; set; }
async void GetCollectionList(object sender, EventArgs e)
{
activityStackLayout.IsVisible = true;
activityIndicator.IsRunning = true;
loadingTxt.IsVisible = true;
string queryIntervalStartDate = dtIntervalStart.Date.ToString("MM.dd.yyyy");
string queryIntervalFinishDate = dtIntervalFinish.Date.ToString("MM.dd.yyyy");
CollectionDetailQueryCriteriaParameters criteria = new CollectionDetailQueryCriteriaParameters();
criteria.CollectionDateStart = dtIntervalStart.Date;
criteria.CollectionDateFinish = dtIntervalFinish.Date;
ServiceCaller serviceCaller = new ServiceCaller();
CollectionList = await serviceCaller.ListPayDeskBasedCollections(criteria);
var groupedCollectionList = CollectionList.GroupBy(c => c.CollectionType).Select(
g => new
{
CollectionType = g.Key,
CollectionAmount = g.Sum(s => s.CollectionAmount)
});
GroupedList = new ObservableCollection<Grouping<string, PayDeskBaseCollectionParameters>>(CollectionList.GroupBy(c => c.PayDeskName)
.Select(k => new Grouping<string, PayDeskBaseCollectionParameters>(k.Key + "\t\t" + CollectionList
.Where(c => c.PayDeskName == k.Key)
.Sum(x => x.CollectionAmount).ToString("N"), k)));
listview1.ItemsSource = groupedCollectionList;
listview.ItemsSource = GroupedList;
activityIndicator.IsRunning = false;
loadingTxt.IsVisible = false;
activityStackLayout.IsVisible = false;
}
}
}
And this is my Grouping.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
namespace MunIS
{
public class Grouping<K, T> : ObservableCollection<T>
{
public K Key { get; set; }
public Grouping(K key, IEnumerable<T> items)
{
Key = key;
foreach (var item in items)
{
this.Items.Add(item);
}
}
}
}
See my Page I want to get groupheaders
I think you need to remove GroupDisplayBinding from your listview element.
<ListView x:Name="listview" HasUnevenRows="True" SeparatorVisibility="Default"
GroupDisplayBinding="{Binding Key}"
IsGroupingEnabled="True" ItemsSource="{Binding GroupedList}"
CachingStrategy="RecycleElement" Margin="0,0,0,15">
This property is mutually exclusive with GroupHeaderTemplate property.
Setting it will set GroupHeaderTemplate to null.
From the docs: https://learn.microsoft.com/en-us/dotnet/api/xamarin.forms.listview.groupdisplaybinding?view=xamarin-forms#remarks
This worked for me
remove the x:DataType attribute from the XAML. For some reason doing this for the overall page creates problems with templated controls that have their own context.
And as Jeroen Corteville said, you need to remove the GroupDisplayBinding aswell. The two do the same, but somehow works differently.
How can i deserialize this jsonx variable and put it on a longlistselector on windows phone?
Currently i can only echo one string with messagebox. i need key-value sets on a longlistselector.
edit: this is my answer http://pastebin.com/CcADHaab
here is my code
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 PhoneApp5.Resources;
using Newtonsoft.Json;
namespace PhoneApp5
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
string json = #"{
'Email': 'james#example.com',
'Active': true,
'CreatedDate': '2013-01-20T00:00:00Z'
}";
string jsonx = #"{
'Table1': [
{
'id': 0,
'item': 'item 0'
},
{
'id': 1,
'item': 'item 1'
}
]
}";
Account account = JsonConvert.DeserializeObject<Account>(json);
// Console.WriteLine(account.Email);
// james#example.com
MessageBox.Show(account.Email);
list.ItemsSource = new BookList();
}
}
public class BookList : List<Account>
{
public BookList()
{
}
}
public class Account
{
public string Email { get; set; }
public bool Active { get; set; }
public DateTime CreatedDate { get; set; }
// public IList<string> Roles { get; set; }
}
///////////////////////////
}
and my XAML
<phone:PhoneApplicationPage
x:Class="PhoneApp5.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: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">
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:LongListSelector Name="list">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding id}" />
<TextBlock Text=" ( " />
<TextBlock Text="{Binding item}" FontStyle="Italic" />
<TextBlock Text=" )" />
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
You need a class to represent your json:
public class MyClass
{
public string Id { get; set; }
public string Item { get; set; }
}
Set a ObservableCollection property in your Form:
public ObservableCollection<MyClass> MyClassCollection { get; set; }
and then set the MyClassCollection property to your Deserialized json
MyClassCollection = JsonConvert.DeserializeObject<ObservableCollection<MyClass>>(e.Result);
That way you're binding your class list to the LongListSelector Control in your XAML:
<phone:LongListSelector Name="list" ItemsSource="{Binding MyClassCollection}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding id}" />
<TextBlock Text=" ( " />
<TextBlock Text="{Binding item}" FontStyle="Italic" />
<TextBlock Text=" )" />
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
That should work.
I am using MVVM Light, Autofac for windows phone 7 and Autofac locator.
With autofac
http://www.nuget.org/packages/Autofac.Wp7
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
using MvvmLight1.Model;
using Autofac;
namespace MvvmLight1.ViewModel
{
public class ViewModelLocator
{
static ViewModelLocator()
{
var builder = new ContainerBuilder();
builder.RegisterType<MainViewModel>();
var container = builder.Build();
ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(container));
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
}
}
using Microsoft.Phone.Controls;
namespace MvvmLight1
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
var main = this.DataContext as MainPage; // will be null
}
}
}
<phone:PhoneApplicationPage x:Class="MvvmLight1.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ignore="http://www.ignore.com"
mc:Ignorable="d ignore"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait"
Orientation="Portrait"
d:DesignWidth="480"
d:DesignHeight="768"
shell:SystemTray.IsVisible="True"
DataContext="{Binding Main, Source={StaticResource Locator}}">
<!--LayoutRoot contains the root grid where all other page content is placed-->
<Grid x:Name="LayoutRoot"
Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel"
Grid.Row="0"
Margin="24,24,0,12">
<TextBlock x:Name="ApplicationTitle"
Text="{Binding ApplicationTitle}"
Style="{StaticResource PhoneTextNormalStyle}" />
<TextBlock x:Name="PageTitle"
Text="{Binding PageName}"
Margin="-3,-8,0,0"
Style="{StaticResource PhoneTextTitle1Style}" />
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentGrid"
Grid.Row="1">
<TextBlock Text="{Binding WelcomeTitle}"
Style="{StaticResource PhoneTextNormalStyle}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="40"
TextWrapping="Wrap"
TextAlignment="Center" />
</Grid>
</Grid>
</phone:PhoneApplicationPage>
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Autofac;
using Microsoft.Practices.ServiceLocation;
namespace MvvmLight1
{
public sealed class AutofacServiceLocator : ServiceLocatorImplBase
{
readonly IComponentContext _container;
public AutofacServiceLocator(IComponentContext container)
{
if (container == null)
throw new ArgumentNullException("container");
_container = container;
}
protected override object DoGetInstance(Type serviceType, string key)
{
return key != null ? _container.ResolveNamed(key, serviceType) : _container.Resolve(serviceType);
}
protected override IEnumerable<object> DoGetAllInstances(Type serviceType)
{
var enumerableType = typeof(IEnumerable<>).MakeGenericType(serviceType);
object instance = _container.Resolve(enumerableType);
return ((IEnumerable)instance).Cast<object>();
}
}
}
using GalaSoft.MvvmLight;
using MvvmLight1.Model;
namespace MvvmLight1.ViewModel
{
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
}
}
}
now the viewModel in my constructor of MainPage.cs will always be null.
When I just used SimpleIoc it was filled with the Main Object.
So, I found a way of creating RSS feed app for Windows Phone. It binds SyndicationFeed items into Listbox template. And it works great!
However, I wanted to make an app, that handles a bit different. I thought, that changing Listbox template into Pivot would be quite easy. The problem is, that instead of articles I get only "System.ServiceModel.Syndication.SyndicationItem".
I am out of ideas how to fix that, could anyone help me?
Xaml:
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Popup Name="myPopup" IsOpen="True" Width="Auto">
<ProgressBar Height="Auto" IsIndeterminate="True" Width="480" />
</Popup>
<controls:Pivot Name="FeedPivot" Loaded="loadFeed">
<controls:Pivot.Title>
<TextBlock FontSize="56"> Komorkomania </TextBlock>
</controls:Pivot.Title>
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<Grid>
<TextBlock>test1</TextBlock>
</Grid>
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.DataContext>
<DataTemplate>
<StackPanel>
<TextBlock>test</TextBlock>
<!--
<TextBlock FontWeight="Bold" FontSize="28" Name="feedTitle" TextWrapping="Wrap" Margin="12,0,0,0" HorizontalAlignment="Left" Foreground="{StaticResource PhoneAccentBrush}" Text="{Binding Title.Text, Converter={StaticResource RssTextTrimmer}}" Width="430" />
<TextBlock Name="feedSummary" FontSize="24" TextWrapping="Wrap" Margin="12,0,0,0" Text="{Binding Summary.Text, Converter={StaticResource RssTextTrimmer}}" Width="430" />
<TextBlock Name="feedPubDate" Foreground="{StaticResource PhoneSubtleBrush}" Margin="12,0,0,10" Text="{Binding PublishDate.DateTime}" Width="430" />
-->
</StackPanel>
</DataTemplate>
</controls:Pivot.DataContext>
</controls:Pivot>
</Grid>
Code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.IO;
using System.ServiceModel.Syndication;
using System.Xml;
using Microsoft.Phone.Tasks;
using Microsoft.Phone.Shell;
using System.ComponentModel;
using System.Windows.Controls.Primitives;
namespace KomorkomaniaRss
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
myPopup.IsOpen = true;
}
// Co robimy jak już w końcu się ściągnie?
private void webClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(e.Error.Message);
});
}
else
{
// Save the feed into the State property in case the application is tombstoned.
this.State["feed"] = e.Result;
UpdateFeedList(e.Result);
myPopup.IsOpen = false;
}
}
// This method determines whether the user has navigated to the application after the application was tombstoned.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
// First, check whether the feed is already saved in the page state.
if (this.State.ContainsKey("feed"))
{
// Get the feed again only if the application was tombstoned, which means the ListBox will be empty.
// This is because the OnNavigatedTo method is also called when navigating between pages in your application.
// You would want to rebind only if your application was tombstoned and page state has been lost.
if (FeedPivot.Items.Count == 0)
{
UpdateFeedList(State["feed"] as string);
}
}
}
// This method sets up the feed and binds it to our ListBox.
private void UpdateFeedList(string feedXML)
{
// Load the feed into a SyndicationFeed instance.
StringReader stringReader = new StringReader(feedXML);
XmlReader xmlReader = XmlReader.Create(stringReader);
SyndicationFeed feed = SyndicationFeed.Load(xmlReader);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
// Bind the list of SyndicationItems to our ListBox.
FeedPivot.ItemsSource = feed.Items;
});
}
public void feedLoader()
{
myPopup.IsOpen = true;
WebClient webClient = new WebClient();
webClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClient_DownloadStringCompleted);
webClient.DownloadStringAsync(new System.Uri("http://komorkomania.pl/feed/rss2"));
}
private void runBrowser(object sender)
{
ListBox listBox = sender as ListBox;
if (listBox != null && listBox.SelectedItem != null)
{
// Get the SyndicationItem that was tapped.
SyndicationItem sItem = (SyndicationItem)listBox.SelectedItem;
// Set up the page navigation only if a link actually exists in the feed item.
if (sItem.Links.Count > 0)
{
// Get the associated URI of the feed item.
Uri uri = sItem.Links.FirstOrDefault().Uri;
// Create a new WebBrowserTask Launcher to navigate to the feed item.
// An alternative solution would be to use a WebBrowser control, but WebBrowserTask is simpler to use.
WebBrowserTask webBrowserTask = new WebBrowserTask();
webBrowserTask.Uri = uri;
webBrowserTask.Show();
}
}
}
// The SelectionChanged handler for the feed items
private void feedListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
runBrowser(sender);
}
private void loadFeed(object sender, RoutedEventArgs e)
{
feedLoader();
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
}
}
}
}
There are some "leftovers" for handling another actions. Please ignore them, I didn't get to it yet. The biggest focus is to make it show text after app is loaded.
I bealive that I fixed that. There was a problem with Pivot concept. This is how I fixed that:
<controls:Pivot Name="FeedPivot" Loaded="loadFeed" ScrollViewer.VerticalScrollBarVisibility="Visible" Tap="feedPivotTap" Margin="0,88,0,0" LoadedPivotItem="getPivotItem">
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock FontWeight="Bold" FontSize="28" Name="feedTitle" TextWrapping="Wrap" Margin="12,0,0,0" HorizontalAlignment="Left" Foreground="#FF5DBA00" Text="{Binding Title.Text, Converter={StaticResource RssTextTrimmer}}" Width="430" />
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate>
<ScrollViewer>
<StackPanel>
<TextBlock Name="feedSummary" FontSize="24" TextWrapping="Wrap" Margin="12,0,0,0" Text="{Binding Summary.Text, Converter={StaticResource RssTextTrimmer}}" Width="430" />
<TextBlock Name="feedPubDate" Foreground="{StaticResource PhoneSubtleBrush}" Margin="12,0,0,10" Text="{Binding PublishDate.DateTime}" Width="430" />
</StackPanel>
</ScrollViewer>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
I'm trying to develop a simple WP7 app that queries a REST feed which produces a XML file. Depending on the query, the feed can generate many different XML files, but I am having problems with the most basic one.
The XML I am trying to display in a ListBox looks like;
<subsonic-response status="ok" version="1.1.1">
</subsonic-response>
or
<subsonic-response status="ok" version="1.1.1">
<license valid="true" email="foo#bar.com" key="ABC123DEF" date="2009-09-03T14:46:43"/>
</subsonic-response>
I've tried following several examples from MSDN and other source but I can't seem to wrap my head around it. The URL that I'm using works because it displays the correct information when entered into a browser, but for some reason isn't displayed in the ListBox.
Here is the code I am currently using;
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Xml.Linq;
namespace RESTTest
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
string requestString =
"http://WEBSITE/rest/{0}.view?u=USERNAME&p=PASSWORD&v=1.8.0&c=RestTest";
string UriNoAppId =
"http://WEBSITE/rest/{0}.view?u=USERNAME&p=PASSWORD&v=1.8.0&c=RestTest";
public MainPage()
{
InitializeComponent();
List<string> searchTopics = new List<string>() { "ping", "getLicense" };
comboBox1.DataContext = searchTopics;
comboBox1.SelectedIndex = 0;
// Create the WebClient and associate a handler with the OpenReadCompleted event.
wc = new WebClient();
wc.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
}
// Call the topic service at the Bing search site.
WebClient wc;
private void CallToWebService()
{
// Call the OpenReadAsyc to make a get request, passing the url with the selected search string.
wc.OpenReadAsync(new Uri(String.Format(requestString, comboBox1.SelectedItem.ToString())));
}
void wc_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
XElement resultXml;
// You should always check to see if an error occurred. In this case, the application
// simply returns.
if (e.Error != null)
{
return;
}
else
{
XNamespace web = "http://subsonic.org/restapi";
try
{
resultXml = XElement.Load(e.Result);
// Search for the WebResult node and create a SearchResults object for each one.
var searchResults =
from result in resultXml.Descendants(web + "WebResult")
select new SearchResult
{
// Get the Title, Description and Url values.
Title = result.Element(web + "version").Value,
Url = result.Element(web + "status").Value
};
// Set the data context for the listbox to the results.
listBox1.DataContext = searchResults;
textBox1.DataContext = searchResults;
}
catch (System.Xml.XmlException ex)
{
textBlock2.Text = ex.Message;
}
}
}
private void button1_Click(object sender, RoutedEventArgs e)
{
CallToWebService();
}
// Update the textblock as the combo box selection changes.
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
uriTextBlock.DataContext = string.Format(UriNoAppId, e.AddedItems[0]);
}
}
// Simple class to hold the search results.
public class SearchResult
{
public string Title { get; set; }
public string Url { get; set; }
}
}
XAML
<phone:PhoneApplicationPage
x:Class="RESTTest.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="False">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.Resources>
<Style x:Key="ComboBoxItemStyle" TargetType="ComboBoxItem" >
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="LightGray"/>
</Style>
<Style x:Key="ComboBoxStyle" TargetType="ComboBox" >
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Background" Value="Gray"/>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="REST CLIENT"
Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="Subsonic"
Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"
Height="99" Width="453" />
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Margin="12,139,12,0" Grid.RowSpan="2">
<Button Content="Search!" Height="89" HorizontalAlignment="Left"
Margin="264,140,0,0" Name="button1"
VerticalAlignment="Top" Width="189" Click="button1_Click" />
<ComboBox Height="50" Style="{StaticResource ComboBoxStyle}"
HorizontalAlignment="Left" Margin="6,159" Name="comboBox1"
ItemContainerStyle="{StaticResource ComboBoxItemStyle}"
VerticalAlignment="Top" Width="235" ItemsSource="{Binding}"
SelectionChanged="comboBox1_SelectionChanged" />
<TextBlock Height="36" HorizontalAlignment="Left" Margin="12,120"
Name="textBlock2" Text="Search Topic:" VerticalAlignment="Top" width="121" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="12,1,0,0"
Name="textBlock3"
Text="URI:" VerticalAlignment="Top" />
<TextBlock Height="86" HorizontalAlignment="Left" Margin="6,28"
Name="uriTextBlock" TextWrapping="Wrap" Text="{Binding}"
VerticalAlignment="Top" Width="447" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="12,242,0,0"
Name="textBlock5"
Text="Results:" VerticalAlignment="Top" />
<ListBox Height="169" HorizontalAlignment="Left" Margin="6,271,0,0" Name="listBox1"
VerticalAlignment="Top" Width="444" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="{StaticResource PhoneForegroundBrush}" Width="418"
BorderThickness="2" Margin="2">
<StackPanel>
<TextBlock Text="{Binding Path=Title}" TextWrapping="Wrap" />
<TextBlock Text="{Binding Path=Url}" TextWrapping="Wrap"/>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox Height="209" HorizontalAlignment="Left" Margin="6,446,0,0" Name="textBox1" Text="" VerticalAlignment="Top" Width="444" IsEnabled="True" IsReadOnly="True" />
</Grid>
</Grid>
</phone:PhoneApplicationPage>
The code is currently designed so you can choose to display either one of the example XML files, but nothing is displayed in the Listbox at all.
Any advice would be appreciated. Thank you.
See if the following helps:
string fakeXML = "<subsonic-response status='ok' version='1.1.1'>" +
"<license valid='true' email='foo#bar.com' " +
" key='ABC123DEF' date='2009-09-03T14:46:43'/>" +
"</subsonic-response>";
XDocument doc = XDocument.Parse(fakeXML);
var searchResults = from xe in doc.Elements("subsonic-response")
select new SearchResult
{
Title = xe.Attribute("version").Value,
Url = xe.Attribute("status").Value
};
listBox1.DataContext = searchResults;
textBox1.DataContext = searchResults;