'Specified cast is not valid' when I reload listview items - Xamarin Forms - forms

I'm trying to make an app that saves subjects into an SQLite database and I'm facing an exception: 'Specified cast is not valid'. That happens when I reload the listview items.
(SubjectViewModel.UpdateSubjects())
I receive the data from SubjectServices static class, with async connection.
I set the contentpage binding context to this viewmodel and then set the listview itemssource's binding the SubjectViewModel's SubjectList.
XAML code:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:resx="clr-namespace:MyApp.Resources"
x:Class="MyApp.View.ShellPages.SubjectsPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="{x:Static resx:AppResources.NewSubject}"
Command="{Binding SubjectNewSCommand}"/>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<ListView x:Name="subjectListView" ItemsSource="{Binding SubjectList}"
IsRefreshing="True" RefreshCommand="{Binding SubjectRefreshCommand}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}" Detail="{Binding AddedTime, StringFormat='{0:d}'}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
SubjectViewModel:
using MyApp.Model;
using MyApp.View.ShellPages;
using MyApp.ViewModel.Commands;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text;
namespace MyApp.ViewModel
{
public class SubjectViewModel
{
public ObservableCollection<Subject> SubjectList { get; set; }
public SubjectPageRefreshCommand SubjectRefreshCommand { get; set; }
public SubjectNewSubjectCommand SubjectNewSCommand { get; set; }
public SubjectViewModel()
{
SubjectRefreshCommand = new SubjectPageRefreshCommand(this);
SubjectNewSCommand = new SubjectNewSubjectCommand(this);
SubjectList = new ObservableCollection<Subject>();
}
public async void UpdateSubjects()
{
var subjectList = await SubjectServices.GetSubjects();
SubjectList.Clear();
foreach (var subject in subjectList)
SubjectList.Add(subject);
}
public async void Navigate()
{
await App.Current.MainPage.Navigation.PushAsync(new NewSubjectPage());
}
}
}
Subject class:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
using SQLite;
namespace MyApp.Model
{
public class Subject
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
[MaxLength(50)]
public string Name { get; set; }
public DateTime AddedTime { get; set; }
}
}
What could be the problem? I've tried to find any solution but didn't succeed.
I appreciate any kind of help.

Related

Xamarin forms List in List (navigating using prism)

