binding not being done with json data - json

I have a listbox and its datacontext is set to a collection. In the background I am fetching data and giving it to the binding element. But it is not reflected in my design. Code goes as follows.
<ListBox Name="StatusListBox"
DataContext="{Binding StatusCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding}" TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In the Page definitions I gave as
DataContext="{Binding StatusViewModel, RelativeSource={RelativeSource Self}}"
d:DataContext="{Binding Source={d:DesignData Source=/Data/SampleData.json, Type=data:DataSource}}"
In cs file I have a statusviewmodel and i give the statusviewmodel, the content i fetched.
public ObservableDictionary StatusViewModel
{
get
{
return this.statusViewModel;
}
}
private async void GetStatusOnline()
{
HttpWebRequest request = HttpWebRequest.Create(requestURI) as HttpWebRequest;
WebResponse response = await request.GetResponseAsync();
ObservableCollection<string> statusCollection = new ObservableCollection<string>();
using (var reader = new StreamReader(response.GetResponseStream()))
{
string textcontent = reader.ReadToEnd();
Debug.WriteLine(textcontent);
DataSource dataSource = new DataSource();
this.StatusViewModel["StatusCollection"] = dataSource.GetStatusCollection(textcontent);
}
}
private ObservableCollection<Status> _statusCollection = new ObservableCollection<Status>();
public ObservableCollection<Status> StatusCollection
{
get
{
return this._statusCollection;
}
}
public IEnumerable<Status> GetStatusCollection(string textcontent)
{
JsonObject jsonObject = JsonObject.Parse(textcontent);
JsonArray jsonArray = jsonObject["items"].GetArray();
foreach (JsonValue value in jsonArray)
{
StatusCollection.Add(new Status(value.GetString()));
}
return StatusCollection;
}
The sample json data is
{
"items": [
"Hi\n",
"This is my new status. How is this?\n",
"This is thrid line."
]
}

You are not settings the ItemSource property of the ListBox. Change
DataContext="{Binding StatusCollection}"
to
ItemSource="{Binding StatusCollection}"

Okay, I'll take a swing at this.
Looking at your XAML code for the Listbox.ItemTemplate and the DataContext,
you've set the data context to be Binding StatusCollection, and in your page definitions you have the DataContext as the Binding StatusViewModel. As well as d:DataContext is {Binding Source={d:DesignData Source=/Data/SampleData.json, Type=data:DataSource}
The issue lies in the Listbox's ItemTemplate for the TextBlock. Since you have the text set as {Binding} which is shorthand, it is assuming that the DataContext is for StatusCollection. In reality, the datacontext you want is for the DesignData source for the JSON file.
So I would suggest changing your StatusViewModel to reflect calling the JSON file, otherwise you have disjointed code whereas your JSON file is never actually read.

Related

How to display JSON in WPF TreeView

