Hi everybody i have a little problem and i hope that somebody could help me
I have a json url that gives me the data like this :
[
{
"nom": "fofo",
"appGuid": "79fa058b-395a-438d-b66f-d751faea82e0"
},
{
"nom": "fifi",
"appGuid": "8b6bfcdb-d286-46e2-889e-0168a782323f"
},
{
"nom": "toto",
"appGuid": "65DE39E7-0130-4836-BBD3-7051574018B6"
},
{
"nom": "titi",
"appGuid": "66DE39E7-0130-4836-BBD3-7051574018B6"
}
]
My class :
public class ListApplication
{
public string nom { get; set; }
public string appGuid { get; set; }
}
I have a listpicker :
I want to bind just the element “nom” in the listpicker, I’ve tried this methods but nothing works:
The first method:
WebClient visio = new WebClient();
visio.DownloadStringCompleted += new DownloadStringCompletedEventHandler(vision_DownloadStringCompleted);
visio.DownloadStringAsync(new Uri("https://......... "));
void vision_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
return;
JArray jArray = JArray.Parse(e.Result);
List<ListApplication> apps = new List<ListApplication>();
for (int i = 0; i < jArray.Count; i++)
{
JObject app = (JObject)jArray[i];
apps.Add(new ListApplication { nom = (string)app["nom"], appGuid = (string)app["appGuid"] });
this.Application.ItemsSource = apps;
//
}
The second method:
public Appli()
{
InitializeComponent();
this.Type_info.ItemsSource = Action;
this.Periode.ItemsSource = Per;
var w = new WebClient();
Observable.FromEvent<DownloadStringCompletedEventArgs>(w, "DownloadStringCompleted").Subscribe(r =>
{
var deserialized =
JsonConvert.DeserializeObject<List<ListApplication>>(r.EventArgs.Result);
Application.ItemsSource = deserialized;
});
w.DownloadStringAsync(
new Uri("https://........"));
}
And then i added Itemsource= {Binding nom} in the listpicker in XAML
Any help I’ll be so appreciative ,and sorry for my English
I believe you are asking that the binding is not taking effect. That is, you cannot see the data in your list.
If that is the case, are you setting the DataContext of the list picker to the List? Also, it seems that you would expect the content of the list picker to change when you receive more JSON data. So, if that is the case i would advise you to use an ObservableCollection instead of a List.
It's ok i found the answer ,i've used this with the second method
<toolkit:ListPicker x:Name="listPicker" Header="Application" >
<toolkit:ListPicker.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding nom}" />
</StackPanel>
</DataTemplate>
</toolkit:ListPicker.ItemTemplate>
</toolkit:ListPicker>
Related
I noted something wrong, either it's from me or a bug when experimenting with .Net MAUI.
I have an ObservableCollection property :
public ObservableCollection<LotoModel> Lotteries { get; set; } = new();
and an ObservableProperty (using community mvvm toolkit) :
[ObservableProperty]
public string _lotteriesCount = "A";
When ever I click/touch a Button I load my Lotteries collection. (tested with an hard coded 4 static LotoModel items) :
static GridModel _testGM1 = new GridModel { Name = "TEST Grid #1", Start = 0, End = 10, NumberOfDraw = 2 };
static GridModel _testGM2 = new GridModel { Name = "TEST Grid #2", Start = 0, End = 20, NumberOfDraw = 5 };
static GridModel _testGM3 = new GridModel { Name = "TEST Grid #3", Start = 0, End = 30, NumberOfDraw = 8 };
static GridModel _testGM4 = new GridModel { Name = "TEST Grid #4", Start = 0, End = 50, NumberOfDraw = 10 };
static LotoModel _testLM1 = new LotoModel { Name = "TEST Lottery #1", IsFavorite = true, Grids = new ObservableCollection<GridModel> { _testGM1, _testGM2 } };
static LotoModel _testLM2 = new LotoModel { Name = "TEST Lottery #2", IsFavorite = false, Grids = new ObservableCollection<GridModel> { _testGM3, _testGM4 } };
And the Button command Task :
async Task GetLotteriesAsync()
{
if (IsBusy)
return;
try
{
IsBusy = true;
_buttonCount++;
LotteriesCount = _buttonCount.ToString();
if (Lotteries.Count != 0)
Lotteries.Clear();
Lotteries.Add(_testLM1);
Lotteries.Add(_testLM2);
Lotteries.Add(_testLM1);
Lotteries.Add(_testLM2);
}
catch (Exception e)
{
Log.Error(e, "Error while trying to get our lotteries");
await Application.Current.MainPage.DisplayAlert("Error!", e.Message, "OK");
}
finally
{
IsBusy = false;
}
}
So each time I touch/click my Button, LotteriesCount string property get's updated with a static int counter field value :
static int _buttonCount = 0;
That is OK.
Now I also update this property via this CollectionChangedEventHandler :
public LotteriesVM(LotteryService lotteryService)
{
GetLotteriesCommand = new Command(async () => await GetLotteriesAsync());
Lotteries.CollectionChanged += LotteriesChangedMethod;
}
private void LotteriesChangedMethod(object sender, NotifyCollectionChangedEventArgs e)
{
LotteriesCount = _lotteriesCount + "_" + Lotteries.Count.ToString();
}
And now here the unexpected behavior : The label only update the counter part of it string property, the remaining "_1_2_3_4" added in the handler doesn't get updated in UI.
Note that I'm using a Android Pixel 5 emulator from VS 17.3 preview.
And I also noted that if I force orientation of the emulated android device, then the Label is updated !
Even more, if I force a XAML MinimalWidthRequest="200" for my Label, then it is correctly updated now !
<!-- without MinimumWidthRequest, the label update only after forcing a screen orientation-->
<Label Text="{Binding LotteriesCount}" MinimumWidthRequest="200" HorizontalOptions="Center" FontAttributes="Bold" FontSize="22" TextColor="OrangeRed"/>
So am I doing something wrong or it is a bug ? Thank you.
I have a problem. I am using a CollectionView that receives data in a custom ViewModel from my webpage as long as it returns a JSON with the data. Once the Offset in the call >= num_of_rows the webpage prints "Nothing". If that happens I set a boolean HitBottomOfList = true;. Now everytime when it wants to do a webcall it checks if the HitBottomOfList == false.
Full Code
ViewModel:
public class TemplateListViewModel
{
public double WidthHeight { get; set; }
public ICommand LoadTemplates => new Command(LoadTemplateList);
public int CurrentTemplateCountReceived;
public bool HitBottomOfList = false;
public ObservableCollection<TemplateSource> sourceList { get; set; }
public TemplateListViewModel()
{
CurrentTemplateCountReceived = 0;
sourceList = new ObservableCollection<TemplateSource>();
var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
var width = mainDisplayInfo.Width;
var density = mainDisplayInfo.Density;
var ScaledWidth = width / density;
WidthHeight = (ScaledWidth / 2);
loadingTemplates += onLoadingTemplates;
LoadTemplateList();
}
private event EventHandler loadingTemplates = delegate { };
private void LoadTemplateList()
{
loadingTemplates(this, EventArgs.Empty);
}
private async void onLoadingTemplates(object sender, EventArgs args)
{
if (HitBottomOfList == false)
{
List<Template> templateList = await App.RestService.GetTemplates(App.User, CurrentTemplateCountReceived);
if (templateList != null)
{
foreach (var template in templateList)
{
ImageSource source = ImageSource.FromUri(new Uri("mysite.org/myapp/" + template.FileName));
TemplateSource templateSource = new TemplateSource { Id = template.Id, Source = source, WidthHeight = WidthHeight, FileName = template.FileName };
sourceList.Add(templateSource);
}
CurrentTemplateCountReceived = sourceList.Count;
}
else
{
HitBottomOfList = true;
}
}
}
}
The XAML:
<CollectionView ItemsSource="{Binding sourceList}" RemainingItemsThreshold="6"
RemainingItemsThresholdReachedCommand="{Binding LoadTemplates}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<ff:CachedImage
Source="{Binding Source}"
VerticalOptions="Center"
HorizontalOptions="Center"
WidthRequest="{Binding WidthHeight}"
HeightRequest="{Binding WidthHeight}">
<ff:CachedImage.GestureRecognizers>
<TapGestureRecognizer Tapped="imgTemplate_Clicked" />
</ff:CachedImage.GestureRecognizers>
</ff:CachedImage>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
And finally the WebCall that I do:
public async Task<List<Template>> GetTemplates(User user, int offset)
{
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("un", user.Username));
postData.Add(new KeyValuePair<string, string>("pw", user.Password));
postData.Add(new KeyValuePair<string, string>("offset", offset.ToString()));
var content = new FormUrlEncodedContent(postData);
var weburl = "mysite.org/myapp/get_templates.php";
List<Template> response = await PostResponseTemplates(weburl, content);
return response;
}
public async Task<List<Template>> PostResponseTemplates(string weburl, FormUrlEncodedContent content)
{
var response = await client.PostAsync(weburl, content);
var json = await response.Content.ReadAsStringAsync();
if (json != "Nothing")
{
var jObject = JObject.Parse(json);
var templatePropery = jObject["Templates"] as JArray;
List<Template> templateList = new List<Template>();
foreach (var property in templatePropery)
{
List<Template> propertyList = new List<Template>();
propertyList = JsonConvert.DeserializeObject<List<Template>>(property.ToString());
templateList.AddRange(propertyList);
}
var sourcePropery = (JObject)jObject["Source"];
foreach (var property in sourcePropery)
{
string tempplateSource = property.Value.Value<string>();
App.TemplateSource = tempplateSource;
}
return templateList;
}
else
{
ErrorMessage = json;
return default(List<Template>);
}
}
Now the problem is that when it does trigger the RemainingItemsThresholdReachedCommand="{Binding LoadTemplates}"
it executes the command a lot of times after each other, thinking it needs more data, while there is already a command to get new data. This causes the app to get new data with the same offset a few times, so the app will the same data in the CollectionView a lot of times.
I want the app to call the webpage 1 time to receive more images and just let it load, without asking again for new data, so the duplicates in the list will disappear.
So how can I make sure it only asks the data once, when almost hit the bottom?
Update
Using #Jason his code the following is going wrong:
When the code goes through the MyHandler, it fires the LoadTemplateList(); But jumps to the handling = false; before it finished, so the next command is allowed to start, without finishing the other. Any idea how to wait for the method to finish?
use a bool to track if you are already handling the event and ignore any new ones
bool handling = false;
public void MyHandler()
{
// already handling an event, ignore the new one
if (handling) return;
handling = true;
// process event here
handling = false;
}
I'm new to both C# and Windows App development, my comes experience mostly in python but I'm trying to challenge myself to learn something new.
I've been practicing/learning c# by making windows store apps, and after doing some WinJS/HTML5 tutorials I started on this tutorial: http://msdn.microsoft.com/en-us/library/windows/apps/br211380.aspx
I've completed the tutorial (including modifying the instructions for 8.1 apps since the tutorial is behind. I'm now trying to adapt my application to handle other types of data.
I'm attempting to pull all of the media:image tags from each item in a post so that I can display them. This is the structure of my XML data from an RSS feed.
<item>
<title>Post with photos</title>
<link>http://website.com/2014/07/23/post-1//</link>
<comments>http://website.com/2014/07/23/post-1/#comments</comments>
<pubDate>Wed, 23 Jul 2014 15:45:02 +0000</pubDate>
<dc:creator><![CDATA[Author]]></dc:creator>
<category><![CDATA[Post]]></category>
<guid isPermaLink="false">http://www.website.com/p?1</guid>
<description><![CDATA[description here]]></description>
<wfw:commentRss>http://www.website.com/post/1/feed/</wfw:commentRss>
<slash:comments>0</slash:comments>
<enclosure type="image/jpeg" length="1" url="http://0.gravatar.com/avatar/" />
<media:thumbnail url="http://www.website.com/thumbnail_urle1406130272443.jpg?w=500" />
<media:content url="http://0.gravatar.com/avatar/" medium="image">
<media:category>author</media:category>
</media:content>
<media:content url="http://www.website.com/post/1/233-e1406130272443.jpg" medium="image">
<media:title>image-23</media:title>
</media:content>
<media:content url="http://www.website.com/post/1/163.jpg" medium="image">
<media:title>image-16</media:title>
</media:content>
<media:content url="http://www.website.com/post/1/73.jpg" medium="image">
<media:title>bimage-7</media:title>
</media:content>
</item>
I implemented this in HTML5/JS and when I did I used this method:
var thumb = post.querySelector(
"thumbnail").attributes.getNamedItem("url").textContent;
var postImages = post.querySelectorAll("content");
var ImageList = [];
for (var imgIndex = 1; imgIndex < postImages.length; imgIndex++) {
var imgHTML = "<img src='" + postImages[imgIndex].attributes.getNamedItem("url").textContent + "'</img><br/>";
var ImageList = ImageList += imgHTML;
}
But naturally.. that won't do in C#. I have looked at these thread in SO: Get media elements from RSS using SyndicationFeed as well as the one linked inside of it and they don't work for me. When I try to use
var elements = rss.Feed.Items.SelectMany(s => s.ElementExtensions.Select(x => x.GetObject().Value));
I do not have a GetObject method available when I put it all together using my code. Here is my current Data model.
private async Task<FeedData> GetFeedAsync(string feedUriString)
{
Windows.Web.Syndication.SyndicationClient client = new SyndicationClient();
Uri feedUri = new Uri(feedUriString);
try
{
SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri);
// This code is executed after RetrieveFeedAsync returns the SyndicationFeed.
// Process the feed and copy the data you want into the FeedData and FeedItem classes.
FeedData feedData = new FeedData();
if (feed.Title != null && feed.Title.Text != null)
{
feedData.Title = feed.Title.Text;
}
if (feed.Subtitle != null && feed.Subtitle.Text != null)
{
feedData.Description = feed.Subtitle.Text;
}
if (feed.Items != null && feed.Items.Count > 0)
{
// Use the date of the latest post as the last updated date.
feedData.PubDate = feed.Items[0].PublishedDate.DateTime;
foreach (SyndicationItem item in feed.Items)
{
FeedItem feedItem = new FeedItem();
if (item.Title != null && item.Title.Text != null)
{
feedItem.Title = item.Title.Text;
}
if (item.PublishedDate != null)
{
feedItem.PubDate = item.PublishedDate.DateTime;
}
if (item.Authors != null && item.Authors.Count > 0)
{
feedItem.Author = item.Authors[0].Name.ToString();
}
// Handles RSS / Atom Feed differences..
if (feed.SourceFormat == SyndicationFormat.Atom10)
{
if (item.Content != null && item.Content.Text != null)
{
feedItem.Content = item.Content.Text;
}
if (item.Id != null)
{
feedItem.Link = new Uri(item.Id);
}
}
else if (feed.SourceFormat == SyndicationFormat.Rss20)
{
if (item.Summary != null && item.Summary.Text != null)
{
feedItem.Content = item.Summary.Text;
}
if (item.Links != null && item.Links.Count > 0)
{
feedItem.Link = item.Links[0].Uri;
}
}
feedData.Items.Add(feedItem);
}
}
return feedData;
}
catch (Exception)
{
return null;
}
}
I've tried setting breakpoints and looking at the item data in my RSS2.0 syndication handler, and I can see var media = item.ElementExtensions; has an accurate acount of all the element extensions in my post, and the title of them. (NodeName "content", NodeValue is the "title" from the element. but no URI for the url tag..)
I am looking for some way to integrate some way of getting these media:content, media thumbnail, etc, into a list so that I can assemble them and use them for HTML content later in my app.
Any advice would be appreciated!
edit:
More of my code..
public class FeedData
{
public string Title { get; set; }
public string Description { get; set; }
public DateTime PubDate { get; set; }
public Uri Image { get; set; }
private List<FeedItem> _Items = new List<FeedItem>();
public List<FeedItem> Items
{
get
{
return this._Items;
}
}
}
// Holds info for a single blog post
public class FeedItem
{
public string Title { get; set; }
public string Author { get; set; }
public string Content { get; set; }
public DateTime PubDate { get; set; }
public Uri Link { get; set; }
}
// Holds a collection of blog feeds (FeedData), and contains methods needed to retrieve
// the feeds
public class FeedDataSource
{
private ObservableCollection<FeedData> _Feeds = new ObservableCollection<FeedData>();
public ObservableCollection<FeedData> Feeds
{
get
{
return this._Feeds;
}
}
public async Task GetFeedsAsync()
{
Task<FeedData> feed1 =
GetFeedAsync("http://url.com/feed");
Task<FeedData> feed2 =
GetFeedAsync("http://url.com/feed");
...
...
this.Feeds.Add(await feed1);
...
...
...
this.Feeds.Add(await feed15);
}
I'm not familiar with phone apps but you'd be putting this data into a repeater of some sort, data grid, etc.,
yes? Not being familiar with the Task generic object I'll still hazard a guess that you could use the C# key-value pair class with the List, then in this object in a Repeater, Grid, directly. I believe any object that implements IEnumerable (which List should) can be iterated over with a KeyValuePair
Let me know a bit more of what you want to do. It seems to me a
foreach KeyValuePair KVP in ListObject
{
//Access KVP.key and values with your code here ...
}
A more clear example is using a KVP to iterate over a dictionary object:
foreach (KeyValuePair<string, string> entry in dictTestEasement)
{
builder.RowFormat.Height = 0.2; //force row height by text font by setting height small
builder.InsertCell();
builder.Font.Bold = true;
builder.InsertHtml(entry.Key);
builder.Font.Bold = false;
builder.InsertCell();
builder.InsertHtml(entry.Value);
}
The builder in this case is a global object for document construction (Aspose Words Object) -- it's constructing a Word document. Don't be thrown by it.
seems straightforward ... I've used such solutions before and believe that's what you're fishing for.
SyndicationItem has a GetXMLDocument method that takes a SourceFormat (like Rss20) and then generates an XML string that you can parse using GEtElementsByTagName (or ID). Once you have that you can iterate through duplicate tags in a loop and use Attributes.GetNamedItem() to grab named attributes of an XML tag. It seems that 'media' is lopped off when exploring the xml for media:content tags in Rss20 format, so all thats necessary is content to search for.
var allImages = item.GetXmlDocument(feed.SourceFormat).GetElementsByTagName("content");
foreach (var s in allImages)
{
Debug.WriteLine(s.Attributes.GetNamedItem("url").InnerText;)
}
I have an WP C# app built on the Local Database Sample (http://code.msdn.microsoft.com/wpapps/Local-Database-Sample-57b1614c).
The main page displays a list of items from the xml database, which by default shows items in the order created. I would like to be able to offer at least one other sort order - either reversed or sorted by "Subject". Unfortunately Listbox.Sort is not supported in WP.
I have tried various answers found on here, including attempting to sort the xml file itself, but for reasons beyond my level of coding they do not change the order of the list (see Templatestorage) however i suspect it is due to improper implementation.
The code for the listbox is:
<ListBox x:Name="Templates" SelectionChanged="OnSelectionChanged" Background="Transparent" Style="{StaticResource ListBoxStyle1}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Grid.Row="2" Text="{Binding Subject}" Style="{StaticResource PhoneTextLargeStyle}" Margin="12,2" />
<TextBlock Grid.Row="2" Text="{Binding DT}" Style="{StaticResource PhoneTextSmallStyle}" Margin="12,5" />
<Rectangle Height="1" Margin="23,7,50,7" Fill="{StaticResource PhoneAccentBrush}" MinWidth="400" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The c# is:
public partial class MainPage
{
private readonly TemplateStorage storage = new TemplateStorage();
public MainPage()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Templates.ItemsSource = storage.GetItems();
this.NavigationService.RemoveBackEntry();
}
private void PhoneApplicationPage_GotFocus(object sender, RoutedEventArgs e)
{
Templates.ItemsSource = storage.GetItems();
}
}
The Templatestorage, which shows the various attempts at sorting (commented out) is:
public class TemplateStorage
{
private IList<NanoMemoTemplate> templates;
private const string Filename = "template-list.xml";
protected IList<NanoMemoTemplate> Templates
{
get
{
return templates ?? (templates = LoadTemplates().ToList());
}
set
{
templates = value;
}
}
protected IEnumerable<NanoMemoTemplate> LoadTemplates()
{
using(var applicationStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
if(!applicationStorage.FileExists(Filename))
return Enumerable.Empty<NanoMemoTemplate>();
using(var speedListFile = applicationStorage.OpenFile(Filename, FileMode.Open, FileAccess.Read))
{
var document = XDocument.Load(speedListFile);
return from t in document.Root.Elements("template")
select new NanoMemoTemplate
{
Id = new Guid(t.Attribute("id").Value),
Subject = t.Attribute("subject").Value,
Body = t.Attribute("body").Value,
DT = t.Attribute("dateCreated").Value,
};
}
}
}
//public IEnumerable<NanoMemoTemplate> SortTemplates()
//{
// using (var applicationStorage = IsolatedStorageFile.GetUserStoreForApplication())
// {
// if (!applicationStorage.FileExists(Filename))
// return Enumerable.Empty<NanoMemoTemplate>();
// using (var speedListFile = applicationStorage.OpenFile(Filename, FileMode.Open, FileAccess.ReadWrite))
// {
// var documentSort = XDocument.Load(speedListFile);
// XDocument datatemp = new XDocument(documentSort);
// var subjectSort = from p in datatemp.Descendants("template")
// orderby (string)p.Attribute("subject")
// select p;
// //var subjectSort = datatemp.Elements("template").OrderBy(p => (string)p.Attribute("subject")).ToArray();
// string cleanDataDump = subjectSort.ToString();
// MessageBox.Show(cleanDataDump);
// documentSort.Descendants("template").Remove();
// documentSort.Element("template").Add(subjectSort);
// return Templates;
// }
// }
//}
//public IEnumerable<NanoMemoTemplate> SortItems()
//{
// //Sort XML order so order is saved
// using (var applicationStorage = IsolatedStorageFile.GetUserStoreForApplication())
// {
// if (!applicationStorage.FileExists(Filename))
// return Enumerable.Empty<NanoMemoTemplate>();
// using (var speedListFile = applicationStorage.OpenFile(Filename, FileMode.Open, FileAccess.ReadWrite))
// {
// var documentSort = XDocument.Load(speedListFile);
// IEnumerable<string> codes = from code in documentSort.Elements("template")
// let subs = (string)code.Element("subject")
// orderby subs
// select subs;
// //return Templates as per usual as sorting is done at DB level
// return from t in documentSort.Root.Elements("template")
// select new NanoMemoTemplate
// {
// Id = new Guid(t.Attribute("id").Value),
// Subject = t.Attribute("subject").Value,
// Body = t.Attribute("body").Value,
// DT = t.Attribute("dateCreated").Value,
// };
// }
// }
//}
public IEnumerable<NanoMemoTemplate> GetItems()
{
return Templates;
}
public void Save(NanoMemoTemplate template)
{
Templates.Add(template);
}
public void Delete(NanoMemoTemplate template)
{
Templates.Remove(template);
}
//public void Sort(NanoMemoTemplate template)
//{
// IList<NanoMemoTemplate> list = new List<NanoMemoTemplate>();
// IEnumerable<NanoMemoTemplate> sortedEnum = list.OrderBy(Templates => Templates.Subject);
// IList<NanoMemoTemplate> sortedList = sortedEnum.ToList();
//}
public void SaveChanges()
{
using(var applicationStorage = IsolatedStorageFile.GetUserStoreForApplication())
using(var speedListFile = applicationStorage.OpenFile(Filename, FileMode.Create, FileAccess.Write))
{
var document = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
new XElement("templates",
from t in Templates
select new XElement("template",
new XAttribute("id", t.Id),
new XAttribute("subject", t.Subject),
new XAttribute("body", t.Body),
new XAttribute("dateCreated", t.DT))));
document.Save(speedListFile);
}
}
}
Instead of having to set Templates.ItemsSource = storage.GetItems(); in your code, you can keep an ObservableCollection (or other enumerable type) as a class-level variable:
//StorageTemplates should be a class-level variable
ObservableCollection<NanoMemoTemplate> StorageTemplates;
//You can assign the value to StorageTemplates when the page loads
StorageTemplates = storage.GetItems();
You would then apply an ItemsSource="{Binding StorageTemplates}" data binding to your ListBox in XAML. (See this for more info on binding)
<ListBox x:Name="Templates" ItemsSource="{Binding StorageTemplates, UpdateSourceTrigger="PropertyChanged"}" SelectionChanged="OnSelectionChanged" Background="Transparent" Style="{StaticResource ListBoxStyle1}" >
<ListBox.ItemTemplate>
....
</ListBox.ItemTemplate>
</ListBox>
Then you can use the built-in Sort methods of the ObservableCollection to set your sort order for the items. You may need to implement a Property Changed handler, you can check this tutorial for more information.
I have created a WCF service and publish into the cloud in http://kailun92wcf.cloudapp.net/Service1.svc. How can I use the method of getSearchCoords to get all the names out and display it into a list ? One example tested result is display below.
"{\"SearchResults\":[{\"PageCount\":\"1\"},{\"SEARCHVAL\":\"ORCHARD 22\",\"CATEGORY\":\"Buildin" +
"g\",\"X\":\"29483.4267\",\"Y\":\"31269.938\"},{\"SEARCHVAL\":\"ORCHARD BEL AIR\",\"CATEGORY\":\"" +
"Building\",\"X\":\"27071.2616\",\"Y\":\"31629.2465\"},{\"SEARCHVAL\":\"ORCHARD BOULEVARD\",\"C" +
"ATEGORY\":\"CATC\",\"X\":\"27614.8046\",\"Y\":\"31857.4392\"},{\"SEARCHVAL\":\"ORCHARD BUILDIN" +
"G\",\"CATEGORY\":\"Building\",\"X\":\"28449.6799\",\"Y\":\"31527.587\"},{\"SEARCHVAL\":\"ORCHARD" +
" BUILDING (FRIENDLY BUILDINGS)\",\"CATEGORY\":\"Community\",\"X\":\"28448.5715\",\"Y\":\"315" +
"26.146\"},{\"SEARCHVAL\":\"ORCHARD BUILDING (WIRELESS HOTSPOTS)\",\"CATEGORY\":\"Recreat" +
"ion\",\"X\":\"28448.3426\",\"Y\":\"31525.9693\"},{\"SEARCHVAL\":\"ORCHARD CENTRAL\",\"CATEGORY" +
"\":\"Building\",\"X\":\"28709.3453\",\"Y\":\"31452.9157\"},{\"SEARCHVAL\":\"ORCHARD CENTRAL (F" +
"RIENDLY BUILDINGS)\",\"CATEGORY\":\"Community\",\"X\":\"28709.3453\",\"Y\":\"31452.9157\"},{\"" +
"SEARCHVAL\":\"ORCHARD CENTRAL (WIRELESS HOTSPOTS)\",\"CATEGORY\":\"Recreation\",\"X\":\"28" +
"709.3453\",\"Y\":\"31452.9156\"},{\"SEARCHVAL\":\"ORCHARD CINELEISURE (WIRELESS HOTSPOTS" +
")\",\"CATEGORY\":\"Recreation\",\"X\":\"28347.9192\",\"Y\":\"31538.4923\"},{\"SEARCHVAL\":\"ORCH" +
"ARD COURT\",\"CATEGORY\":\"Building\",\"X\":\"28931.3725\",\"Y\":\"31225.6489\"},{\"SEARCHVAL\"" +
":\"ORCHARD CREDIT AUTO HOUSE\",\"CATEGORY\":\"Building\",\"X\":\"23255.1398\",\"Y\":\"35016.5" +
"269\"},{\"SEARCHVAL\":\"ORCHARD EMERALD (GREEN MARK BUILDINGS)\",\"CATEGORY\":\"Environm" +
"ent\",\"X\":\"28617.7255\",\"Y\":\"31549.8898\"},{\"SEARCHVAL\":\"ORCHARD FOUNTAIN CORNER\",\"" +
"CATEGORY\":\"Building\",\"X\":\"28464.8743\",\"Y\":\"31580.3349\"},{\"SEARCHVAL\":\"ORCHARD GA" +
"TEWAY\",\"CATEGORY\":\"Building\",\"X\":\"28666.655\",\"Y\":\"31427.7293\"},{\"SEARCHVAL\":\"ORC" +
"HARD GATEWAY # EMERALD\",\"CATEGORY\":\"Building\",\"X\":\"28617.699\",\"Y\":\"31549.9633\"}," +
"{\"SEARCHVAL\":\"ORCHARD GRAND COURT PTE LTD (FRIENDLY BUILDINGS)\",\"CATEGORY\":\"Comm" +
"unity\",\"X\":\"28580.4218\",\"Y\":\"31071.6324\"},{\"SEARCHVAL\":\"ORCHARD HOTEL (FRIENDLY " +
"BUILDINGS)\",\"CATEGORY\":\"Community\",\"X\":\"27469.037\",\"Y\":\"32216.2037\"},{\"SEARCHVAL" +
"\":\"ORCHARD HOTEL (WIRELESS HOTSPOTS)\",\"CATEGORY\":\"Recreation\",\"X\":\"27469.0369\",\"" +
"Y\":\"32216.2037\"},{\"SEARCHVAL\":\"ORCHARD HOTEL GALLERIA\",\"CATEGORY\":\"Building\",\"X\"" +
":\"27494.5279\",\"Y\":\"32195.9069\"}]}"
I have to use the above result to display all the name into a listbox in windows phone 7.1. How can I do that ?
I have saw from other sources they had this to display names into a list box in windows phone 7.1:
private void Search_Click(object sender, RoutedEventArgs e)
{
//retrieving the results for the keywords the user input
searchError.Text = "Loading... Please Wait";
if (Classes.Global.searched == 1)
{
searchVal = new List<string>();
}
MobileClinicWebService.MCWebServiceSoapClient obj = new MobileClinicApp.MobileClinicWebService.MCWebServiceSoapClient();
obj.getSearchCoordsAsync(searchBar.Text.ToString());
obj.getSearchCoordsCompleted += new EventHandler<MobileClinicWebService.getSearchCoordsCompletedEventArgs>(obj_getSearchCoordsCompleted);
}
void obj_getSearchCoordsCompleted(object sender, MobileClinicWebService.getSearchCoordsCompletedEventArgs e)
{
//retrieving the results, and displaying it on the phone
string[] search = null;
if (!e.Result.ToString().Equals("error"))
{
using (JsonTextReader jsonReader = new JsonTextReader(new StringReader(e.Result)))
{
while (jsonReader.Read())
{
if ((string)jsonReader.Value == "SEARCHVAL")
{
jsonReader.Read();
searchVal.Add((string)jsonReader.Value);
}
if ((string)jsonReader.Value == "X")
{
jsonReader.Read();
posx.Add(Double.Parse(jsonReader.Value.ToString()));
}
if ((string)jsonReader.Value == "Y")
{
jsonReader.Read();
posy.Add(Double.Parse(jsonReader.Value.ToString()));
}
}
}
search = new string[searchVal.Count];
for (int i = 0; i < searchVal.Count; i++)
{
search[i] = searchVal[i];
}
}
else
{
searchError.Text = "No Results Found";
}
if (search != null)
{
Classes.Global.searched = 1;
searchError.Text = "Search Results";
Results.ItemsSource = search;
}
}
First and foremost, since you control the structure of your json response at the web service source, you should fix its structure.
From your data, Search result contains a page results count and a set of results, hence I have changed the json to reflect this. This implies that Parsing with a suitable json de-serializer is possible and makes your code compact and tidy. Ensure you have the Newtonsoft json library set up in your project.
C# Classes
public class ResultSetPager<T>
{
public int PageCount { get; set; }
public IEnumerable<T> SearchResults { get; set; }
}
public class Place
{
public string SearchVal { get; set; }
public string Category { get; set; }
public double X { get; set; }
public double Y { get; set; }
}
Click event
private void LoadJsonData(object sender, RoutedEventArgs e)
{
string data = #"{
""PageCount"" : ""1"",
""SearchResults"": [
{
""SEARCHVAL"": ""ORCHARD22"",
""CATEGORY"": ""Building"",
""X"": ""29483.4267"",
""Y"": ""31269.938""
},
{
""SEARCHVAL"": ""ORCHARDBELAIR"",
""CATEGORY"": ""Building"",
""X"": ""27071.2616"",
""Y"": ""31629.2465""
}
]
}";
var pagedResults = JsonConvert.DeserializeObject<ResultSetPager<Place>>(data);
lstPlaces.ItemsSource = pagedResults.SearchResults;
}
Xaml
<Grid>
<StackPanel>
<Button Click="LoadJsonData" Content="Test"></Button>
<ListBox x:Name="lstPlaces">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0 0 0 15">
<TextBlock Text="{Binding SearchVal}" FontSize="{StaticResource PhoneFontSizeLarge}" />
<TextBlock Text="{Binding Category}" FontSize="{StaticResource PhoneFontSizeMediumLarge}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Grid>