The issue is that i cant seem to pass through the NavigationService to ModulesModel to use to Navigate to AnotherView items that i can only pass it to SectionModel. but i can only pass the NavigationService to the Parent ListView(Which i dont want) it needs to pass through the child ListView. HELP!!!
UI - CODE
<ListView
SeparatorColor="Transparent"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
ItemsSource="{Binding Data}"
HasUnevenRows="True">
<ListView.Header>
<local:ModuleCourseHeaderViewControl />
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame
HasShadow="False"
BackgroundColor="{StaticResource BiancaBackgroundColour}">
<Frame.CornerRadius>
<OnIdiom
x:TypeArguments="x:Single"
Phone="0"
Tablet="15" />
</Frame.CornerRadius>
<Frame.Margin>
<OnIdiom
x:TypeArguments="Thickness"
Phone="0,10"
Tablet="20,10" />
</Frame.Margin>
<StackLayout>
<Label
FontFamily="{StaticResource LatoRegularFont}"
TextColor="{StaticResource MediumGold}"
Text="{Binding Title}">
<Label.FontSize>
<OnIdiom
x:TypeArguments="x:Double"
Phone="15"
Tablet="17" />
</Label.FontSize>
</Label>
<flv:FlowListView
BackgroundColor="Transparent"
SeparatorVisibility="None"
HasUnevenRows="False"
FlowColumnCount="{DynamicResource ModuleFlowColumnCount}"
RowHeight="{DynamicResource RiseCardHeight}"
FlowItemsSource="{Binding Modules}">
<flv:FlowListView.FlowColumnTemplate>
<OnIdiom
x:TypeArguments="DataTemplate">
<OnIdiom.Phone>
<DataTemplate>
<local:ModuleCourseCardPhoneControl>
<local:ModuleCourseCardPhoneControl.GestureRecognizers>
<TapGestureRecognizer
CommandParameter="{Binding}"
Command="{Binding ItemSelectedCommand}" />
</local:ModuleCourseCardPhoneControl.GestureRecognizers>
</local:ModuleCourseCardPhoneControl>
</DataTemplate>
</OnIdiom.Phone>
<OnIdiom.Tablet>
<DataTemplate>
<local:ModuleCourseCardControl>
<local:ModuleCourseCardControl.GestureRecognizers>
<TapGestureRecognizer
CommandParameter="{Binding}"
Command="{Binding ItemSelectedCommand}" />
</local:ModuleCourseCardControl.GestureRecognizers>
</local:ModuleCourseCardControl>
</DataTemplate>
</OnIdiom.Tablet>
</OnIdiom>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>
</StackLayout>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Models - CODE
public class NewModuleModel
{
public IList<SectionModel> Sections { get; set; }
public int ActiviyId { get; set; }
public string CourseTitle { get; set; }
}
public class SectionModel
{
public string Title { get; set; }
public IList<ModulesModel> Modules { get; set; }
public INavigationService NavigationService { get; set; }
}
public class ModulesModel
{
public int ModuleId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string ModuleImageUrl { get; set; }
public double Progress { get; set; }
public double RoundedProgress
{
get
{
var p = Math.Round(Progress * 100, 0);
return p;
}
}
public DateTime? LastActivityDTUtc { get; set; }
public DateTime? CompletedDate { get; set; }
public string EstimatedDuration { get; set; }
public int AssetCount { get; set; }
public int? NavigationAssetID { get; set; }
public int ActiviyId { get; set; }
public string CourseTitle { get; set; }
public int? NavigationAssetContentType { get; set; }
public string Status
{
get
{
var result = string.Empty;
if (CompletedDate != null)
{
var c = String.Format("{0:d MMMM yyyy}", CompletedDate);
result = "Completed on " + c;
}
else if (LastActivityDTUtc != null)
{
var l = String.Format("{0:d MMMM yyyy}", LastActivityDTUtc);
result = "Last Activity on " + l;
}
else
{
result = "New";
}
return result;
}
}
public ModulesModel()
{
ItemSelectedCommand = new DelegateCommand<ModulesModel>(this.OnCardItemSelectedCommand);
}
private void OnCardItemSelectedCommand(ModulesModel module)
{
if (module.NavigationAssetContentType == 28 && module.AssetCount == 1)
{
var navigationParams = new NavigationParameters();
navigationParams.Add("AssetContentId", module.NavigationAssetID);
navigationParams.Add("AssetActivityId", module.ActiviyId);
navigationParams.Add("AssetModuleId", module.ModuleId);
navigationParams.Add("ParamCourseTitle", module.CourseTitle);
navigationParams.Add("ParamModuleTitle", module.Title);
Preferences.Set("NavFromModulePage", true);
NavigationService.NavigateAsync("AssetWebViewPage", navigationParams, true, false).Forget();
}
else
{
var navigationParams = new NavigationParameters();
navigationParams.Add("ParamModuleId", module.ModuleId);
navigationParams.Add("ParamActivityId", module.ActiviyId);
navigationParams.Add("ParamCourseTitle", module.CourseTitle);
Preferences.Set("NavFromModulePage", false);
//NavigationService.NavigateAsync("ModuleAssetPage", navigationParams, true, false);
}
}
public DelegateCommand<ModulesModel> ItemSelectedCommand { get; set; }
}
}
ViewModel - CODE
private async void LoadData()
{
this.ExecuteAsyncTask(async () =>
{
var result = await this.ModuleService.GetNewModuleAsync(ActivityID);
if (result != null)
{
CourseTitle = result.CourseTitle;
CourseDescription = result.CourseDescription;
CourseImageUrl = result.CourseImageUrl;
DurationInSeconds = result.DurationInSeconds;
DurationAsReadableString = result.DurationAsReadableString;
DisplayDescription = result.DisplayDescription;
Progress = Math.Round(result.Progress * 100, 0);
StartDateUTC = result.StartDateUTC;
EnrolmentDate = result.EnrolmentDate;
LastActivityDate = result.LastActivityDate;
foreach (var item in result.Sections)
{
var itemToAdd = new SectionModel
{
Title = item.Title,
Modules = item.Modules,
NavigationService = navigationService
};
Device.BeginInvokeOnMainThread(() =>
{
this.Data.Add(itemToAdd);
});
}
}
else
{
var exception = new Exception($"Api Error");
}
});
}
}
Remember that MVVM is Model-View-ViewModel. Very often we see people confusing Models and ViewModel's. I'll more indirectly answer your question by showing you the proper architecture. To start we'll look at a ToDoItem model.
public class ToDoItem
{
public string Name { get; set; }
public DateTime Created { get; set; }
public DateTime Due { get; set; }
}
With this note that we can make this easier to Bind by having our model inherit from something like Prism's BindableBase or ReactiveUI's ReactiveObject. I will make the assumption here that you already understand how to make those properties implement INotifyPropertyChanged.
The next thing we need is our ViewModel, we'll say that this is the ToDoItemsPageViewModel
public class ToDoItemsPageViewModel : BindableBase
{
public ObservableCollection<ToDoItem> Items { get; set; }
public DelegateCommand<ToDoItem> ItemSelectedCommand { get; }
private async void ItemSelectedCommandExecuted(ToDoItem item)
{
// do your navigation here..
}
}
Finally we have our ListView or CollectionView (which is what you should use as ListView is being deprecated). For simplicity let's look at the following.
<ListView ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding Name}" />
<Button Text="Show"
Command="{Binding ItemSelectedCommand}"
CommandParameter="{Binding .}" />
</StackLayout>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The core idea to understand here is that the ListView shares the BindingContext of its parent Page. Within our DataTemplate our BindingContext is a ToDoItem and not the ToDoItemsPageViewModel. As a result our binding for the value of Name will return the name of the individual ToDoItem. While our Binding for the CommandParameter will pass in the entire ToDoItem, our Binding for the Command will not work because the ToDoItem has no such command.
Now let's look at how we can access the Command from our ViewModel.
<ListView ItemsSource="{Binding Items}" x:Name="list">
<ListView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding Name}" />
<Button Text="Show"
Command="{Binding BindingContext.ItemSelectedCommand,Source={x:Reference list}}"
CommandParameter="{Binding .}" />
</StackLayout>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
What we've done here are three small changes.
We've added an x:Name to the ListView. This could also be put on the parent Page.
We've changed the Command Binding from ItemSelectedCommand to BindingContext.ItemSelectedCommand
We've changed the Command Binding to include a Source which references the parent item (the list in this case)
What this accomplishes is to update that one specific binding to look at the parent. This effectively sets the BindingContext (for this single property) to the actual parent. In this case you can think of it as the BindingContext being set to the instance of the ListView. This means that our Binding must reference the BindingContext, and then we can dot into access a property of our BindingContext on the ListView.

