Am trying to bind 2 items to a xaml page.One is an observable collection of services the other is an instance of expert item.Am getting an error A first chance exception of type 'System.ArgumentException' occurred in myapp.Client.DLL when I try to raise an INotifyProperty changed for the expert item.
SummaryPage.xaml
//some fields ommitted for brevity Expert
<TextBlock Text="Full Name" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding Expert.name,Mode=TwoWay}" Grid.Column="1" HorizontalAlignment="Center"/>
<TextBlock Text="Age" Grid.Row="1" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding Expert.age}" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"/>
<TextBlock Text="National ID:" Grid.Row="2" HorizontalAlignment="Left"/>
//observable list services
<ListView ItemsSource="{Binding Services}"
IsItemClickEnabled="False"
ScrollViewer.VerticalScrollMode="Enabled"
ScrollViewer.VerticalScrollBarVisibility="Visible"
TabIndex="1" Header="Service Request">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding Cost}" Grid.Column="1" HorizontalAlignment="Center"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
SummaryPageViewModel.cs
public class SummaryPageViewModel : ViewModel, ISummaryPageViewModel
{
public ICommand ConfirmCommand { get; private set; }
public ExpertItem Expert { get { return this.GetValue<ExpertItem>(); } set { this.SetValue(value); } }
public ObservableCollection<ServiceItem> Services { get { return this.GetValue<ObservableCollection<ServiceItem>>(); } set { this.SetValue(value); } }
public SummaryPageViewModel()
{
}
public override void Initialize(IViewModelHost host)
{
base.Initialize(host);
// setup...
this.Services = new ObservableCollection<ServiceItem>();
this.Expert = new ExpertItem();
this.ConfirmCommand = new DelegateCommand((args) => GetSelected(args as CommandExecutionContext));
}
public override async void Activated(object args)
{
base.Activated(args);
var conn = Myapp.GetSystemDatabase();
using (this.EnterBusy())
{
IEnumerable<ServiceItem> servs = await conn.Table<ServiceItem>().ToListAsync();
foreach (ServiceItem s in servs)
this.Services.Add(s);
IEnumerable<ExpertItem> exps = await ExpertItem.GetAllFromCacheAsync();
this.Expert = await conn.Table<ExpertItem>().Where(v => v.NativeId == 3).FirstOrDefaultAsync();
}
}
ModelItem.cs
public abstract class ModelItem : INotifyPropertyChanged
{
private Dictionary<string, object> Values { get; set; }
protected ModelItem()
{
this.Values = new Dictionary<string, object>();
}
public event PropertyChangedEventHandler PropertyChanged;
protected T Get
Value<T>([CallerMemberName] string name = null)
{
if (this.Values.ContainsKey(name))
return (T)this.Values[name];
else
return default(T);
}
protected void SetValue(object value, [CallerMemberName] string name = null)
{
// set...
this.Values[name] = value;
// notify...
this.OnPropertyChanged(new PropertyChangedEventArgs(name));
}
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
this.OnPropertyChanged(new PropertyChangedEventArgs(name));
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, e);//error raised here e- property name expert.Value does not fall in expected range
}
}
ExpertItem.cs
//code omitted for brevity
public class ExpertItem : ModelItem
{
public int Id { get; set; }
public int NativeId { get { return this.GetValue<int>(); } set { this.SetValue(value); } }
public string name { get { return this.GetValue<string>(); } set { this.SetValue(value); } }
public int age { get { return this.GetValue<int>(); } set { this.SetValue(value); } }
public string email { get { return this.GetValue<string>(); } set { this.SetValue(value); } }
}
stacktrace
at System.ComponentModel.PropertyChangedEventHandler.Invoke(Object sender, PropertyChangedEventArgs e)
at MFundi.Client.ModelItem.OnPropertyChanged(PropertyChangedEventArgs e)
at MFundi.Client.ModelItem.SetValue(Object value, String name)
at MFundi.Client.SummaryPageViewModel.set_Expert(ExpertItem value)
at MFundi.Client.SummaryPageViewModel.<Activated>d__b.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__3(Object state)
Related
I am trying to filter my ListView based on my TextBox but it's not firing for some reason. Running the debugger, I can see the input text to be changed but it's not reflected in the ListView.
My Main View Model:
projectCollection = new CollectionViewSource();
projectCollection.Source = Projects;
projectCollection.Filter += projectCollection_Filter;
}
public ICollectionView SourceCollection
{
get
{
return this.projectCollection.View;
}
}
public string FilterText
{
get
{
return filterText;
}
set
{
filterText = value;
this.projectCollection.View.Refresh();
RaisePropertyChanged("SearchProjectsText");
}
}
private void projectCollection_Filter(object sender, FilterEventArgs e)
{
if (string.IsNullOrEmpty(FilterText))
{
e.Accepted = true;
return;
}
Project project = e.Item as Project;
if (project.Name.ToUpper().Contains(FilterText.ToUpper()) || project.Path.ToUpper().Contains(FilterText.ToUpper()))
{
e.Accepted = true;
}
else
{
e.Accepted = false;
}
}
public void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
And my relevant XAML:
<TextBox x:Name="SearchProjectsBox" Grid.Column="5" Background="White" Grid.Row="1" Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}"
Margin="47.333,0,0,654.333" VerticalContentAlignment="Center" Foreground="Black" Padding="6" FontSize="16" HorizontalAlignment="Left" Width="268"/>
<ListView x:Name="ProjectListView" Margin="0,0,10,0" ItemsSource="{Binding ElementName=Hierarchy, Path=SelectedItem.GetAllMembers, UpdateSourceTrigger=PropertyChanged}" FontSize="16" Foreground="Black">
Edit. Here is the XAML.
<TextBox x:Name="SearchProjectsBox" Grid.Column="5" Background="White" Grid.Row="1" Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}"
Margin="47.333,0,0,654.333" VerticalContentAlignment="Center" Foreground="Black" Padding="6" FontSize="16" HorizontalAlignment="Left" Width="268"/>
<TreeView x:Name="Hierarchy" Grid.Column="4" HorizontalAlignment="Left" Height="631" Margin="0,58,0,0" Grid.Row="1" VerticalAlignment="Top" Width="226"
ItemsSource="{Binding Path=Projects}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding ChildFolders}">
<StackPanel Orientation="Horizontal" >
<Image Source="{Binding Icon}" MouseUp="SelectedFolder_Event" Margin="5, 5, 5, 5"></Image>
<TextBox x:Name="FolderNames" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" BorderThickness="0" FontSize="16" Margin="5" IsReadOnly="True" PreviewMouseDoubleClick="SelectAll" LostFocus="TextBoxLostFocus"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
And here is my View Model template.
private ObservableCollection<Project> projects;
private string filterText;
private CollectionViewSource projectCollection;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<Project> Projects
{
get { return projects; }
set
{
if (value != projects)
{
projects = value;
OnPropertyChanged("Projects");
}
}
}
public string FilterText
{
get
{
return filterText;
}
set
{
filterText = value;
this.projectCollection.View.Refresh();
OnPropertyChanged("SearchProjectsText");
}
}
private void projectCollection_Filter(object sender, FilterEventArgs e)
{
if (string.IsNullOrEmpty(FilterText))
{
e.Accepted = true;
return;
}
Project project = e.Item as Project;
if (project.Name.ToUpper().Contains(FilterText.ToUpper()) || project.Path.ToUpper().Contains(FilterText.ToUpper()))
{
e.Accepted = true;
}
else
{
e.Accepted = false;
}
}
public void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
The methods above are the ones that are used to filter and update the List View based on the TextBox's text.
Simple Example for using filters in CollectionView. Refer below code.
<Grid >
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Filter"/>
<TextBox Text="{Binding TextValue, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="200"/>
</StackPanel>
<ListBox ItemsSource="{Binding EmpView}" DisplayMemberPath="Name"/>
</StackPanel>
</Grid>
class ViewModel : INotifyPropertyChanged
{
private string myVar;
public string TextValue
{
get { return myVar; }
set { myVar = value;
OnPropertyChanged("TextValue"); EmpView.Refresh();}
}
public ICollectionView EmpView { get; set; }
public List<Employee> Employees { get; set; }
public ViewModel()
{
Employees = new List<Employee>()
{
new Employee() {Name = "Test1"},
new Employee() {Name = "Version2"},
new Employee() {Name = "Test2"},
new Employee() {Name = "Version4"},
new Employee() {Name = "Version5"}
};
EmpView = CollectionViewSource.GetDefaultView(Employees);
EmpView.Filter = Filter;
}
private bool Filter(object emp)
{
if (string.IsNullOrWhiteSpace(TextValue))
{
return true;
}
var emp1 = emp as Employee;
return TextValue != null && (emp1 != null && emp1.Name.Contains(TextValue));
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
class Employee
{
public string Name { get; set; }
}
My problem, developing a shopping system on a Raspberry Pi 3 Bodel B, is as following:
First of all some context:
Raspberry Pi with Barcode Scanner is used as self-service shop
Employees scans a drink and the price on the screen is added up the price of the drink
Now a extension should be provided: A list of all currently scanned products should be shown.
Until now I only achieved, that every scanned product appears as one ListViewItem in the ListView
This is my Model
public partial class Product : object, System.ComponentModel.INotifyPropertyChanged {
private string DescriptionField;
private System.DateTime ExpirationDateField;
private int IDField;
private string NameField;
private decimal PriceField;
[System.Runtime.Serialization.DataMemberAttribute()]
public string Description {
get {
return this.DescriptionField;
}
set {
if ((object.ReferenceEquals(this.DescriptionField, value) != true)) {
this.DescriptionField = value;
this.RaisePropertyChanged("Description");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public System.DateTime ExpirationDate {
get {
return this.ExpirationDateField;
}
set {
if ((this.ExpirationDateField.Equals(value) != true)) {
this.ExpirationDateField = value;
this.RaisePropertyChanged("ExpirationDate");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public int ID {
get {
return this.IDField;
}
set {
if ((this.IDField.Equals(value) != true)) {
this.IDField = value;
this.RaisePropertyChanged("ID");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string Name {
get {
return this.NameField;
}
set {
if ((object.ReferenceEquals(this.NameField, value) != true)) {
this.NameField = value;
this.RaisePropertyChanged("Name");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public decimal Price {
get {
return this.PriceField;
}
set {
if ((this.PriceField.Equals(value) != true)) {
this.PriceField = value;
this.RaisePropertyChanged("Price");
}
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName) {
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null)) {
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
This model describes a product which can be bought in our shop.
My XAML Snippet
<ListView Name="ProductSumUp"
AllowDrop="False"
SelectionMode="None"
CanDrag="False"
CanReorderItems="False"
CanDragItems="False"
Grid.Column="2"
HorizontalAlignment="Left"
Height="290"
Margin="10,10,0,0"
Grid.Row="1"
VerticalAlignment="Top"
Width="180"
RenderTransformOrigin="1.682,0.59"
Foreground="White"
FontFamily="Assets/Fonts/Baskerville.ttf#Baskerville">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock FontFamily="Assets/Fonts/Baskerville.ttf#Baskerville"
Foreground="White">
<Run Text="{Binding Name}"/>
<Run x:Name="{Binding Price}"/>
</TextBlock>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Now my question is:
Is it possible, if a product was scanned twice, not to add a new ListViewItem, instead, the existing ListViewItem should be manipulated by adding the same Price on the existing Item.
I tried many possibilities and also asked some developers at my work but nobody could figure out.
If you need more information just ask.
Thanks in advance and excuse me for my horrible English grammar :)
So, I worked out a solution by myself with nice support from #JustinXL and #user230910.
I'll just post my code here, so you can see that I came to a solution.
XAML
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock
FontFamily="Assets/Fonts/Baskerville.ttf#Baskerville"
Foreground="White">
<Run Text="{Binding Path=groupedProduct.Name}"/>
<Run Text="{Binding PriceSum,
Converter={StaticResource PriceConverter},
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"/>
<LineBreak/>
<Run Text="{Binding Path=Count,
Converter={StaticResource StringFormatter},
ConverterParameter='Anzahl: {0}',
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
C# - Modelcode
public class ProductGroup : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void onPropertyChanged(object sender, string propertyName)
{
if (this.PropertyChanged != null)
{
PropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
}
}
private decimal _priceSum;
private int _count;
public Product groupedProduct { get; set; }
public int Count
{
get
{
return _count;
}
set
{
_count = value;
onPropertyChanged(this, "Count");
}
}
public decimal Price { get; set; }
public decimal PriceSum
{
get { return _priceSum; }
set
{
_priceSum = value;
onPropertyChanged(this, "PriceSum");
}
}
}
C# - CollectionFill
ProductSumUp.ItemsSource = _showProducts;
bool prodExists = false;
foreach (ProductGroup prodz in _showProducts)
{
if (prodz.groupedProduct.ID == prod.ID)
{
prodExists = true;
}
}
if (!prodExists)
{
ProductGroup prodGroup = new ProductGroup();
prodGroup.groupedProduct = prod;
prodGroup.Price = prod.Price;
prodGroup.Count = 1;
prodGroup.PriceSum += prod.Price;
_showProducts.Add(prodGroup);
}
else
{
ProductGroup pgroup = _showProducts.First(x => x.groupedProduct.ID == prod.ID);
if (pgroup != null)
{
pgroup.Count++;
pgroup.PriceSum += pgroup.Price;
}
}
Please don't judge my programming style, I solved the problem quick and dirty.
I hope that somebody could use my solution for his/her problems and thanks for your help, it saved me a lot of time.
I've tried solving this myself, looking at several possible solutions here on Stack Overflow, but alas I've been unable to solve this issue.
TL;DR version:
The problem:
A listBox using databinding to show a list of RPG characters, which have a nested property for their attributes. I can't get the attributes to show due to the limitations with nested properties and databindings.
The code below is related to the issue.
I have a listBox that has a databinding that controls what is shown in the list. The databinding uses ObservableCollection for the list of objects that the list contains. All this works fine, but is related to the issue at hand.
The listBox databinding has several nested properties in each element, that I want to display and change in the form, yet I cannot get nested databinding to work correctly.
This is the listBox XAML:
<ListBox x:Name="listCharacters" Margin="2,0" ItemsSource="{Binding}" Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Hidden" SelectionChanged="listCharacters_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type local:Character}" x:Name="Symchar">
<Grid Width="125" HorizontalAlignment="Left" Background="{x:Null}">
<Grid.RowDefinitions>
<RowDefinition Height="18"/>
<RowDefinition Height="12"/>
<RowDefinition Height="16"/>
</Grid.RowDefinitions>
<Image Panel.ZIndex="5" HorizontalAlignment="Right" VerticalAlignment="Top" Height="16" Width="16" Margin="0,2,0,0" Source="Resources/1454889983_cross.png" MouseUp="DeleteCharacter" />
<TextBlock Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" FontWeight="Bold" FontSize="13.333" Grid.Row="0" TextTrimming="CharacterEllipsis" Padding="0,0,16,0" />
<TextBlock Text="{Binding RealRace.Label, UpdateSourceTrigger=PropertyChanged}" FontSize="9.333" Grid.Row="1" FontStyle="Italic" />
<TextBlock FontSize="9.333" Grid.Row="2" HorizontalAlignment="Left" VerticalAlignment="Top">
<Run Text="{Binding RealClass.Archetype.Label, UpdateSourceTrigger=PropertyChanged}"/>
<Run Text=" - "/>
<Run Text="{Binding RealClass.Label, UpdateSourceTrigger=PropertyChanged}"/>
</TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And setting the listBox ItemSource:
this.listCharacters.ItemsSource = CharacterList;
This is the character class, I removed unrelated code (XML serialization attributes etc.)
public class Character : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
this.NotifyPropertyChanged("Name");
}
}
private string _player;
public string Player
{
get { return _player; }
set
{
_player = value;
this.NotifyPropertyChanged("Player");
}
}
private string _race;
public string Race
{
get { return _race; }
set
{
_race = value;
this.NotifyPropertyChanged("Race");
}
}
private Race _realRace;
public Race RealRace
{
get { return _realRace; }
set
{
_realRace = value;
Race = value.Id;
this.NotifyPropertyChanged("RealRace");
}
}
private string _gender;
public string Gender
{
get { return _gender; }
set
{
_gender = value;
this.NotifyPropertyChanged("Gender");
}
}
private Attributes _attributes;
public Attributes Attributes
{
get { return _attributes; }
set
{
_attributes = value;
this.NotifyPropertyChanged("Attributes");
}
}
private string _class;
public string Class
{
get { return _class; }
set
{
_class = value;
this.NotifyPropertyChanged("Class");
}
}
private Class _realClass;
public Class RealClass
{
get { return _realClass; }
set
{
_realClass = value;
Class = value.Id;
this.NotifyPropertyChanged("RealClass");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
To keep it simple, the property that I've been testing with, is the 'Attributes' property, this is the code for it:
public class Attributes : INotifyPropertyChanged
{
private int _accurate;
public int Accurate
{
get { return _accurate; }
set
{
_accurate = value;
this.NotifyPropertyChanged("Accurate");
}
}
private int _cunning;
public int Cunning
{
get { return _cunning; }
set
{
_cunning = value;
this.NotifyPropertyChanged("Cunning");
}
}
private int _discreet;
public int Discreet
{
get { return _discreet; }
set
{
_discreet = value;
this.NotifyPropertyChanged("Discreet");
}
}
private int _persuasive;
public int Persuasive
{
get { return _persuasive; }
set
{
_persuasive = value;
this.NotifyPropertyChanged("Persuasive");
}
}
private int _quick;
public int Quick
{
get { return _quick; }
set
{
_quick = value;
this.NotifyPropertyChanged("Quick");
}
}
private int _resolute;
public int Resolute
{
get { return _resolute; }
set
{
_resolute = value;
this.NotifyPropertyChanged("Resolute");
}
}
private int _strong;
public int Strong
{
get { return _strong; }
set
{
_strong = value;
this.NotifyPropertyChanged("Strong");
}
}
private int _vigilant;
public int Vigilant
{
get { return _vigilant; }
set
{
_vigilant = value;
this.NotifyPropertyChanged("Vigilant");
}
}
private int _toughness;
public int Toughness
{
get { return _toughness; }
set
{
_toughness = value;
this.NotifyPropertyChanged("Toughness");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
I want to display each individual attribute in a field when a character in the listBox is selected, this works fine with properties directly in the character class, but due to the limitations on nested properties and databindings, I haven't been able to get it to work with the 'Attributes' properties values.
XAML for one of the attribute input fields:
<TextBox x:Name="attr_Accurate" DataContext="{Binding Path=(local:Character.Attributes), XPath=SelectedItem, ElementName=listCharacters, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Text="{Binding Path=(local:Accurate)}" PreviewTextInput="NumericInput"/>
The UpdateSourceTrigger is simply a method to only allow integers to be input in the field:
private void NumericInput(object sender, TextCompositionEventArgs e)
{
if (!char.IsDigit(e.Text, e.Text.Length - 1))
{
e.Handled = true;
}
}
If anyone could help me get the values within the selected character's attributes to show up via databindings, I would greatly appreciate it.
Use binding as following:
To Show Accurate Property value:
<TextBox x:Name="attr_Accurate" Text="{Binding Path=SelectedItem.Attributes.Accurate), ElementName=listCharacters, Mode=OneWay}" PreviewTextInput="NumericInput"/>
To Show Cunning property value:
<TextBox x:Name="attr_Accurate" Text="{Binding Path=SelectedItem.Attributes.Cunning), ElementName=listCharacters, Mode=OneWay}" PreviewTextInput="NumericInput"/>
and so one.
(I'm not sure if you want binding to be two way or one so please
change as your need)
I am developing an windows phone applicaiton using sqlite database.I have stored all the values in history.xaml.cs but when I run the applicaiton it ends being error on debugger.break as "> SmartParking.DLL!SmartParking.App.RootFrame_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e) Line 133 C#"
Below are all my 3 classes that I am dealing with to store the values in the database and output it in the history.xaml
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="Smart Parking" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="History" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox x:Name="ListData">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name= "DateTxt" Text="{Binding Date}" TextWrapping="Wrap" />
<TextBlock x:Name= "TimeTxt" Text="{Binding Time}" TextWrapping="Wrap" />
<TextBlock x:Name= "ZoneTxt" Text="{Binding Zone}" TextWrapping="Wrap"/>
<TextBlock x:Name= "FloorTxt" Text="{Binding Floor}" TextWrapping="Wrap"/>
<TextBlock x:Name= "LatTxt" Text="{Binding location_latitude}" TextWrapping="Wrap" />
<TextBlock x:Name= "LongTxt" Text="{Binding location_longitude}" TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
below is dbhelper that carries out all the main functions
public class DbHelper
{
SQLiteConnection dbConn;
public async Task<bool> onCreate(string DB_PATH)
{
try
{
if (!CheckFileExists(DB_PATH).Result)
{
using (dbConn = new SQLiteConnection(DB_PATH))
{
dbConn.CreateTable<historyTableSQlite>();
}
}
return true;
}
catch
{
return false;
}
}
private async Task<bool> CheckFileExists(string fileName)
{
try
{
var store = await Windows.Storage.ApplicationData.Current.LocalFolder.GetFileAsync(fileName);
return true;
}
catch
{
return false;
}
}
//retrieve all list from the database
public ObservableCollection<historyTableSQlite> ReadHistory()
{
using (var dbConn = new SQLiteConnection(App.DB_PATH))
{
List<historyTableSQlite> myCollection = dbConn.Table<historyTableSQlite>().ToList<historyTableSQlite>();
ObservableCollection<historyTableSQlite> HistoryList = new ObservableCollection<historyTableSQlite>(myCollection);
return HistoryList;
}
}
// Insert the new info in the histrorytablesqlite table.
public void Insert(historyTableSQlite newcontact)
{
using (var dbConn = new SQLiteConnection(App.DB_PATH))
{
dbConn.RunInTransaction(() =>
{
dbConn.Insert(newcontact);
});
}
}
}
here is the history.xaml.cs code file
public partial class History : PhoneApplicationPage
{
// string dbPath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "db.sqlite");
ObservableCollection<historyTableSQlite> DB_HistoryList = new ObservableCollection<historyTableSQlite>();
public History()
{
InitializeComponent();
AddInfo();
ReadHistoryList_Loaded();
}
public void ReadHistoryList_Loaded()
{
ReadAllContactsList dbhistory = new ReadAllContactsList();
DB_HistoryList = dbhistory.GetAllHistory();//Get all DB contacts
ListData.ItemsSource = DB_HistoryList.OrderByDescending(i => i.Id).ToList();//Latest contact ID can Display first
}
public void AddInfo()
{
// ListData.Items.Add(new historyTableSQlite{
// Date = DateTime.Now.ToShortDateString(),
// Time = DateTime.Now.ToShortTimeString(),
// Zone = "PST",
// Floor = "10th Floor",
// latitude = 35.45112,
// longtitude = -115.42622
//});
DbHelper Db_helper = new DbHelper();
Db_helper.Insert((new historyTableSQlite {
Date = DateTime.Now.ToShortDateString(),
Time = DateTime.Now.ToShortTimeString(),
Zone = "PST",
Floor = "10th Floor",
latitude = 35.45112,
longtitude = -115.42622
}));
}
}
and the last is the class where I intialize all my values
ublic class historyTableSQlite : INotifyPropertyChanged
{
[SQLite.PrimaryKey, SQLite.AutoIncrement]
public int Id { get; set; }
private int idvalue;
private string dateValue = string.Empty;
public string Date {
get { return this.dateValue; }
set
{
if (value != this.dateValue)
{
this.dateValue = value;
NotifyPropertyChanged("Date");
}
}
}
private string timeValue = string.Empty;
public string Time
{
get { return this.timeValue; }
set
{
if (value != this.timeValue)
{
this.timeValue = value;
NotifyPropertyChanged("Time");
}
}
}
private string floorValue = string.Empty;
public string Floor
{
get { return this.floorValue; }
set
{
if (value != this.floorValue)
{
this.floorValue = value;
NotifyPropertyChanged("Floor");
}
}
}
public string zoneValue;
public string Zone
{
get { return this.zoneValue; }
set
{
if (value != this.zoneValue)
{
this.zoneValue = value;
NotifyPropertyChanged("Zone");
}
}
}
private double latValue;
public double latitude
{
get { return latValue; }
set
{
if (value != this.latValue)
{
this.latValue = value;
NotifyPropertyChanged("Latitude");
}
}
}
private double lonValue;
public double longtitude
{
get { return this.lonValue; }
set
{
if (value != this.lonValue)
{
this.lonValue = value;
NotifyPropertyChanged("Longitude");
}
}
}
// public string isMarkPoint { get; set; }
public historyTableSQlite()
{
}
public historyTableSQlite(string date,string time,string floor,string zone,double lat,double lng)
{
Date = date;
Time = time;
Floor = floor;
Zone = zone;
latitude = lat;
longtitude = lng;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
Remove AddInfo() and ReadHistoryList_Loaded() from the History constructor and override OnNavigatedTo() like this.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
AddInfo();
ReadHistoryList_Loaded();
}
If it the page constructor takes long than a few hundred millisecond to create the page windows will assume something has gone wrong. It is best not to put anything in the constructor for this reason.
I've spent lots of hours with this problem.
I have a class with data:
public class User : INotifyPropertyChanged
{
private int _key;
private string _fullName;
private string _nick;
public int Key
{
get{return _key;}
set { _key = value; NotifyPropertyChanged("Key"); }
}
public string Nick
{
get { return _nick; }
set { _nick = value; NotifyPropertyChanged("Nick"); }
}
public string FullName
{
get { return _fullName; }
set { _fullName = value; NotifyPropertyChanged("FullName"); }
}
public User()
{
Nick = "nickname";
FullName = "fullname";
}
public User(String nick, String name, int key)
{
Nick = nick;
FullName = name;
}
//INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public override string ToString()
{
return string.Format("{0} {1}, {2}", Key, Nick, FullName);
}
}
Next I have a class with observablecollection of userClass class:
public class UserList : ObservableCollection<UserList>
{
public UserList (){}
~UserList ()
{
//Serialize();
}
public void Serialize(ObservableCollection<UserList> usersColl)
{
FileStream fs = new FileStream("DataFile.dat", FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(fs, usersColl);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
}
public void Deserialize()
{
FileStream fs = new FileStream("DataFile.dat", FileMode.Open);
try
{
BinaryFormatter formatter = new BinaryFormatter();
//users = (Hashtable) formatter.Deserialize(fs);
//usersColl = (ObservableCollection<userClass>)formatter.Deserialize(fs);
}
catch (SerializationException e)
{
MessageBox.Show(" Error: " + e.Message);
throw;
}
finally
{
fs.Close();
}
}
}
In fact, after lots of testing an editing, big part of code doesn't work, like serialization. But it is not necessary for data binding and binding is what i am solving now.
So i have this collection and want to bind it to listBox.
I tried several ways, but haven't got it to work.
The last one I tried gave me the write error:
The resource 'users' cannot be resolved.
<ListBox Grid.Column="0" Name="userViewLeft" ItemsSource="{Binding Source={StaticResource users} }" />
Some points to be noted
Make Properties public and not private.
Make Variables private.
Follow Naming Conventions and don't append class behind the class.
ItemsSource you supply should be as per scope of the data, In my example the userlist in class scope and I have provided the ItemSource on Window Loaded event.
Here is the an complete example code, In this I have nested the Grid Control inside ListBox because later on you can change the ListBox property for VirtualizingStackPanel.
So that it would give huge performance gain when you have heavy updates on the list.
Also you can use BindingList which is in my opinion better than ObservableCollection performance wise.
User class:
public class User : INotifyPropertyChanged
{
private int _key;
private string _fullName;
private string _nick;
public int Key
{
get { return _key; }
set { _key = value; NotifyPropertyChanged("Key"); }
}
public string NickName
{
get { return _nick; }
set { _nick = value; NotifyPropertyChanged("NickName"); }
}
public string Name
{
get { return _fullName; }
set { _fullName = value; NotifyPropertyChanged("Name"); }
}
public User(String nick, String name, int key)
{
this.NickName = nick;
this.Name = name;
this.Key = key;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public override string ToString()
{
return string.Format("{0} {1}, {2}", Key, NickName, Name);
}
}
User List class:
public class Users : ObservableCollection<User>
{
public Users()
{
Add(new User("Jamy", "James Smith", Count));
Add(new User("Mairy", "Mary Hayes", Count));
Add(new User("Dairy", "Dary Wills", Count));
}
}
XAML:
<Grid>
<Button Content="Start" Height="23" HorizontalAlignment="Left" Margin="416,12,0,0" x:Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
<ListBox x:Name="UserList" HorizontalContentAlignment="Stretch" Margin="12,41,12,12">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="150" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Key}" Margin="3" Grid.Column="0" />
<TextBlock Text="{Binding NickName}" Margin="3" Grid.Column="1" />
<TextBlock Text="{Binding Name}" Margin="3" Grid.Column="2" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
XAML Code behind:
public partial class MainWindow : Window
{
public static Users userslist = new Users();
DispatcherTimer timer = new DispatcherTimer();
public MainWindow()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
timer.Interval = DateTime.Now.AddSeconds(10) - DateTime.Now;
timer.Tick += new EventHandler(timer_Tick);
UserList.ItemsSource = userslist;
}
void timer_Tick(object sender, EventArgs e)
{
userslist.Add(new User("Jamy - " + userslist.Count, "James Smith", userslist.Count));
userslist.Add(new User("Mairy - " + userslist.Count, "Mary Hayes", userslist.Count));
userslist.Add(new User("Dairy - " + userslist.Count, "Dary Wills", userslist.Count));
}
private void button1_Click(object sender, RoutedEventArgs e)
{
if (button1.Content.ToString() == "Start")
{
button1.Content = "Stop";
timer.Start();
}
else
{
button1.Content = "Start";
timer.Stop();
}
}
}
You need to do 2 things:
Firstly, set the DataContext of whatever element (Window/UserControl/whatever) contains your ListBox to an object that looks like:
public class ViewModel
{
public ViewModel() { this.users = new userListClass(); }
public userListClass users { get; private set; }
}
This is your view model, and it is what you want to bind to.
Secondly, change your binding to ItemsSource="{Binding Path=users}". This translates into "set the value of my ItemsSource property to the value of the property users on this.DataContext. Because the DataContext is inherited from the parent, and you set this to the ViewModel class above, your ListBox will now display your user list.