I have a Json file saved in "IsolatedStorage" (json.html) and i need populate a "ListBox" with the field "FName" (from Json file).
The Json below, is stored in file (json.html) and saved in
IsolatedStorage. The file will be changed as necessary (synchronized
with web server). So I need that fields as "FNome" and "FEstado"
received information from "json.html".
My Json file:
{"xId":"52","result":{"type":"Basico.Bean.MunicipioClass.TMunicipio","id":1,"fields":{"FRefCount":0,"FId":52,"FNome":"Sumare","FEstado":"SP","FPais":"Brasil"}}}
My class from Json:
public class Fields
{
public int FId { get; set; }
public string FNome { get; set; }
public string FEstado { get; set; }
public string FPais { get; set; }
}
My ListBox:
<ListBox x:Name="listBox1"
Height="192" Width="456"
HorizontalAlignment="Center"
VerticalAlignment="Top"
BorderThickness="5"
Padding="5"
BorderBrush="White"
FontSize="30"
HorizontalContentAlignment="Stretch" Foreground="{x:Null}">
<ListBox.Background>
<SolidColorBrush Color="White" Opacity="0.5"/>
</ListBox.Background>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding FNome}"/>
<TextBlock Grid.Column="10" Text="{Binding FEstado}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I'm assuming you are not using MVVM design pattern or anything "fancy", so here's (almost) minimal working example for you to study.
First, right-click on your project, select Manage NuGet Packages and install Json.NET dependency. Json.NET package helps you handle JSON formatted data.
After installation, this would be your MainWindow.xaml. Here you define your ListBox and template you want to use when showing each ListBox item.
<Window x:Class="MyWpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="100"
Width="420">
<Grid>
<!-- Your ListBox, notice the ItemsSource -->
<ListBox
Height="50"
Width="400"
FontSize="30"
HorizontalContentAlignment="Stretch"
ItemsSource="{Binding Items}">
<!-- Template to display each item -->
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- Bind UI controls to properties you want to display -->
<TextBlock Grid.Column="0" Text="{Binding FId}"/>
<TextBlock Grid.Column="1" Text="{Binding FPais}"/>
<TextBlock Grid.Column="2" Text="{Binding FNome}"/>
<TextBlock Grid.Column="3" Text="{Binding FEstado}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
And your code-behind, namely MainWindow.xaml.cs. For clarity, json is defined as const string.
using System.Windows;
using System.Collections.ObjectModel;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace MyWpfApplication
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
// Your JSON string
const string json =
"{'xId':'52'," +
" 'result':{" +
" 'type':'Basico.Bean.MunicipioClass.TMunicipio'," +
" 'id':1," +
" 'fields':{" +
" 'FRefCount':0," +
" 'FId':52," +
" 'FNome':'Sumare'," +
" 'FEstado':'SP'," +
" 'FPais':'Brasil'" +
" }" +
" }" +
"}";
// Parse as JObject
JObject jObj = JObject.Parse(json);
// Extract what you need, the "fields" property
JToken jToken = jObj["result"]["fields"];
// Convert as Fields class instance
Fields fields = jToken.ToObject<Fields>();
// Assign to Items property, which is used as ListBox's ItemsSource
// In real application you'd probably want to have more than one item :)
Items = new ObservableCollection<Fields>() { fields };
}
public ObservableCollection<Fields> Items { get; set; }
}
}
And then, of course, you need you Fields class, too. You can "map" JSON to C# class autamagically if property names match. If you want to use other name in your class properties, say plain Id instead of FId, then you need to mark the property with JsonProperty attribute. For example [JsonProperty(PropetyName = "FId)].
public class Fields
{
[JsonProperty(PropertyName = "FId")]
public int FId { get; set; }
public string FNome { get; set; }
public string FEstado { get; set; }
public string FPais { get; set; }
}
Running the "application" gives you the following output
Related
OK, I think similar questions have already been asked, but I can't get this to work. I have a View with an ItemsControl like this:
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Content="Model Health Report:" Margin="10,10,10,0" Height="26" VerticalAlignment="Top" FontWeight="Bold"/>
<ItemsControl Grid.Row="1"
ItemsSource="{Binding HealthReports, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type hr:HealthReportSummaryControl}"/>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
That has a view model behind it like this:
public class CommunicatorViewModel : ViewModelBase
{
public ObservableCollection<HealthReportSummaryViewModel> HealthReports { get; set; }
public CommunicatorModel Model { get; set; }
public CommunicatorViewModel(HealthReportData data)
{
Model = new CommunicatorModel();
HealthReports = new ObservableCollection<HealthReportSummaryViewModel>
{
new HealthReportSummaryViewModel {Title = "View1", Description = "Some desc."},
new HealthReportSummaryViewModel {Title = "View2", Description = "Some desc."}
};
}
}
As you can see I am binding it to an ObservableCollection of HealthReportSummaryViewModel objects. These are populated in the constructor. I checked the objects at runtime, they are correct.
The actual control looks like this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="2"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Ellipse Grid.Column="0"
Fill="{Binding FillColor}"
Margin="2"/>
<Rectangle Grid.Column="1"
Fill="DarkGray"
Margin="0,2"/>
<Label Content="{Binding Title}"
Grid.Column="2"
Margin="5,0,10,0"
VerticalAlignment="Top"/>
<TextBlock Grid.Column="2"
Margin="5,10,10,0"
TextWrapping="Wrap"
Text="{Binding Description}"/>
</Grid>
With a view model:
public class HealthReportSummaryViewModel : ViewModelBase
{
private System.Windows.Media.Color _fillColor;
public System.Windows.Media.Color FillColor {
get { return _fillColor; }
set { _fillColor = value; RaisePropertyChanged(() => FillColor); }
}
private string _title;
public string Title
{
get { return _title; }
set { _title = value; RaisePropertyChanged(() => Title); }
}
private string _description;
public string Description
{
get { return _description; }
set { _description = value; RaisePropertyChanged(() => Description); }
}
}
I am getting no exceptions, but my window has only empty items. There is a rectangle in the user control that is not dependent on data binding so perhaps this is an issue with the size of the content? I can't figure this out. It's all blank. Do I need to somehow set the size for each ItemsControl item, or will they just adjust to size of the grid they are placed in? What am i missing here? All help will be appreciated.
Your DataTemplate definition is wrong:
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type hr:HealthReportSummaryControl}"/>
</ItemsControl.ItemTemplate>
This defines an empty data template for the items of the HealthReportSummaryControl type.
Instead, you should define it like that:
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type hr:HealthReportSummaryViewModel}">
<hr:HealthReportSummaryControl/>
</DataTemplate>
</ItemsControl.ItemTemplate>
This defines a template for the HealthReportSummaryViewModel items.
I need to dig into a nested observable collection in UWP, which consists another observable collection inside it, and then bind it to my XAML.
How could I do it?
Allen Rufolo's Solution works. But Here is another way of approaching this.
x:Bind is newly implemented and available for UWP. My Answer is based on x:Bind
Sample Classes
public class MainItems
{
public string ItemName { get; set; }
public ObservableCollection<SubItems> SubItemsList { get; set; }
}
public class SubItems
{
public string SubItemName { get; set; }
}
Sample Data
ObservableCollection<MainItems> _data = new ObservableCollection<MainItems>();
for (int i = 1; i <= 5; i++)
{
MainItems _mainItems = new MainItems();
_mainItems.ItemName = "Main" + i.ToString();
_mainItems.SubItemsList = new ObservableCollection<SubItems>();
for (int j = 1; j <= 3; j++)
{
SubItems _subItems = new SubItems()
{
SubItemName = "SubItem" + i.ToString()
};
_mainItems.SubItemsList.Add(_subItems);
}
_data.Add(_mainItems);
}
My XAML
<ListView x:Name="MyMainList">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:MainItems">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="{x:Bind ItemName}" />
<ListView ItemsSource="{x:Bind SubItemsList}" Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:SubItems">
<TextBlock Foreground="Red" Text="{x:Bind SubItemName}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
x:Bind gives you an easy way to Bind your Nested Observable Collection
Output
A code example of your observable collections would help but you could do something like this...
public class MyViewModel
{
public ObservableCollection<MyObject> MyObjectCollection { get; set;}
}
public class MyObject
{
public string ObjectName {get; set;}
public ObservableCollection<AnotherObject> AnotherObjectCollection { get; set; }
}
And in your XAML you can bind to these collection similar to this
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListView x:Name="ListView1" Grid.Column="0"
ItemsSource="{Binding MyObjectCollection}">
<ListView.ItemTemplate>
<Datatemplate>
<TextBlock Text="{Binding ObjectName}"/>
</Datatemplate
</ListView.ItemTemplate>
</ListView>
<Grid Grid.Column=1 DataContext="{Binding ElementName=ListView1, Path=SelectedItem}">
<ListView ItemsSource="{Binding AnotherObjectCollection}"/>
</Grid>
</Grid>
In this example, the DataContext of the second Grid is bound to the selected item in ListView1.
I am not sure that I get what do you need, but I guess that it could be the same as for WPF.
Check out questions and answers for the next questions:
Binding nested ItemsControls to nested collections
Nested ObservableCollection data binding in WPF
WPF Binding on Nested ItemControls with Sub Collection
Databinding for nested collections in XAML (WPF and Silverlight)
I am binding an observable collection to a Grid in UWP project and binding is working for string datatypes but not for ImageSource Data Type. The image is need to be loaded from a Local folder .
The image is downloaded to Local folder via the application in some other parts [ The code is not included here ] But that downloading section is working fine
The below code is used to create the collection to bind
public class LibraryBookModel
{
public string Name { get; set; }
public string Title { get; set; }
public ImageSource CoverImage { get; set; }
}
private ObservableCollection<LibraryBookModel> DPMBooks;
private async Task<bool> lodLibrariesAsync(Uri library_url)
{
try
{
//create a view model object and add to observable collection
LibraryBookModel view_model = new LibraryBookModel { Name = "Myname", Title = "Myttile" };
string filename = "picture_uname.png"; //this file is present in the folder
string cover_path = string.Format("{0}\\{1}", COVERPICS_Folder, filename);
view_model.CoverImage = new BitmapImage(new Uri(new Uri("ms-appdata:///"), cover_path));
DPMBooks.Add(view_model);
return true;
}
catch
{
return false;
}
}
const string COVERPICS_Folder = "MyUniversalApp\\LabWork1\\CoverImages";
And xaml used is here and run time it shows both string properties correctly but not the image.
<ListView.ItemTemplate>
<DataTemplate x:DataType="data:LibraryBookModel">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Width="56" Height="56">
<Image Source="{Binding CoverImage}" Stretch="UniformToFill"/>
</Border>
<StackPanel Grid.Column="1">
<TextBlock Text="{Binding Title}" Style="{StaticResource TitleTextBlockStyle}" TextWrapping="NoWrap" Margin="9.6,0"/>
<TextBlock Text="{Binding Author}" Style="{StaticResource SubtitleTextBlockStyle}" TextWrapping="NoWrap" Margin="9.6,0"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Is there anything wrong in the way image url is constructed?
I would like to display some information in a data template in my app but when it is run it shows nothing in the listbox.
Here is the class code (class called notes)
public class notes
{
public string strNoteName { get; set; }
public string strCreated { get; set; }
public string strModified { get; set; }
public bool boolIsProtected { get; set; }
public string strNoteImage { get; set; }
public static ObservableCollection<notes> GetnotesRecord()
{
ObservableCollection<notes> notesRecord = new ObservableCollection<notes>
{
new notes{strNoteName="Science",strCreated="17/07/2014",strModified="17/07/2014",boolIsProtected=true,strNoteImage=""},
new notes{strNoteName="Math",strCreated="12/02/2014",strModified="15/07/2014",boolIsProtected=false,strNoteImage=""},
new notes{strNoteName="HW",strCreated="05/06/2014",strModified="2/07/2014",boolIsProtected=false,strNoteImage=""},
new notes{strNoteName="Business",strCreated="23/04/2014",strModified="17/07/2014",boolIsProtected=true,strNoteImage=""},
};
return notesRecord;
}
public ObservableCollection<notes> _notes;
public ObservableCollection<notes> allNotes
{
get
{
return _notes;
}
set
{
_notes = value;
}
}
}
And here is the XAML code:
<ListBox Margin="0,10,0,88">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Grid Margin="0,5,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image Source="{Binding strNoteImage}" Height="80" Width="80" Grid.Column="0"></Image>
<StackPanel Grid.Column="1" Orientation="Vertical" Width="150" Height="100" >
<TextBlock Text="{Binding strNoteName}" Margin="5,1,0,1"></TextBlock>
<TextBlock Text="{Binding strCreated}" Margin="5,1,0,1"></TextBlock>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Last modified: " Margin="5,1,0,1"></TextBlock>
<TextBlock Text="{Binding strModified}" Margin="3,1,0,1"></TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Is protected: " Margin="5,1,0,1"></TextBlock>
<TextBlock Text="{Binding boolIsProtected}" Margin="3,1,0,1"></TextBlock>
</StackPanel>
</StackPanel>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox >
Thank you in advance for any help :)
Change the ListBox definition to
<ListBox Margin="0,10,0,88" ItemsSource="{Binding}">
and set in C# code
this.DataContext = Notes.GetnotesRecord();
You are missing to set the ItemsSource to the Listbox,
You can do that in XAML and set the DataContext in code behind , Something like this,
<ListBox Margin="0,10,0,88" Name = "lstBox1" ItemsSource= "{Binding}" />
In code behind,
This.DataContext = GetnotesRecord();
Or
lstBox1.ItemsSource = GetnotesRecord();
If I have a Model like this:
public class LayerViewModel
{
public LayerViewModel(string name, string alias, UIElement representation)
{
Name = name;
Alias = alias;
Representation = representation;
}
public string Name { get; set; }
public string Alias { get; set; }
public UIElement Representation
{
get; private set;
}
}
Using the following DataTemplate:
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ContentControl Content="{Binding Representation, Mode=OneTime}"/>
<TextBlock
VerticalAlignment="Center"
Grid.Column="1" Text="{Binding Alias}"
FontSize="{StaticResource PhoneFontSizeLarge}"
Margin="16 21 0 20" TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
If you bind a collection of these models to a ListBox, navigate away and back to the ListBox's containing page, your application will crash. This is because LayerViewModel.Representation is not released from the VisualTree even if the ListBox's ItemSource is set to null when its containing page is being unloaded. I used DependencyObject.GetVisualAncestors() to confirm this.
How do I get a ListBox to completely frees all of the UIElements that comprsises of its VisualTree? Setting its ItemsSource to null doesn't achieve this.