Xamarin Forms - How to write typeof() in XAML?

The xamarin forms class DataTemplate recieves a parameter with Type in ctor.
public class DataTemplate : ElementTemplate, IDataTemplateController
{
public DataTemplate(Type type);
...
}
How to pass the type of a specific class to a ctor in XAML? In c# I would write new DataTemplate(typeof(DeviceViewModel)). But I have to write this in XAML.
Pseudo code:
<DataTemplate>
<x:Arguments>
<typeof(viewModels:DeviceViewModel)/>
</x:Arguments>
<myControls:MyCustomControl/>
</DataTemplate>
EDIT
To make my goals more clear I created a derived example. Let's say there is following structure:
Picture
Music
Document
txt
pdf
xml
My List contains these elements. Every of this type has to be handled in own DataTemplate. In my case the items are quite complex so thats why I create a ViewModel for each Item. In code it could look like this:
public abstract class BaseViewModel
public class PictureViewModel : BaseViewModel
public class MusicViewModel : BaseViewModel
public class DocumentViewModel : BaseViewModel
/* My List full of different ViewModels*/
List<BaseViewModel> itemList;
Now I create a TemplateSelector which holds other TemplateSelector. It calls the right one based on view model type:
using System;
using Xamarin.Forms;
using MyApp.ViewModels;
namespace MyApp.TemplateSelectors
{
public class MyItemTemplateSelector : DataTemplateSelector
{
public DataTemplateSelector PictureTemplateSelector { get; set; }
public DataTemplateSelector MusicTemplateSelector { get; set; }
public DataTemplateSelector DocumentTemplateSelector { get; set; }
public DataTemplateSelector DefaultTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
switch (item)
{
case PictureViewModel vm:
return PictureTemplateSelector.SelectTemplate(item, container);
case MusicViewModel vm:
return MusicTemplateSelector.SelectTemplate(item, container);
case DocumentViewModel vm:
return DocumentTemplateSelector.SelectTemplate(item, container);
default:
return DefaultTemplate.SelectTemplate(item, container);
}
}
}
}
In XAML all the assignment happens:
<DataTemplate x:Key="PictureDefaultTemplate">
<ViewCell>
<Image Source="{Binding FilePath}"/>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="MusicDefaultTemplate">
<ViewCell>
<Button Text="Play this!"/>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="DocumentDefaultTemplate">
<ViewCell>
<Label Text="show filename at least"/>
</ViewCell>
</DataTemplate>
<!-- The DocumentTemplateSelector handles file extensions differently -->
<DataTemplate x:Key="MyTxtTemplate">
<ViewCell>
<Label Text="This is a text file"/>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="MyPdfTemplate">
<ViewCell>
<Label Text="This is a pdf file"/>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="MyXmlTemplate">
<ViewCell>
<Label Text="This is a xml File"/>
</ViewCell>
</DataTemplate>
<!--provide specific template selectors with initiated datatemplates-->
<templateSelectors:PictureTemplateSelector x:Key="pictureTemplateSelector" DefaultTemplate="{StaticResource PictureDefaultTemplate}"/>
<templateSelectors:MusicTemplateSelector x:Key="musicTemplateSelector" DefaultTemplate="{StaticResource MusicDefaultTemplate}"/>
<templateSelectors:DocumentTemplateSelector x:Key="documentTemplateSelector" DefaultTemplate="{StaticResource DocumentDefaultTemplate}"
TxtTemplate="{StaticResource MyTxtTemplate}"
PdfTemplate="{StaticResource MyPdfTemplate}"
XmlTemplate="{StaticResource MyXmlTemplate}"/>
<!--provide superior template selector with other template selectors -->
<templateSelectors:MyItemTemplateSelector x:Key="myItemTemplateSelector"
PictureTemplateSelector="{StaticResource pictureTemplateSelector}"
MusicTemplateSelector="{StaticResource musicTemplateSelector}"
DocumentTemplateSelector="{StaticResource documentTemplateSelector}"/>
Last bind MyItems (objects of type BaseViewModel) and set superior template selector. This is where I set the CachingStrategy to RecycleElementAndDataTemplate:
<ListView ItemsSource="{Binding MyItems}"
ItemTemplate="{StaticResource myItemTemplateSelector}"
IsPullToRefreshEnabled="True"
CachingStrategy="RecycleElementAndDataTemplate"/>
The Exception is thrown in DocumentTemplateSelector.
using System;
using Xamarin.Forms;
using MyApp.ViewModels;
namespace MyApp.TemplateSelectors
{
public class DocumentTemplateSelector : DataTemplateSelector
{
public DataTemplate TxtTemplate { get; set; }
public DataTemplate PdfTemplate { get; set; }
public DataTemplate XmlTemplate { get; set; }
public DataTemplate DefaultTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
var doc = (DocumentViewModel)item;
switch (doc.FileExtension)
{
case "txt":
return TxtTemplate; // Exception
case "pdf":
return PdfTemplate; // Exception
case "xml":
return XmlTemplate; // Exception
default:
return DefaultTemplate; // Exception
}
}
}
}
Following exception is thrown:
System.NotSupportedException: RecycleElementAndDataTemplate requires DataTemplate activated with ctor taking a type.
#IvanIčin #G.hakim I'm not worried that the default mechanism is not working but after studying the xamarin forms code from github I see no other solution to make it work without passing the type in DataTemplate ctor.
Update: new Xamarin Forms enhancement proposal
https://github.com/xamarin/Xamarin.Forms/issues/7060
Above enhancement would solve my request.