I am reading in JSON and then displaying it in a WPF treeview.
Here is the code...
Class MainWindow
Public Sub New()
InitializeComponent()
Dim dic = GetThreadedObject(GetJASN())("phases")
Dim items = dic(0)
tView.ItemsSource = items
End Sub
Private Function GetJASN() As String
Dim output As String = My.Computer.FileSystem.ReadAllText(My.Application.Info.DirectoryPath & "\UAL525 Phase of Flight.json")
Return output
End Function
Private Function GetThreadedObject(JASN As String)
Dim Js As New JavaScriptSerializer()
Js.MaxJsonLength = JASN.Length * 2
Dim j = Js.Deserialize(Of Object)(JASN)
Return j
End Function
End Class
And the WPF...
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<TreeView x:Name="tView">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Value}" >
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="Red"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<TextBlock Text="{Binding Key}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
Start and End points (above) look fine (presumably because they contain child elements to display).
But the Phase element should just contain one value. A single string that reads "GROUND". But it is broken up into a charArray for some reason. And displayed in multiple elements as shown above.
So what is the key to fixing this? Multiple data templates that display a string differently from other objects?
Here is the code Rekshino submitted, in Vb.
Imports System.Globalization
Public Class ValConv
Implements IValueConverter
Private Function IValueConverter_Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
If (TypeOf value Is String) Then
Dim newStr As New List(Of String)
newStr.Add(value)
Return newStr
Else
Return value
End If
End Function
Private Function IValueConverter_ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
Return value
End Function
End Class
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp2"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<local:ValConv x:Key="valConv"/>
</Window.Resources>
<Grid>
<TreeView x:Name="tView">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Value, Converter={StaticResource valConv}}" >
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="Red"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<TextBlock Text="{Binding Key}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
The problem is that your XAML can only show a collections in dictionary's value and if there is a string, then it will be considered as collection of characters. One of the quick sollutions is to create a converter, which will transform your strings into string collections.
For this you need a value converter(sorry I do code in c#)
public class ValConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string str)
{
return new List<string> { str };
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
Instantiate this converter in resources:
<Window.Resources>
<local:ValConv x:Key="valKonv"/>
</Window.Resources>
and use it:
<HierarchicalDataTemplate ItemsSource="{Binding Value, Converter={StaticResource valConv}}" >
I needed a more generic operation to consume any JSON.
This code uses the nuget Newtonsoft JSON to do the magic of taking any raw JSON (without models) and loading it into a TreeView which looks like this:
JSON
string jsonString = #"[{""BatchId"":0,""AccessionChanges"":[{""LabId"":8675309,""InstanceChanges"":[{""Property"":""Note"",""ChangedTo"":""Jabberwocky"",""UniqueId"":null,""SummaryInstance"":null},{""Property"":""Instrument"",""ChangedTo"":""instrumented"",""UniqueId"":null,""SummaryInstance"":null}],""DetailChanges"":[{""Property"":""Comments"",""ChangedTo"":""2nd Comment"",""UniqueId"":null,""SummaryInstance"":null},{""Property"":""CCC"",""ChangedTo"":""XR71"",""UniqueId"":null,""SummaryInstance"":null}]}]}]";
Xaml <TreeView x:Name="tView" />
Codbehind Xaml
InitializeComponent();
try
{
tView.Items.Add(JSONOperation.Json2Tree(JArray.Parse(jsonString), "Root"));
}
catch (JsonReaderException jre)
{
MessageBox.Show($"Invalid Json {jre.Message}");
}
public static class JSONOperation
public static TreeViewItem Json2Tree(JToken root, string rootName = "")
{
var parent = new TreeViewItem() { Header = rootName };
foreach (JToken obj in root)
foreach (KeyValuePair<string, JToken> token in (JObject)obj)
switch (token.Value.Type)
{
case JTokenType.Array:
var jArray = token.Value as JArray;
if (jArray?.Any() ?? false)
parent.Items.Add(Json2Tree(token.Value as JArray, token.Key));
else
parent.Items.Add($"\x22{token.Key}\x22 : [ ]"); // Empty array
break;
case JTokenType.Object:
parent.Items.Add(Json2Tree((JObject)token.Value, token.Key));
break;
default:
parent.Items.Add(GetChild(token));
break;
}
return parent;
}
private static TreeViewItem GetChild(KeyValuePair<string, JToken> token)
{
var value = token.Value.ToString();
var outputValue = string.IsNullOrEmpty(value) ? "null" : value;
return new TreeViewItem() { Header = $" \x22{token.Key}\x22 : \x22{outputValue}\x22"};
}

Binding data from Linq Database using Observable Collection - WP8

I'm saving some data in a database using linq. I have a DAO class, where I put all my CRUD methods, and I have another class where I define my table and its columns.
[Table(Name = "CONTACTS")]
public class UserContacts
{
private int _id;
[Column(Name = "ID", IsPrimaryKey = true, IsDbGenerated = true, CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int ID
{
get { return _id; }
set { _id = value; }
}
private string _name;
[Column(Name = "NAME", CanBeNull = false)]
public string NAME
{
get { return _name; }
set { _name = value; }
}
private string _number;
[Column(Name = "NUMBER", CanBeNull = false)]
public string NUMBER
{
get { return _number; }
set { _number = value; }
}
}
DAO Class
public class DAOUserContacts
{
public IList<UserContacts> list = new List<UserContacts>();
public IList<UserContacts> GetData()
{
try
{
using (DataBaseContext db = new DataBaseContext(DataBaseContext.ConnectionString))
{
list = (from info in db.UserContacts orderby info.COLUMN_NAME ascending select info).ToList();
}
return list;
}
catch (Exception)
{
return null;
}
}
// Other methods
}
I'm showing all data stored in this database in a LongListSelector.
In Main.cs constructor
llsContacts.DataContext = new DAORUserContacts().GetData();
In Main.xaml
<phone:LongListSelector x:Name="llsContacts" ItemsSource="{Binding}" >
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<ListBoxItem local:TiltEffect.IsTiltEnabled="true">
<Grid Margin="0" >
<TextBlock Text="{Binding NAME}" FontFamily="Segoe WP" FontSize="28" Margin="77,0,0,0" />
<TextBlock Text="{Binding NUMBER}" FontFamily="Segoe WP Light" FontSize="17" Margin="77,33,0,0"/>
</Grid>
</ListBoxItem>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
I made a research on internet, and found about ObservableCollection, and I want to use it. I read this article http://www.codeproject.com/Articles/80555/Databinding-in-Silverlight-applications#_Toc261149245 to understand how it works, but I still have some doubts.
On this article, was created an Employee that inherits from INotifyPropertyChanged, and an Emplyees that inherits from ObservableCollection.
In my case, I want that my list (on xaml) always shows what is in database.
Is OK inheriting my UserContacts from INotifyPropertyChanged? Because this class declares a Table...
And should my DAOClass inherits from ObservableCollection? Or just my GetData() returns a ObservableCollection instead of a List?
Another thing.. there is a button that, when the user press, updates the database (search all the contacts on device, and remove from database what had been removed in phone, and add to database what had been add in phone).
Using ObservableCollection, when the search for contacts finishes, and my database is updated, should I call something to update the LongListSelector on xaml? Or after the database update, the LongListSelector is automatically updated too?
Thanks...
User viewmodel for assigning data context and assign observable collection at xaml side as binding.And viewmodel should have observable collection which you use for binding.Then if you made any changes for the collection automatically updates the longlistselector.
Every time you should change the collection according to your database changes.

binding device image path windows phone 8.1

How to bind device image path windows phone.
Below is image path
"C://Data//Users//Public//Pictures//Camera Roll//WP_20141001_002.jpg"
Thanks
I'm not sure if in your case using string is a good choice - maybe it will be possible to use BitmapImage - obtain a StorageFile from path, open Stream and then set BitmapImage - in this case you perform async operations outside converter.
In case you still want to use string it's possible, but will need some special approach - using async methods along with binding. There is a very good article about aynchronous MVVM, written by Stephen Cleary. Basing on the article and other Stephen's answer I've made such a code:
First of all, we will have to define a Converter - it's little complicated as getting file and stream is asynchronous:
/// <summary>
/// Converter getting an image basing upon delivered path
/// </summary>
public class PathToImage : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var task = GetImage((String)value);
// the below class you will find in Stephen's answer mentioned above
return new TaskCompletionNotifier<BitmapImage>(task);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{ throw new NotImplementedException(); }
private async Task<BitmapImage> GetImage(string path)
{
StorageFile file = await StorageFile.GetFileFromPathAsync(path);
using (var stream = await file.OpenAsync(FileAccessMode.Read))
{
BitmapImage image = new BitmapImage();
image.SetSource(stream);
return image;
}
}
}
In our page we will need a property, which we will use in binding and set the DataContext:
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
private string imagePath;
public string ImagePath
{
get { return imagePath; }
set { imagePath = value; RaiseProperty("ImagePath"); }
}
public MainPage()
{
this.InitializeComponent();
DataContext = this;
}
// rest of the code
Of course we have to define our binding - for example in XAML, it's little tricky as first we have to bind the DataContext to our Task then bind Source to the Result, which will be raised as the image is loaded:
<Image DataContext="{Binding ImagePath, Converter={StaticResource PathToImage}}" Stretch="Uniform"
Source="{Binding Result} HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
Once we have this all, we can set the property like this:
ImagePath = #"C:\Data\Users\Public\Pictures\Camera Roll\WP_20141001_002.jpg";
and we should see the result on the screen.

How to refresh the data in pivot item after updating data through xaml UI?

Hello all i am working on windows phone 8 app, i am facing a issue, i am loading some data in my pivot item and if user tap a user control opens and i modify the data through user control. Data is saving into the database successfully but my pivot item is not updating immediately. i am using observable collection as following.
ObservableCollection i used like following in mypivot.xaml.cs file
ObservableCollection<MyWrapper> saveinfo = new ObservableCollection<MyWrapper>();
public ObservableCollection<MyWrapper> savedWordBankCollection
{ get { return saveinfo; } }
//MyWrapper class structure
public class MyWrapper: INotifyPropertyChanged
{
private string desc;
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyChange(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
public string Name { get; set; }
public string NameDescription
{
get { return desc; }
set
{
desc = value;
NotifyChange(new PropertyChangedEventArgs("NameDescription"));
}
}
public string NameId { get; set; }
public string NameLocId { get; set; }
}
Now as following i am loading data into my pivot item in pivot page
private void LoadWordbank()
{
List<MysecondWrapper> dbData = helper.FetchAllName(thisApp.CurrentName.Id);
if (dbData.Count != 0)
{
foreach (MySerconWrapper item in dbData)
{
saveinfo.Add(new MyWrapper { NameLocalId = item.Id.ToString(), Name= item.Name, NameDescription = item.Description, NameId = thisApp.CurrentName.Id});
}
}
}
mypivot.xaml as follwoing. i am not writing full code but how i have assigned the attributes that i am showing.
<TextBlock x:Name="wordbankStored" Grid.Column="0" Grid.Row="0" Text="{Binding Name}"/>
<Button x:Name="btnWordDescription" Grid.Row="1" Grid.Column="0" Content="{Binding NameDescription}"
Tag="{Binding}" Click="btnNameDescription_Click"/>
In above textblocks i tried:
Content="{Binding NameDescription, Mode=TwoWay}"
but it didn't work so i have removed. on btnNameDescription_Click my user control opens and i can save data in my local db of wp8 but it does not show immediately in my pivot. Please give me suggession what and how to do ? where i am wrong. need help.
I have done, first of all no need to refresh the page, observable collection can do it automatically. my observableCollection is saveInfoCollection.
there are three possiblities with the observable collection
1) deletion a item from observable collection.
2) Modifying a item in observable collection.
3) Add a item in observable collection.
Explaination
1) In first case when i will delete the item from the observable collection i will use the remove method of the observable collection like following
//savedData is my observableCollection name.
savedData.Remove(selected);
2) In second case when i will modify the item from the observable collection, here you will see the magic of the observable collection, I am taking the item object with the help of Tag property, so as i will update my database it my observable collection will automatically update.
3) In this case you can add new data object into the observable collection, and it will automatically update the observable collection.
If you are using the observableCollection than no need to refresh the page. It is the magic of ViewModel.

