I need help...
So essentially I've been watching WP 8.1 development tutorials and there was a tutorial with the standard HUB template.
So I tried to configure this template for my own use. I have a JSON file with all the data I need (apartments) which I want list now on my page. I "recreated" the SampleDataSource which is in my app just DataSource. I think everything is OK with the data and now comes the problem with translating this data and binding it to XAML. I don't really know why it isn't working as I have just tried to change the paramters which work in the template (provided by the SDK). Could you guys help me or give me some directions where can I find example for doing this.
If someone would be willing to help or skype/TW with me just to show me the structure and what I have to do, I would be grateful as I would then know how this basically translates and works so I could work on other sections of the project! Have bitcoins as a reward! :)
Thx in advance.
EDIT: Add Github repo: https://github.com/lklancir/zimmerfrei_wp/tree/master/ZimmerFrei_v0.1
Here is the DataSource.cs:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Data.Json;
using Windows.Storage;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
namespace ZimmerFrei.Data
{
public class ApartmentData
{
public ApartmentData(String id, String name, String description, String capacity, String stars, String address, String email, String phone, String phone2, String rating, String lat, String lng, String price, String cover_photo, String owner_id, String type_id, String city_id)
{
this.Id = id;
this.Name = name;
this.Description = description;
this.Capacity = capacity;
this.Stars = stars;
this.Address = address;
this.Email = email;
this.Phone = phone;
this.Phone2 = phone2;
this.Rating = rating;
this.Lat = lat;
this.Lng = lng;
this.Price = price;
this.Cover_photo = cover_photo;
this.Owner_id = owner_id;
this.Type_id = type_id;
this.City_id = city_id;
}
public string Id { get; private set; }
public string Name { get; private set; }
public string Description { get; private set; }
public string Capacity { get; private set; }
public string Stars { get; private set; }
public string Address { get; private set; }
public string Email { get; private set; }
public string Phone { get; private set; }
public string Phone2 { get; private set; }
public string Rating { get; private set; }
public string Lat { get; private set; }
public string Lng { get; private set; }
public string Price { get; private set; }
public string Cover_photo { get; private set; }
public string Owner_id { get; private set; }
public string Type_id { get; private set; }
public string City_id { get; private set; }
public override string ToString()
{
return this.Name;
}
}
public sealed class DataSource
{
private static DataSource _dataSource = new DataSource();
private ObservableCollection<ApartmentData> _apartments = new ObservableCollection<ApartmentData>();
public ObservableCollection<ApartmentData> Apartments
{
get { return this._apartments; }
}
public static async Task<IEnumerable<ApartmentData>> GetApartmentsAsync()
{
await _dataSource.GetDataAsync();
return _dataSource.Apartments;
}
public static async Task<ApartmentData> GetApartmentAsync(string id)
{
await _dataSource.GetDataAsync();
var matches = _dataSource.Apartments.Where((apartment) => apartment.Id.Equals(id));
if (matches.Count() == 1) return matches.First();
return null;
}
private async Task GetDataAsync()
{
if (this._apartments.Count != 0)
return;
Uri dataUri = new Uri("ms-appx:///DataModel/Apartments.json");
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(dataUri);
string jsonText = await FileIO.ReadTextAsync(file);
JsonObject jsonObject = JsonObject.Parse(jsonText);
JsonArray jsonArray = jsonObject["apartments"].GetArray();
foreach (JsonValue apartmentValue in jsonArray)
{
JsonObject apartmentObject = apartmentValue.GetObject();
ApartmentData apartment = new ApartmentData(apartmentObject["Id"].GetString(),
apartmentObject["Name"].GetString(),
apartmentObject["Description"].GetString(),
apartmentObject["Capacity"].GetString(),
apartmentObject["Stars"].GetString(),
apartmentObject["Address"].GetString(),
apartmentObject["Email"].GetString(),
apartmentObject["Phone"].GetString(),
apartmentObject["Phone2"].GetString(),
apartmentObject["Rating"].GetString(),
apartmentObject["Lat"].GetString(),
apartmentObject["Lng"].GetString(),
apartmentObject["Price"].GetString(),
apartmentObject["Cover_photo"].GetString(),
apartmentObject["Owner_id"].GetString(),
apartmentObject["Type_id"].GetString(),
apartmentObject["City_id"].GetString());
this.Apartments.Add(apartment);
}
}
}
}
Here is the ListPage.xaml (where I want to write out my data)
<Page
x:Class="ZimmerFrei_v0._1.ListPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ZimmerFrei_v0._1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="using:ZimmerFrei.Data"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
d:DataContext="{Binding Source={d:DesignData Source=/DataModel/Apartments.json, Type=data:DataSource}}"
mc:Ignorable="d" FontFamily="Global User Interface">
<Page.Resources>
<DataTemplate x:Key="StandardTripleLineItemTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" Margin="0,9.5,0,0" Grid.Column="0" HorizontalAlignment="Left">
<Image Source="{Binding Cover_photo}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}" Height="79" Width="79"/>
</Border>
<StackPanel Grid.Column="1" Margin="14.5,0,0,0">
<TextBlock Text="{Binding Name}" Style="{ThemeResource ListViewItemTextBlockStyle}" FontFamily="Global User Interface"/>
<TextBlock Text="{Binding Description}" Style="{ThemeResource ListViewItemContentTextBlockStyle}" Foreground="{ThemeResource PhoneMidBrush}" FontFamily="Global User Interface" />
<TextBlock Text="{Binding Stars}" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" />
</StackPanel>
</Grid>
</DataTemplate>
</Page.Resources>
<Grid x:Name="LayoutRoot">
<Hub x:Name="Hub" x:Uid="Hub" Header="ZimmerFrei">
<HubSection x:Uid="HubSection" Header="APARTMENTS"
DataContext="{Binding Apartments}" >
<DataTemplate>
<ListView
AutomationProperties.AutomationId="ItemListViewSection3"
AutomationProperties.Name="Items In Group"
SelectionMode="None"
IsItemClickEnabled="True"
ItemsSource="{Binding apartment}"
ItemTemplate="{StaticResource StandardTripleLineItemTemplate}"
ItemClick="ItemView_ItemClick"
ContinuumNavigationTransitionInfo.ExitElementContainer="True">
</ListView>
</DataTemplate>
</HubSection>
</Hub>
</Grid>
There are a few issues here:
Your ApartmentData class has some properties named like this Cover_photo. This isn't typically the style convention used by C#, so I renamed them to like CoverPhoto.
On the same topic, your ApartmentData properties are named like Cover_photo but they are named like cover_photo in the JSON (which is a typical JSON style). You're accessing the JSON keys like this:
apartmentObject["Cover_photo"].GetString() // KeyNotFoundException
but it should be:
apartmentObject["cover_photo"].GetString()
This will work during runtime, but the designer won't execute this code. The designer reads the JSON file and attempts to match keys in the JSON file to properties on the type you have specified, but it won't be able to because the keys and properties don't match. So either you:
Modify the JSON so that the keys match the properties like CoverPhoto.
Annotate your type with the DataContractAttribute. This allows you to specify the mapping between JSON and .NET type with DataMemberAttribute, but mostly because you get JSON serialization/deserialization!
I sent you a pull request with these changes. Also, your design data is huge (~1000 items!). It should only contain ~5 items since you won't be able to see all items in the designer anyway.
Related
For my current project I am working on a cross-platform application. We are building this using Visual studio, cross platform-app.
In this project we use questionaires which we set in an SQL Database.
Using MVVM I can load this dynamically into the mobile app. (We do this because there are many platforms where we show this, so we choose to set it in the back-end, the questionaire with the answers to each question).
But with saving there seems to be an issue,
I can't seem to send data back to my back end
-> I want to send either the value or the string showed from the picker back to the back end (preferably using MVVM). If I can get the data in the viewmodel (or code behind if MVVM would not be possible), i would be helped enough with my question.
I build my questionaire using a collectionview which contains a DataTemplate with a picker inside.
QuestionaireView.xaml:
<ContentPage.BindingContext>
<viewModels:Questionaire_viewmodel/>
</ContentPage.BindingContext>
<CollectionView
x:Name="CollectionQuestionsView"
SelectionMode="None"
Margin="0,0,0,0" RemainingItemsThreshold="5"
BackgroundColor="Transparent"
SelectedItems="{Binding selectedPickers}"
ItemsSource="{Binding Questionaire.Vraag,Mode=TwoWay}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Style="{StaticResource RegularLabelStyleSmallLogin}" Text="{Binding vraagstelling}" HorizontalTextAlignment="Start" VerticalTextAlignment="Start" LineBreakMode="WordWrap"/>
<Picker Style="{StaticResource PickRegularSmall}" SelectedItem="{Binding vraag_id}" x:Name="{Binding vraag_id}" ItemsSource="{Binding Antwoorden}" ItemDisplayBinding="{Binding antwoord_vraagstelling}"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Frame Margin="0,0,0,20" Style="{StaticResource OrangeLoginFrame}">
<Grid Margin="-15" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Style="{StaticResource SemiBoldLabelStyleMedium}" Grid.Row="0" Grid.Column="0" Text="Opslaan"/>
<Button Style="{StaticResource LoginButton}" Command="{Binding SaveVragenlijstCompetentiesCommand}" Grid.Row="0" Grid.Column="0" />
</Grid>
</Frame>
<Button x:Name="questionaireButton" Command="{Binding getQuestionaireLoopbaancompetenties}" IsVisible="False"/>
So to explain the bindings (since some names are not English):
itemsource of collectionview: The questionaire.vraag retrieves a collection of questions out of the questionaire object (see the model.cs down below)
label text binding: Displays the question
picker selectedItem binding: vraag id results in a string (retrieved from the backend) which here specifly is vraag_127, vraag_128 (the numbers are an id of the question)
itemsource picker: binding antwoorden, these are the answers to the questions
in the frame below the collectionview, I made a button to (at least i tried) to send the data to the ViewModel.cs
The (hidden)button below the frame loads the data (I execute it in the code behind, not sure if this is the best option)
QuestionaireViewModel.cs
public string vraag_127 { get; set; }
public string vraag_128 { get; set; }
... and so on
public string vraag_161 { get; set; }
public string categorie_vraag { get; set; }
public string SelectedAnswer { get; set; }
public string vraagstelling { get; set; }
public string vraag_id { get; set; }
public string score_antwoord { get; set; }
public string antwoord_vraagstelling { get; set; }
public string default_question { get; set; }
public string description { get; set; }
private Questionaire_model _questionaire;
public Questionaire_model Questionaire
{
get { return _questionaire; }
set
{
_questionaire = value;
OnPropertyChanged();
}
}
private List<Questionaire_model> _vraag;
public List<Questionaire_model> Vraag
{
get { return _vraag; }
set
{
_vraag = value;
OnPropertyChanged();
}
}
private List<Questionaire_model> _antwoorden;
public List<Questionaire_model> Antwoorden
{
get { return _antwoorden; }
set
{
_antwoorden = value;
OnPropertyChanged();
}
}
public ICommand getQuestionaireLoopbaancompetenties
{
get
{
return new Command(async (boolean) =>
{
Questionaire = await _apiServices.GetQuestionaireQuestions("Competenties");
});
}
}
private ObservableCollection<vragenModel> _selectedPicker;
public ObservableCollection<vragenModel> SelectedPicker
{
get
{
return _selectedPicker;
}
set
{
_selectedPicker = value;
OnPropertyChanged();
}
}
public ICommand SaveVragenlijstCompetentiesCommand
{
get
{
return new Command(async () =>
{
var responseBool = await _apiServices.SaveCultuur(vraag_127,vraag_128, ... vraag_161)});
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
And my QuestionaireModel.cs:
public class Questionaire_model
{
public int id { get; set; }
public string default_question { get; set; }
public string description { get; set; }
public IList<Vragen> Vraag{ get; set; }
public class Vragen
{
public string categorie_vraag { get; set; }
public string SelectedAnswer { get; set; }
public string vraagstelling { get; set; }
public string vraag_id { get; set; }
public IList<antwoorden> Antwoorden { get; set; }
}
public class antwoorden
{
public string score_antwoord { get; set; }
public string antwoord_vraagstelling { get; set; }
}
}
The reason we use an collectionView, is because we use the template for various questionaires with various amount of questions and answer possibilities.
So at this moment, when I execute my save action, it gives "null" in my ViewModel - action
I have defined public class Questionaire_viewmodel : INotifyPropertyChanged above my viewmodel
So I hope someone can either help me with my code, that I missed something here
Or if I have to change something because it is simply impossible well then I would like to have an direction where to go to.
As I understand, you want your Picker.SelectedItem actually bind to QuestionaireViewModel.vrag_xxx properties. That won't work like this - what now happens is that your Picker.SelectedItem is bound to Vragen.vraag_id field and is not able to use it, as long as it expects antwoorden type there.
However, I see that you have SelectedAnswer property in Vragen, you can change it to be of antwoorden type and then fetch user choice from that field.
So, if your Vragen class is:
public class Vragen
{
public string categorie_vraag { get; set; }
public antwoorden SelectedAnswer { get; set; }
public string vraagstelling { get; set; }
public string vraag_id { get; set; }
public IList<antwoorden> Antwoorden { get; set; }
}
Then, you can change your binding for Picker to:
<Picker Style="{StaticResource PickRegularSmall}" SelectedItem="{Binding SelectedAnswer}" x:Name="{Binding vraag_id}" ItemsSource="{Binding Antwoorden}" ItemDisplayBinding="{Binding antwoord_vraagstelling}"/>
And, at last in SaveVragenlijstCompetentiesCommand you'll be able to get array of answers (sorted by question id):
Questionaire.Vraag.OrderBy(x => x.vraag_id).Select(x => x.SelectedAnswer.antwoord_vraagstelling)
That will give you array of answer texts. Still it doesn't conform to your apiServices.SaveCultuur call. I would strongly recommend to change that method - method that contains a lot of parameters is certainly a problem.
If you can change it to accept string[], then you will be able to pass Questionaire.Vraag.OrderBy(x => x.vraag_id).Select(x => x.SelectedAnswer.antwoord_vraagstelling) to it.
If you can't change apiServices, there's still possibility to call the method through reflection using array, but it's a bit tricky.
So I have an online database. And I want the query results to be displayed in a listbox. I tried to use data binding but I think I'm doing it totally wrong.
Files
[![enter image description here][1]][1]
Table
class ProductTable
{
public string id { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public double Price { get; set; }
public string Type { get; set; }
public string Seller { get; set; }
public int Expiration { get; set; }
}
MainViewModel.cs
namespace Test
{
class MainViewModel
{
IMobileServiceTable<ProductTable> product = App.MobileService.GetTable<ProductTable>();
//In this method, load your data into Products
public async void Load()
{
// This query filters out completed TodoItems.
MobileServiceCollection<ProductTable, ProductTable> Products = await product
.Where(ProductTable => ProductTable.Price == 15)
.ToCollectionAsync();
// itemsControl is an IEnumerable that could be bound to a UI list control
IEnumerable itemsControl = Products;
}
}
}
XAML
<Page x:Name="PAGE"
xmlns:local="clr-namespace:Test;assembly=Version1">
<Grid>
<Grid.DataContext>
<local:MainViewModel />
</Grid.DataContext>
<ListBox Margin="10,10,10,100" x:Name="lb" ItemsSource="{Binding Products}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}" FontSize="10"></TextBlock>
<TextBlock Text="{Binding Title}" FontSize="10"></TextBlock>
<TextBlock Text="{Binding Description}" FontSize="10"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Page>
Solution
Table needs JSON property name explicitly declared otherwise you won't be able to use data binding.
Table.cs
public class ProductTable
{
[JsonProperty(PropertyName = "id")]
public string id { get; set; }
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "Title")]
public string Title { get; set; }
[JsonProperty(PropertyName = "Description")]
public string Description { get; set; }
[JsonProperty(PropertyName = "Price")]
public double Price { get; set; }
[JsonProperty(PropertyName = "Type")]
public string Type { get; set; }
[JsonProperty(PropertyName = "Seller")]
public string Seller { get; set; }
[JsonProperty(PropertyName = "Expiration")]
public int Expiration { get; set; }
}
XAML.cs
You don't need to declare a new listbox, only use itemsource.
private async void button1_Click(object sender, RoutedEventArgs e)
{
IMobileServiceTable<ProductTable> productTest = App.MobileService.GetTable<ProductTable>();
// This query filters out completed TodoItems.
MobileServiceCollection<ProductTable, ProductTable> products = await productTest
.Where(ProductTable => ProductTable.Type == "Test")
.ToCollectionAsync();
lb.ItemsSource = products;
}
XAML
IN THE STACKPANEL, NEVER EVER USE HEIGHT"*" this will cause a critical error!
<ListBox x:Name="lb" Margin="10,10,10,100" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Width="300">
<TextBlock Text="{Binding Name}" FontSize="10"></TextBlock>
<TextBlock Text="{Binding Title}" FontSize="10"></TextBlock>
<TextBlock Text="{Binding Description}" FontSize="10"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You are creating two ListBoxes - one in code that isn't being displayed and one in XAML which is bound to whatever your DataContext is.
Remove the last two lines in your code, and change your XAML to:
ItemsSource="{Binding Products}"
Next, expose Products as a Property on a class (ViewModel if you want to use MVVM), and ensure that the DataContext of your ListBox is set to said ViewModel/class.
I'm not familiar with MobileServiceCollection, so I assume it is bindable. If it is not, expose Products as a ObservableCollection (if the values in it change over time), or any other supported collection type.
Elaboration on Properties
Create a class:
public class MainViewModel {
//This is a property
public ObservableCollection<ProductTable> Products { get; set; }
//In this method, load your data into Products
public void Load(){
//Products = xxx
}
}
In your XAML:
<Page [...]
xmlns:local="clr-namespace:YourNamespace;assembly=YourProjectName">
<Grid>
<Grid.DataContext>
<local:MainViewModel />
</Grid.DataContext>
<!-- ListBox goes in here somewhere, still with ItemsSource bound to Products -->
</Grid>
</Page>
Read more about namespaces here.
By doing this, your Windows' DataContext will be set to the MainViewModel (could also be named ProductsViewModel). Since your ListBox will be within your Window, it will inherit (due to Property Value Inheritance) the same DataContext.
The Binding will look for a property 'Products' on the ViewModel.
You will need to call the Load() method somewhere.
Part 2 - After looking at the code
Mind you, I am not able to run the code, so I'm flying somewhat blind.
Buy.xaml.cs
public sealed partial class Buy : Page
{
private readonly MainViewModel _viewModel;
public Buy()
{
this.InitializeComponent();
_viewModel = new MainViewModel();
DataContext = _viewModel;
}
private async void button1_Click(object sender, RoutedEventArgs e)
{
_viewModel.Load();
}
}
MainViewModel.cs
public class MainViewModel : INotifyPropertyChanged
{
IMobileServiceTable<ProductTable> product = App.MobileService.GetTable<ProductTable>();
public List<ProductTable> Products { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
public async void Load()
{
Products = await product
.Where(ProductTable => ProductTable.Price == 15)
.ToListAsync();
//Notify that the property has changed to alert to UI to update.
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Products)));
}
}
You need to make ProductTable public, or you will get a compilation error.
Hopefully, the above will enable you to bind your ListBox using the ItemsSource binding described above.
And please note that the above code is not necessarily best practice.
you don't need that line in your code behind
ListBox lb = new ListBox();
and you can keep that line
lb.ItemsSource = Products;
or you can sit the Binding to the MobileServiceCollection in the XAML
<ListBox Margin="10,10,10,100" x:Name="lb" ItemsSource="{Binding Products}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Title}"/>
<TextBlock Text="{Binding Description}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I have trouble to deserialize this json file. I want to bind the "favoriteSongs" array to my view in xaml and display all the informations in a longlistselector.
{
"_id": "56fd864ff28510694a6a7b5e",
"addFavorites": {
"favoriteSongs": [
{
"_id": "570aeb89869a0520e0d0365c",
"title": "get lucky",
"album": "random access memory",
"primaryArtist": "daft punk",
"artist": "570ae933cd7d1072b430ea51",
"primaryGenre": "electro",
"genre": "570ae933cd7d1072b430ea52",
"duration": "3m31s",
"year": 2013
},
{ ... }
]
}
In my view model im using an observablecollection to add the informations from the json, here the "getFavoriteSongsModel" is my RootObject
for (int i = 0; i < count; i++)
{
getFavoriteSongsModel = JsonConvert.DeserializeObject<GetFavoriteSongsModel>(e.Result);
getFavoriteSongs.Add(new GetFavoriteSongsModel()
{
Id = getFavoriteSongsModel.Id,
Favorites = getFavoriteSongsModel.Favorites
});
I tried to use this pattern with another observablecollection that points to a class with a list of all the infomations i need but it crashes everytime. I don't know how to use the "Favorites" variable, i know it is populated but i can't display what i want in the xaml.
<Grid>
<phone:LongListSelector x:Name="MainLongListSelector" Margin="0,0,-12,0" ItemsSource="{Binding getFavoriteSongs}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" >
<TextBlock Text="{Binding FavoriteSongs.Album}" Style="{StaticResource PhoneTextBlockBase}"/>
<TextBlock Text="{Binding FavoriteSongs.Title}" Style="{StaticResource PhoneTextBlockBase}"/>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</Grid>
I have create a sample Code on base of my understanding.
I have Created three classes on based of Json string from json2csharp, which is very useful to create classes on based of Json string.
Three classes are as following
public class FavoriteSong
{
public string _id { get; set; }
public string title { get; set; }
public string album { get; set; }
public string primaryArtist { get; set; }
public string artist { get; set; }
public string primaryGenre { get; set; }
public string genre { get; set; }
public string duration { get; set; }
public int year { get; set; }
}
public class AddFavorites
{
public ObservableCollection<FavoriteSong> favoriteSongs { get; set; }
}
public class MainClass
{
public string _id { get; set; }
public AddFavorites addFavorites { get; set; }
}
I have just use your string as json and on base I have create this samle.
Following code will deserialize json string
public MainClass objMainClass { get; set; }
string strJson = "{\"_id\": \"56fd864ff28510694a6a7b5e\",\"addFavorites\": {\"favoriteSongs\": [{\"_id\": \"570aeb89869a0520e0d0365c\",\"title\": \"get lucky\",\"album\": \"random access memory\",\"primaryArtist\": \"daft punk\",\"artist\": \"570ae933cd7d1072b430ea51\",\"primaryGenre\": \"electro\",\"genre\": \"570ae933cd7d1072b430ea52\",\"duration\": \"3m31s\",\"year\": 2013}]}}";
objMainClass = new MainClass();
objMainClass = JsonConvert.DeserializeObject<MainClass>(strJson);
MainLongListSelector.DataContext = objMainClass.addFavorites;
and binding in XAML is as following
<phone:LongListSelector
x:Name="MainLongListSelector"
Margin="0,0,-12,0"
ItemsSource="{Binding favoriteSongs}">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel
Margin="0,0,0,17">
<TextBlock
Text="{Binding album}"
Style="{StaticResource PhoneTextBlockBase}" />
<TextBlock
Text="{Binding title}"
Style="{StaticResource PhoneTextBlockBase}" />
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
Hope so it will be helpful to you.
In my application I have a ListBox and a DataGrid.
I'm trying to bind the DataGrid to an ObservableCollection which is a property of the returned SelectedItem from the ListBox - this doesn't work and I don't understand why. Output console doesn't print any errors.
The ObservableCollection is of type ReportItem, and it can contain instances of TextReportItem, which inherits from ReportItem.
XAML:
<ListBox x:Name="listBox" HorizontalAlignment="Left" Margin="10,10,0,36.667" Width="119" ItemsSource="{Binding ReportItems}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel HorizontalAlignment="Left" Height="274" Margin="134,10,0,0" VerticalAlignment="Top" Width="375" >
<StackPanel.Resources>
<Style x:Key="ControlBaseStyle" TargetType="{x:Type Control}">
<Setter Property="Margin" Value="0, 10, 0, 0" />
</Style>
</StackPanel.Resources>
<DataGrid Height="190" VerticalAlignment="Bottom" DataContext="{Binding ElementName=listBox, Path=SelectedItem.TItems}" />
</StackPanel>
ViewModel:
public class MainViewModel
{
public ObservableCollection<ReportItem> ReportItems { get; set; }
public object SelectedReportItem { get; set; }
public MainViewModel()
{
ReportItems = new ObservableCollection<ReportItem>();
ReportItems.Add(Example);
}
// line below is for debugging purposes
public TextReportItem Example = new TextReportItem() { Name = "ti1", DataFile = "ti1.txt"};
}
ReportItem:
public class ReportItem
{
public int Id { get; set; }
public string Name { get; set; }
public string DataFile { get; set; }
}
TextReportItem and TextParcel:
public class TextReportItem : ReportItem
{
public ObservableCollection<TextParcel> TItems { get; set; }
public TextReportItem()
{
TItems = new ObservableCollection<TextParcel>();
}
}
public class TextParcel
{
public char Delimiter { get; set; }
public string LineExp { get; set; }
public string Result { get; set; }
public string IgnoreLine { get; set; }
public int DesiredResultIndexInLine { get; set; }
}
I think the mere DataContext doesn't tell the DataGrid what it has to show. You have to give it an ItemsSource. Maybe you could try something like that:
<DataGrid
DataContext="{Binding ElementName=listBox, Path=SelectedItem}"
ItemsSource="{Binding TItems}" />
I believe that the DataContext of a DataGrid expects an IEnumerable, and not a single instance of an object. When you set the source to a single instance of a ReportItem, you're not passing it anything that it can iterate to construct it's rows.
If you make the necessary changes and give that a yank, you should be golden :)
you can use select index change method instead
protected void GridView_SelectedIndexChanged(object sender, EventArgs e){
string value = null;
value = GridView1.SelectedRow.Cells(2).Text.ToString();
}
On Windows Phone 8 I have a page that loads user places. Each place consists of name and image name. I then search for the image in the storage and display it. All of that is viewed in a list box using data binding. I do not know how to set the image source in the data binding. Should I make an extra variable of type bit image in the Place class, or in the get of string image name should I call the function which returns a bit image?
Here is the Place class:
class Place
{
public string id { get; set; }
public string user_id { get; set; }
public string name { get; set; }
public string radius { get; set; }
public string longitude { get; set; }
public string latitude { get; set; }
public string image { get; set; }
public string thumbnail { get; set; }
public async Task<placesobj> getUserPlaces(string userId)
{
var pairs = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string> ("id", userId),
new KeyValuePair<string, string> ("data", "all_places")
};
var serverData = serverConnection.connect("places.php", pairs);
placesobj json = JsonConvert.DeserializeObject<placesobj>(await serverData);
if (json != null)
return json;
else
return null;
}
public class placesobj
{
public List<Place> places { get; set; }
}
}
}
And here is the XAML for the list box:
<ListBox Grid.Row="1" ItemsSource="{Binding places}" Margin="0,10,0,0" >
<ListBox.ItemTemplate>
<DataTemplate >
<StackPanel Margin="10,0,10,8">
<StackPanel Orientation="Horizontal" Margin="10,0,10,8">
<TextBlock Text="{Binding name}" TextWrapping="Wrap" FontSize="50" />
<Image Source="{Binding }"
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Try this. I think this will be fine . this is working for me.
reference
Image source is expecting a uri . so better give this as uri
<Image Source="{Binding Image}"/>
public Uri Image { get; set; }