Xceed Datagrid loses SelectedItem when child selected

I have an Xceed datagrid in a WPF MVVM application which is set up to hold master-detail records. When a child row is selected, I want the ViewModel to detect the selected child. I would like to do this preferably with zero code-behind. I have written code which executes an action on the selected item when a contextmenu is clicked. This works correctly when a parent is selected, but always returns null when a child is selected.
I have put together a very simplified version of what I am trying to acheive:
My XAML is:
<Window x:Class="MasterDetailSelection.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xcdg="clr-namespace:Xceed.Wpf.DataGrid;assembly=Xceed.Wpf.DataGrid.v4.2"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<xcdg:DataGridCollectionViewSource x:Key="cvs_parents" Source="{Binding Path=Parents}">
<xcdg:DataGridCollectionViewSource.DetailDescriptions>
<xcdg:PropertyDetailDescription RelationName="Children"
AutoCreateDetailDescriptions="False">
</xcdg:PropertyDetailDescription>
</xcdg:DataGridCollectionViewSource.DetailDescriptions>
</xcdg:DataGridCollectionViewSource>
</Grid.Resources>
<xcdg:DataGridControl x:Name="ParentGrid"
NavigationBehavior="RowOnly"
ItemsSource="{Binding Source={StaticResource cvs_parents}}"
SelectedItem="{Binding SelectedItem}"
AutoCreateDetailConfigurations="True"
ReadOnly="True">
<xcdg:DataGridControl.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Execute Command"
CommandParameter="{Binding DataContext.SelectedItem}"
Command="{Binding DataContext.SampleCommand}" />
</ContextMenu>
</xcdg:DataGridControl.ContextMenu>
</xcdg:DataGridControl>
</Grid>
</Window>
The View Model is:
namespace MasterDetailSelection
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Microsoft.Practices.Composite.Presentation.Commands;
public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<Parent> _parents;
public event PropertyChangedEventHandler PropertyChanged;
private DelegateCommand<Object> _sampleCommand;
private object _selectedItem;
public ObservableCollection<Parent> Parents
{
get { return _parents; }
set
{
_parents = value;
OnPropertyChanged("Parents");
}
}
public DelegateCommand<Object> SampleCommand
{
get
{
if (_sampleCommand == null)
{
_sampleCommand = new DelegateCommand<object>(ExecuteSampleCommand, CanExecuteSampleCommand);
OnPropertyChanged("SampleCommand");
}
return _sampleCommand;
}
}
public bool CanExecuteSampleCommand(Object commandParameter)
{
return true;
}
public void ExecuteSampleCommand(Object commandParameter)
{
Console.WriteLine("ExecuteSampleCommand");
}
public object SelectedItem
{
get { return _selectedItem; }
set
{
if (_selectedItem != value)
{
_selectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
}
public void LoadParents()
{
var parents = new ObservableCollection<Parent>()
{
new Parent()
{
Id=1,
Description = "Parent1",
Children = new List<Child>(){new Child() {Id = 1, Description = "Child1"} }
}
};
Parents = parents;
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
There are 2 simple entities:
public class Parent
{
public int Id { get; set;}
public string Description { get; set;}
public IEnumerable<Child> Children { get; set;}
}
public class Child
{
public int Id { get; set; }
public string Description { get; set; }
}
The OnStartup override in App.xaml.cs contains the following:
var viewModel = new ViewModel();
var window = new MainWindow();
window.DataContext = viewModel;
viewModel.LoadParents();
window.Show();
Whenever i select the parent row, the SelectedItem setter is called with a populated object. When I selected a child row, the same setter is called, but with a null value.
Is there any way I can get a reference to the selected item when the context menu is clicked on a child row - and do this without code-behind. If not, is it possible with code-behind?
Perhaps you should set a context menu directly on the cells or row like below. Then you can send the appropriate model to the command. In the example below I use a static locator class that has my VM to bind the actual command too.
<Style TargetType="{x:Type xcdg:DataCell}">
<Setter Property="ContextMenu" Value="{StaticResource CellContextMenu}">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Execute Command"
CommandParameter="{Binding}"
Command="{Binding Source={StaticResource Locator} Path=ViewModel.SampleCommand}" />
</ContextMenu>
</Setter.Value>
</Setter>
</Style>

deserialize existing xml into custom object

I have the following xml:
<state>
<groups>
<group id='1' name='Basic Search Options'>
<control name='Building' label='In' display='true' configurable='false'/>
<control name='SearchType' label='For' display='true' configurable='false'/>
<control id='1' default='C' name='Search By' label='By'>
<option searchtype='C' searchmode='Cnumber' value='CNumber' label='C Number' display='true'/>
<option searchtype='C' searchmode='crossrefnumber' value='CNumber1' label='Cross Reference Number' display='true'/>
<option searchtype='P' searchmode='' value='CaseNumber' label='P Name' display='true'/>
<option searchtype='P' searchmode='' value='CaseNumber' label='A Name' display='false'/>
</control>
</group>
<group id='2' name='Advanced Search Options'>
<control name='Ctatus' label='C Status' display='true'/>
<control name='DateFiled' label='Date Filed' display='true'/>
</group>
</groups>
How would I de-serialize this into the following object? I dont want my xml to have the following tags "ArrayofGroup", instead the xml should have custom tags like mention above.
public class GroupOfControls
{
public int instanceId { get; set; }
public int GroupId { get; set; }
public string Name { get; set; }
public List<SearchControl> Group { get; set; }
}
public class SearchControl
{
public string Name { get; set; }
public string Label { get; set; }
public bool Display { get; set; }
public string Default { get; set; }
public List<SearchOption> SearchOptions { get; set; }
}
public class SearchOption
{
public string Value { get; set; }
public string Label { get; set; }
public bool Display { get; set; }
public string SearchMode { get; set; }
public string SearchType { get; set; }
}
}
If you don't have an XSD file, you need to create one from your XML. You can do this with the Visual Studio Command Line using the following command:
xsd myfilename.xml
Once you have an XSD file this should be easy enough.
I am working with Visual Studio 2010 (C#/.Net 4) and I would do this:
First I would make a new solution in Visual Studio:
Then you need to import the XSD file into your project by right clicking on your solution, and selecting Add => Existing Item and browsing to the XSD.
Once you have the XSD inside your project you need to launch the Visual Studio command prompt, use cd to navigate to your projects directory and then type the following command:
xsd myFilename.xsd /classes
This generates the C# class you are going to deserialize your XML into. Use the Add Existing Item dialogue to import this new class into your solution.
Next you add using System.Xml.Serialization; and using System.IO; to your using statements. Then use the following code to deserialize your XML to an object (assuming the XML validates against your XSD). The most recent XSD I could file I called ResponseData as shown below:
With this in mind, my C# code is below:
using System;
using System.IO;
using System.Xml.Serialization;
namespace XML_Deserialization
{
class Program
{
static void Main(string[] args)
{
ResponseData myResponseData = new ResponseData();
XmlSerializer mySerializer = new XmlSerializer(typeof(ResponseData));
StreamReader myStreamReader = new StreamReader(#"C:\Users\JMK\Documents\Visual Studio 2010\Projects\scratch\XML Deserialization\XML Deserialization\text.xml");
myResponseData = (ResponseData)mySerializer.Deserialize(myStreamReader);
Console.ReadLine();
}
}
}

How to create DataTemplate in TreeView Silverlight 4.0

I have some complex requirement to create a DataTemplate for a TreeView in Silverlight. This is using MVVM design pattern.
here is what i want:
Package1
Child1
Child2
Package2
Child3
Child4
Code:
Class Package
{
string _Name;
ObservableCollection<Child> _Childs;
public ObservableCollection<Child> Childs{get{return _Childs; } set{_Childs=value;}}
public string PackageName{get{return _Name; } set{_Name=value;}}
}
class Child
{
string ChildName;
public bool IsEnabled{get;set;}
public string Id{get; set;}
}
Using the above data contract i should create a tree view:
Package Name being TreeItem header value.
Each child item is a child box with Content is ChildName and The Enabled property of the checkbox is binded to IsEnabled of Child.
I have tried the following code but it is not showing any tree view at all.
<sdk:TreeView x:Name="SelectedPackagesTV" ItemsSource="{Binding Packages, Mode=TwoWay}"
ItemTemplate="{StaticResource PackageTemplate}">
<sdk:TreeView.Resources>
<DataTemplate x:Key="FormsTemplate" >
<CheckBox Content="{Binding Id, Mode=TwoWay}" IsEnabled="{Binding IsEnabled}" >
</CheckBox>
</DataTemplate>
<sdk:HierarchicalDataTemplate x:Key="PackageTemplate" ItemsSource="{Binding Childs, Mode=TwoWay}" ItemTemplate="{StaticResource FormsTemplate}">
<TextBlock Text="{Binding Name, Mode=TwoWay}" />
</sdk:HierarchicalDataTemplate>
</sdk:TreeView.Resources>
</sdk:TreeView>
NOTE: I am populating values to the PackagesCollection in the view model constructor. Will that be a problem?
Let me know if I am missing anything and also suggest me best way to resolve this.
Thanks in advance.
Edit:
The binding in the "PackageTemplate" is set to "Name" but the public property on the class is "PackageName".
Here is a sample of creating the data and attaching it. I have tested this and it works.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
public class Package
{
public string Name { get; set; }
public ObservableCollection<Child> Childs { get; set; }
}
public class Child
{
public string ChildName { get; set; }
public bool IsEnabled { get; set; }
}
public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<Package> _packages;
public event PropertyChangedEventHandler PropertyChanged;
public string TestStr { get { return "testing123"; } }
public ViewModel()
{
List<Package> list = new List<Package>() { new Package() { Name = "pkg1", Childs = new ObservableCollection<Child>(new List<Child>() { new Child() { ChildName = "Child1" } }) } };
this.Packages = new ObservableCollection<Package>(list);
}
public ObservableCollection<Package> Packages
{
get
{
return this._packages;
}
set
{
this._packages = value;
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
}
A few things:
Your business objects should look like this:
public class Package
{
public string Name { get; set; }
public ObservableCollection<Child> Childs { get; set; }
}
public class Child
{
public string ChildName { get; set; }
public bool IsEnabled { get; set; }
}
Binding can only work on public Properties, not private fields
Your xaml can be corrected to:
<sdk:TreeView ItemTemplate= "{StaticResoruce PackageTemplate}" ItemsSource="{Binding Packages}">
<sdk:TreeView.Resources>
<sdk:HierarchicalDataTemplate x:Key="PackageTemplate"
ItemsSource="{Binding Childs,Mode=TwoWay}"
ItemTemplate="{StaticResource ChildTemplate}">
<TextBlock Text="{Binding Name,Mode=TwoWay}" />
</sdk:HierarchicalDataTemplate>
<sdk:DataTemplate x:Key="ChildTemplate" >
<CheckBox Content="{Binding ChildName,Mode=TwoWay}"
IsEnabled="{Binding IsEnabled}">
</CheckBox>
</sdk:DataTemplate>
</sdk:TreeView.Resources>
The templates need to be in an enclosing "Resources" bracket, either of the TreeView or the UserControl.
Your PackageTemplate should have the ItemsSource "Childs" instead of Packages. You are binding the PackageTemplate to "PackageName" but the Package class states "Name".
Not an error but because your ChildTemplate has no children of its own it only needs to be a DataTemplate, no hierarchy.
Also
ItemTemplate= {"StaticResoruce PackageTemplate"}
Should be:
ItemTemplate= "{StaticResource PackageTemplate}"