Binding a Dictionary to a WinRT ListBox

I've read a number of posts on binding Dictionary to WPF ListView and ListBox but I can't get equivalent code to work in WinRT.
<Grid Margin="10" Width="1000" VerticalAlignment="Stretch">
<ListBox Name="StatListView" ItemsSource="{Binding FooDictionary}" >
<ListBox.ItemTemplate>
<DataTemplate >
<Grid Margin="6">
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding Key}" Margin="5" />
<TextBlock Text="{Binding Value}" Margin="5" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
public Dictionary<string, string> FooDictionary
{
get
{
Dictionary<string, string> temp = new Dictionary<string, string>();
temp.Add("key1", "value1");
temp.Add("key2", "value2");
temp.Add("key3", "value3");
temp.Add("key4", "value4");
return temp;
}
}
What is the proper binding?
The error in the output window is (trimmed to the most useful part):
Error: Cannot get 'Key' value (type 'String') from type
'System.Runtime.InteropServices.WindowsRuntime.CLRIKeyValuePairImpl`2
[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, ....
Internally, WinRT is converting the type to:
System.Runtime.InteropServices.WindowsRuntime.CLRIKeyValuePairImpl<K, V>
If you add to your DataTemplate:
<TextBlock Text="{Binding}" Margin="5" />
You'll see that it emits the above type with String, String.
However, for some reason, it's not being properly handled as expected. If you search for that type on the Internet, you'll see that there's a documented bug for the issue on Connect.
A simple work around would be to place your data in a simple object that is not a KeyValuePair:
List<StringKeyValue> temp = new List<StringKeyValue>();
temp.Add(new StringKeyValue { Key = "key1", Value = "value1" } );
temp.Add(new StringKeyValue { Key = "key2", Value = "value2" });
temp.Add(new StringKeyValue { Key = "key3", Value = "value3" });
temp.Add(new StringKeyValue { Key = "key4", Value = "value4" });
this.DefaultViewModel["FooDictionary"] = temp;
public class StringKeyValue
{
public string Key { get; set; }
public string Value { get; set; }
}
As an aside, from a simple test at least, it's not the Dictionary that's causing the issue at all, it's the fact that it's a KeyValuePair object instance that's being converted to the CLRIKeyValuePairImpl type mentioned above. I tried just using a list and adding a KeyValuePair<string, string> instance to a List, and that failed as well.
I've come up with a workaround, that involves generating your own Key Value pairs dynamically.
If you've specialized Dictionary, just add this:
public IEnumerable<MyPair<K, V>> Collection
{
get {
foreach (var v in this)
{
MyPair<K, V> p = new MyPair<K, V>() { Key = v.Key, Value = v.Value };
yield return p;
}
}
}
and define your Pair type:
public class MyPair<K, V>
{
public K Key { get; set; }
public V Value { get; set; }
}
Also, be careful that you create a new object each time. Some items walk across the object, and store the return, which can lead to everything looking like the last item, if you try to reuse the MyPair like I originally did.