ReactiveList does not update in the GUI - reactiveui

I'm trying to make good use of ReactiveList and I think I'm close.
My expectation is that only "toyota" is shown after the user presses the filter button
XAML (yes, quick n dirty, no command for the Filter)
<Window
x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="350"
Width="525">
<StackPanel>
<ComboBox
ItemsSource="{Binding Path=CarsVM}"
DisplayMemberPath="Name" />
<Button
Click="ButtonBase_OnClick">
Filter
</Button>
</StackPanel>
</Window>
The code
using System.Windows;
using ReactiveUI;
namespace WpfApplication1
{
public partial class MainWindow
{
private readonly ViewModel _viewModel;
public MainWindow()
{
InitializeComponent();
_viewModel = new ViewModel();
DataContext = _viewModel;
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
_viewModel.ChangeFilter();
}
}
}
public class CarViewModel : ReactiveObject
{
private bool _isVisible = true;
public CarViewModel(string name)
{
Name = name;
}
public bool IsVisible
{
get { return _isVisible; }
set
{
_isVisible = value;
this.RaiseAndSetIfChanged(ref _isVisible, value);
}
}
public string Name { get; set; }
}
public class ViewModel
{
private readonly ReactiveList<CarViewModel> _cars = new ReactiveList<CarViewModel>
{
new CarViewModel("bmw"),
new CarViewModel("toyota"),
new CarViewModel("opel")
};
public ViewModel()
{
_cars.ChangeTrackingEnabled = true;
CarsVM = _cars.CreateDerivedCollection(x => x, x => x.IsVisible);
}
public IReactiveDerivedList<CarViewModel> CarsVM { get; set; }
public void ChangeFilter()
{
foreach (var car in _cars)
{
car.IsVisible = car.Name.Contains("y");
}
}
}

Your bug is in the setter of IsVisible. By pre-assigning the value of _isVisible, RaiseAndSetIfChanged always thinks that the value has never changed. Remove _isVisible = value; and everything should work.

Related

How to Binding Result from ViewModel in Xamarin

I have 1 question here: How to get data from ViewModel in Xamarin, however I still haven't solved the problem. I created a new post with some changes.
I have:
PageOne.xaml
<StackLayout>
<RefreshView x:DataType="locals:ViewCustomerViewModel" Command="{Binding LoadUserinfoCommand}" IsRefreshing="{Binding IsBusy, Mode=OneWay}">
<Label Text="{Binding Customer.Address}" />
</RefreshView>
</StackLayout>
PageOne.xaml.cs
ViewCustomerViewModel viewCustomerViewModel;
public Customer CustomerGet { get; set; }
public PageOne()
{
InitializeComponent();
BindingContext = viewCustomerViewModel = new ViewCustomerViewModel();
viewCustomerViewModel.OnAppearing();
}
Class Customer
public class Customer
{
public string Address{ get; set; }
........
}
ViewCustomerViewModel
public class ViewCustomerViewModel:BaseCustomerViewModel
{
ApiServiceUserinfo apiServiceUserinfo = new ApiServiceUserinfo();
public Command LoadUserinfoCommand { get; }
public ObservableCollection<Customer> CustomerInfos { get; set; }
public ViewCustomerViewModel()
{
LoadUserinfoCommand = new Command(async () => await ExecuteLoadUserinfoCommand());
CustomerInfos = new ObservableCollection<Customer>();
}
public void OnAppearing()
{
IsBusy = true;
}
async Task ExecuteLoadUserinfoCommand()
{
string userget = "1";
IsBusy = true;
try
{
CustomerInfos.Clear();
var customerList = await apiServiceUserinfo.GetCustomersInfo(userget);
CustomerInfos.Add(customerList);
}
catch (Exception)
{
throw;
}
finally
{
IsBusy = false;
}
}
}
And I got the result CustomerInfos.Add(customerList);
However <Label Text="{Binding Customer.Address}" /> does not get results
Please help me again clearly in the answer. Thank you.
Update
ViewCustomerViewModel
public class ViewCustomerViewModel:BaseCustomerViewModel
{
ApiServiceUserinfo apiServiceUserinfo = new ApiServiceUserinfo();
public Command LoadUserinfoCommand { get; set;}
public Customer CustomerGets { get; set;}--> update
public ViewCustomerViewModel()
{
LoadUserinfoCommand = new Command(async () => await ExecuteLoadUserinfoCommand());
//CustomerGets = new Customer();
}
public void OnAppearing()
{
IsBusy = true;
}
async Task ExecuteLoadUserinfoCommand()
{
string userget = "1";
IsBusy = true;
try
{
var customerList = await apiServiceUserinfo.GetCustomersInfo(userget);
CustomerGets = customerList;
}
catch (Exception)
{
throw;
}
finally
{
IsBusy = false;
}
}
}
PageOne.xaml
<StackLayout>
<RefreshView x:DataType="locals:ViewCustomerViewModel" Command="{Binding LoadUserinfoCommand}" IsRefreshing="{Binding IsBusy, Mode=OneWay}">
<Label Text="{Binding CustomerGets.Address}" />
</RefreshView>
</StackLayout>
We need to call the OnPropertyChanged method to notify the change in setter method of the property .
private Customer customerGets;
public Customer CustomerGets {
get { return customerGets; }
set {
customerGets = value;
NotifyPropertyChanged(); //the method is declared in BaseCustomerViewModel
}
}
Ensure that BaseCustomerViewModel has implemented INotifyPropertyChanged , something like that
public class BaseCustomerViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

Xamarin Forms MVVM iOS ListView doesn't show; SelectedItem has data

I followed this example https://medium.com/swlh/xamarin-forms-mvvm-how-to-work-with-sqlite-db-c-xaml-26fcae303edd
I put a breakpoint in my OnRouteSelected event handler, and e.SelectedItem has the selected object, even though the ListView doesn't display it.
Am I missing something glaring below?
Here is my code:
RoutesPage.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<ContentPage.Content>
<ListView ItemsSource="{Binding Routes}" SelectedItem="{Binding SelectedRoute, Mode=TwoWay}" HasUnevenRows="False" SeparatorColor="Gray" ItemSelected="OnRouteSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Label TextColor="Black" Text="{Binding ROName}"/>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
RoutesPage.xaml.cs
public partial class RoutesPage : ContentPage
{
public RoutesPage()
{
InitializeComponent();
var routeStore = new RouteStore(DependencyService.Get<ISQLiteDb>());
var pageService = new PageService();
ViewModel = new RoutesPageViewModel(routeStore, pageService);
}
protected override void OnAppearing()
{
base.OnAppearing();
ViewModel.LoadDataCommand.Execute(null);
}
void OnRouteSelected(object sender, SelectedItemChangedEventArgs e)
{
ViewModel.SelectRouteCommand.Execute(e.SelectedItem);
}
public RoutesPageViewModel ViewModel
{
get { return BindingContext as RoutesPageViewModel; }
set { BindingContext = value; }
}
}
RoutesPageViewModel.cs The LoadData() method gets the data and adds it to the Routes Collection successfully.
public class RoutesPageViewModel : BaseViewModel
{
private RouteViewModel _selectedRoute;
private IRouteStore _routeStore;
private IPageService _pageService;
private bool _isDataLoaded;
public ObservableCollection<RouteViewModel> Routes { get; private set; }
= new ObservableCollection<RouteViewModel>();
public RouteViewModel SelectedRoute
{
get { return _selectedRoute; }
set { SetValue(ref _selectedRoute, value); }
}
public ICommand LoadDataCommand { get; private set; }
public ICommand AddRouteCommand { get; private set; }
public ICommand SelectRouteCommand { get; private set; }
public ICommand DeleteRouteCommand { get; private set; }
public ICommand CallRouteCommand { get; private set; }
public RoutesPageViewModel(IRouteStore routeStore, IPageService pageService)
{
_routeStore = routeStore;
_pageService = pageService;
LoadDataCommand = new Command(async () => await LoadData());
AddRouteCommand = new Command(async () => await AddRoute());
SelectRouteCommand = new Command<RouteViewModel>(async c => await SelectRoute(c));
}
private async Task LoadData()
{
if (_isDataLoaded)
return;
_isDataLoaded = true;
var routes = await _routeStore.GetRoutesAsync();
foreach (var route in routes)
Routes.Add(new RouteViewModel(route));
}
private async Task AddRoute()
{
// await _pageService.PushAsync(new RoutesDetailPage(new RouteViewModel()));
}
private async Task SelectRoute(RouteViewModel route)
{
if (route == null)
return;
SelectedRoute = null;
// await _pageService.PushAsync(new RoutesDetailPage(route));
}
}
The property in the viewmodels are being set like this:
private string _roName;
public string ROName
{
get { return _roName; }
set
{
SetValue(ref _roName, value);
OnPropertyChanged(nameof(ROName));
}
}
The constructor:
public RouteViewModel(Route route)
{
//other properties
ROName = route.ROName;
}

xamarin: Binding command

Binding command to a Button - yields no effect (Xamarin, MVVM):
notes:
Pressing the Button and nothing happens: no CanExecute check occur.
Binding a Button in a ContentPage which is Part of a Tabbed-Template
functionality check and the rest of related MVVM binding works well: Defined a clicked-event and manually triggered the command from the code behind.
//Could someone see the reason?// editted
editted, new:
What would be a good practice when CanExecute relies on fields of a compound data type that are updated independently ? (*can take of the command parameter which is the compound data type, which is accessible to the command directly through the VM).
xaml for the View:
<ContentPage.Content>
<StackLayout>
<Entry Placeholder="Notes"/>
<Entry x:Name="courseIDEntry"
Text="{Binding CourseID, Mode=TwoWay}"
IsReadOnly="{Binding !ExistUnit}"
Placeholder="CourseID *"/>
<Entry x:Name="unitIDEntry"
Text="{Binding UnitID, Mode=TwoWay}"
IsReadOnly="{Binding !ExistUnit}"
Placeholder="UnitID *"/>enter code here
<Label Text="* Fields are mandatory"/>
<Button x:Name="AddSave"
Text="{Binding CommandText}"
Command="{Binding AddSaveCMD}"
CommandParameter="{Binding EdittedUnit}"/>
<!--Clicked="AddSave_Clicked"/>-->
</StackLayout>
</ContentPage.Content>enter code here
c# code behind for the view (*including the Button-Clicked check for)
public partial class EditUnitPage : ContentPage
{
EditUnitViewModel editUVM;
public EditUnitPage()
{
InitializeComponent();
editUVM = new EditUnitViewModel();
BindingContext = editUVM;
}
public EditUnitPage(Unit6 unitSelected) : this()
{
if (unitSelected != null)
{
editUVM.EdittedUnit = unitSelected;
editUVM.ExistUnit = true;
}
}
protected override void OnAppearing()
{
base.OnAppearing();
}
//private void AddSave_Clicked(object sender, EventArgs e)
//{
// if (editUVM.AddSaveCMD.CanExecute(editUVM.EdittedUnit))
// {
// editUVM.AddSaveCMD.Execute(null);
// }
//}
}
C# MyCommand (newbie. using ICommand and not the Command Class)
public class AddSaveUnitCommand : ICommand
{
public EditUnitViewModel EditUVM { get; set; }
public event EventHandler CanExecuteChanged;
public AddSaveUnitCommand(EditUnitViewModel euvm)
{
EditUVM = euvm;
}
public bool CanExecute(object parameter)
{
var editted = parameter as Unit6;
if (editted != null )
{
if (!string.IsNullOrEmpty(editted.CourseID) || !string.IsNullOrEmpty(editted.UnitID))
return true;
}
return false;
}
public void Execute(object parameterf)
{
EditUVM.AddSaveUnitAsync();
}
}
c# for VM (BaseViewModel implements INotify)
public class EditUnitViewModel : BaseViewModel
{
public AddSaveUnitCommand AddSaveCMD { get; set; }
private Unit6 edittedUnit;
public Unit6 EdittedUnit
{
get { return edittedUnit; }
set { edittedUnit = value; OnPropertyChanged(); }
}
private bool existUnit;
public bool ExistUnit
{
get { return existUnit; }
set
{
existUnit = value;
//OnPropertyChanged();
}
}
public string CommandText
{
get { return ExistUnit? "Save": "Add"; }
}
public string CourseID
{
get { return EdittedUnit.CourseID; }
set { EdittedUnit.CourseID = value; OnPropertyChanged(); }
}
public string UnitID
{
get { return EdittedUnit.UnitID; }
set { EdittedUnit.UnitID = value; OnPropertyChanged(); }
}
public EditUnitViewModel()
{
EdittedUnit = new Unit6();
AddSaveCMD = new AddSaveUnitCommand(this);
}
public async void AddSaveUnitAsync()
{
var curPage = App.Current.MainPage;
try
{
switch (ExistUnit)
{
case false: //insert new unit to the DB
EdittedUnit.UnitKey = ""; //Todo: look for more elegant of assigning auto value to property
Unit6.Insert(EdittedUnit);
break;
case true: //update details on existing unit
EdittedUnit.UnitKey = ""; //Todo: look for more elegant of assigning auto value to property
Unit6.Update(EdittedUnit);
break;
}
await curPage.DisplayAlert("Success", "Unit was succesffuly updateded", "OK");
}
catch
{
await curPage.DisplayAlert("Error", "Unit was not updated", "OK");
}
finally
{
EdittedUnit = null;
await curPage.Navigation.PushAsync(new MyTabbedPage());
}
}
}
xaml for the TabbedPage:
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:P205.Views"
x:Class="P205.Views.MyTabbedPage">
<views:UnitsPage Title="Units" />
<views:EditUnitPage x:Name="editOrAddUnit" Title="Edit U"/>
<views:DBChangesPage Title="Edit DB"/>
<views:CoursesPage Title="Course"/>
<ContentPage Padding="10">
</ContentPage>
When your ViewModel defines a property of type ICommand, the ViewModel must also contain or reference a class that implements the ICommand interface. This class must contain or reference the Execute and CanExecute methods, and fire the CanExecuteChanged event whenever the CanExecute method might return a different value.
So you could try change like below:
public class AddSaveUnitCommand : ICommand
{
public EditUnitViewModel EditUVM { get; set; }
public event EventHandler CanExecuteChanged;
public AddSaveUnitCommand(EditUnitViewModel euvm)
{
EditUVM = euvm;
}
public bool CanExecute(object parameter)
{
var editted = parameter as Unit6;
if (editted != null )
{
if (!string.IsNullOrEmpty(editted.CourseID) || !string.IsNullOrEmpty(editted.UnitID))
return true;
}
return false;
}
public void Execute(object parameterf)
{
EditUVM.AddSaveUnitAsync();
CanExecuteChanged?.Invoke(this, EventArgs.Empty); //add this line.
}
}

Create an ICommand Bindable property on Xamarin Forms

I have a custom checkbox control that I created with an ICommand property and the corresponding bindable property (my checkbox is a Xamarin.Forms XAML Page), the code is:
CheckBox.xaml
<Image x:Name="imgCheckBox"
WidthRequest="20"
HeightRequest="20"/>
<Label x:Name="lblCheckBox"
TextColor="Black"
VerticalOptions="CenterAndExpand"/>
<TapGestureRecognizer Tapped="OnCheckBoxTapped"/>
CheckBox.xaml.cs
public partial class CheckBox : ContentView
{
private static ImageSource uncheckedImage;
private static ImageSource checkedImage;
public CheckBox()
{
InitializeComponent();
uncheckedImage = ImageSource.FromResource("cbUnchecked.png");
checkedImage = ImageSource.FromResource("cbChecked.png");
imgCheckBox.Source = uncheckedImage;
}
public static readonly BindableProperty IsCheckedProperty =
BindableProperty.Create<CheckBox, bool>(
checkbox =>
checkbox.IsChecked,
false,
propertyChanged: (bindable, oldValue, newValue) =>
{
CheckBox checkbox = (CheckBox)bindable;
EventHandler<bool> eventHandler = checkbox.CheckedChanged;
if (eventHandler != null)
{
eventHandler(checkbox, newValue);
}
});
public bool IsChecked
{
set { SetValue(IsCheckedProperty, value); }
get { return (bool)GetValue(IsCheckedProperty); }
}
void OnCheckBoxTapped(object sender, EventArgs args)
{
IsChecked = !IsChecked;
if (IsChecked)
{
imgCheckBox.Source = checkedImage;
}
else
{
imgCheckBox.Source = uncheckedImage;
}
}
public static readonly BindableProperty CheckBoxCommandProperty =
BindableProperty.Create<CheckBox, ICommand>(
checkbox =>
checkbox.CheckBoxCommand,
null,
BindingMode.TwoWay,
propertyChanged: (bindable, oldValue, newValue) =>
{
CheckBox checkbox = (CheckBox)bindable;
EventHandler<bool> eventHandler = checkbox.CheckedChanged;
if (eventHandler != null)
{
eventHandler(checkbox, checkbox.IsChecked);
}
});
public event EventHandler<bool> CheckedChanged;
public ICommand CheckBoxCommand
{
get { return (ICommand)GetValue(CheckBoxCommandProperty); }
set { SetValue(CheckBoxCommandProperty, value); }
}
}
This checkbox implementation is on another Page called TermsAndConditionsPage, that is also a a Xamarin.Forms XAML Page, the code of the implementation is:
<toolkit:CheckBox Text="{Binding txtCheckBox}"
FontSize="Small"
CheckBoxCommand="{Binding OnCheckBoxTapChanged}"
IsChecked="{Binding IsCheckedChanged, Mode=TwoWay}"/>
<Button Text="Next"
Command="{Binding Next_OnClick}"
IsEnabled="{Binding Next_IsEnabled}"
HorizontalOptions="CenterAndExpand"
Clicked="OnNextClicked"/>
The Code Behind of this page is empty (Constructur with InitializeComponent()).
I also have the ViewModel of this page with this code:
TermsAndConditionsViewModel.cs
private string _txtCheckBox;
public string txtCheckBox
{ get { return _txtCheckBox; }
set
{
_txtCheckBox = value;
OnPropertyChanged("txtCheckBox");
}
}
private bool _Next_IsEnabled;
public bool Next_IsEnabled
{
get { return _Next_IsEnabled; }
set
{
_Next_IsEnabled = value;
OnPropertyChanged("Next_IsEnabled");
}
}
private bool _IsCheckedChanged;
public bool IsCheckedChanged
{
get { return _IsCheckedChanged; }
set
{
_IsCheckedChanged = value;
OnPropertyChanged("IsCheckedChanged");
}
}
public ICommand Next_OnClick { get; set; }
public ICommand OnCheckBoxTapChanged { get; set; }
public TermsAndConditionsViewModel()
{
txtCheckBox = "I agree with the terms and conditions";
Next_OnClick = new Command(NextClicked);
OnCheckBoxTapChanged = new Command(CheckBoxTapped);
}
private void CheckBoxTapped()
{
if (IsCheckedChanged)
{ Next_IsEnabled = true; }
else
{ Next_IsEnabled = false; }
}
private void NextClicked()
{ App.Current.MainPage = new Views.HelloWorld(); }
#region INPC
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{ PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); }
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
Now, the question time: the problem I'm having is the CheckBoxTapped Command is not working, I mean, it doesn't do anything, although the checkbox image changes every time I touch it, it does not change the Next_IsEnabled property of my button. I'd like to know what I am missing here to make this command work properly.
EDIT
What I'm looking for is a Command that behaves similarly to the one that Buttons have.
Thanks all for your time!
Since the original answer is now obsolete, here is the new method:
using System.Windows.Input;
public partial class MyControlExample : ContentView
{
// BindableProperty implementation
public static readonly BindableProperty CommandProperty =
BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(MyControlExample), null);
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
// Helper method for invoking commands safely
public static void Execute(ICommand command)
{
if (command == null) return;
if (command.CanExecute(null))
{
command.Execute(null);
}
}
public MyControlExample()
{
InitializeComponent();
}
// this is the command that gets bound by the control in the view
// (ie. a Button, TapRecognizer, or MR.Gestures)
public Command OnTap => new Command(() => Execute(Command));
}
Something like that (pseudocode):
public class YourClassName : View
{
public YourClassName()
{
var gestureRecognizer = new TapGestureRecognizer();
gestureRecognizer.Tapped += (s, e) => {
if (Command != null && Command.CanExecute(null)) {
Command.Execute(null);
}
};
var label = new Label();
label.GestureRecognizers.Add(gestureRecognizer);
}
public static readonly BindableProperty CommandProperty =
BindableProperty.Create<YourClassName, ICommand>(x => x.Command, null);
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
}

WP7 listbox binding not working properly

A noob error for sure (I started yesterday afternoon developing in WP7), but I'm wasting a lot time on it.
I post my class and a little part of my code:
public class ChronoLaps : INotifyPropertyChanged
{
private ObservableCollection<ChronoLap> laps = null;
public int CurrentLap
{
get { return lap; }
set
{
if (value == lap) return;
// Some code here ....
ChronoLap newlap = new ChronoLap()
{
// Some code here ...
};
Laps.Insert(0, newlap);
lap = value;
NotifyPropertyChanged("CurrentLap");
NotifyPropertyChanged("Laps");
}
}
public ObservableCollection<ChronoLap> Laps {
get { return laps; }
set
{
if (value == laps) return;
laps = value;
if (laps != null)
{
laps.CollectionChanged += delegate
{
MeanTime = Laps.Sum(p => p.Time.TotalMilliseconds) / (Laps.Count * 1000);
NotifyPropertyChanged("MeanTime");
};
}
NotifyPropertyChanged("Laps");
}
}
}
MainPage.xaml.cs
public partial class MainPage : PhoneApplicationPage
{
public ChronoLaps History { get; private set; }
private void butStart_Click(object sender, EventArgs e)
{
History = new ChronoLaps();
// History.Laps.Add(new ChronoLap() { Distance = 0 });
LayoutRoot.DataContext = History;
}
}
MainPage.xaml
<phone:PhoneApplicationPage>
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid Grid.Row="2">
<ScrollViewer Margin="-5,13,3,36" Height="758">
<ListBox Name="lbHistory" ItemContainerStyle="{StaticResource ListBoxStyle}"
ItemsSource="{Binding Laps}"
HorizontalAlignment="Left" Margin="5,25,0,0"
VerticalAlignment="Top" Width="444">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Lap}" Width="40" />
<TextBlock Text="{Binding Time}" Width="140" />
<TextBlock Text="{Binding TotalTime}" Width="140" />
<TextBlock Text="{Binding Distance}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
Problem is that when I add one or more items to History.Laps collection, my listbox is not refreshed and these items don't appear.
But if I remove comment on // History.Laps.Add(new ChronoLap()... line, this item appear and so every other inserted later.
More: if I remove that comment and then write History.Laps.Clear() (before or after setting binding) binding is not working anymore. It's like it gets crazy if collection is empty.
I really don't understand the reason...
UPDATE AND SOLUTION:
If i move
History = new ChronoLaps();
LayoutRoot.DataContext = History;
from butStart_Click to public MainPage() everything works as expected.
Can someone explain me the reason?
Actually I see no point of having a separate class for ChronoLaps. Here is how I modified the code for MainPage.xaml.cs and everything seems to be working for me.
public partial class MainPage : PhoneApplicationPage
{
public ObservableCollection<ChronoLap> Laps { get; set; }
public double MeanTime { get; set; }
// Constructor
public MainPage()
{
InitializeComponent();
Laps = new ObservableCollection<ChronoLap>();
Laps.CollectionChanged += delegate
{
MeanTime = Laps.Sum(p => p.Time.TotalMilliseconds) / (Laps.Count * 1000);
};
DataContext = this;
Loaded += (s, e) =>
{
Laps.Add(new ChronoLap() {Time = TimeSpan.FromSeconds(1000)});
Laps.Add(new ChronoLap() {Time = TimeSpan.FromSeconds(1000)});
Laps.Add(new ChronoLap() {Time = TimeSpan.FromSeconds(1000)});
};
}
}
Try binding DataContext and ItemSource for listbox..
How i have done is..
<ListBox x:Name="AppList" Background="White" DataContext="{Binding DisplayItem}" SelectionChanged="AppList_SelectionChanged" Height="500" Width="auto">
<ListBox.ItemTemplate>
<DataTemplate>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And i dont know if it will help but still i will just post the code that i am using..
ItemList.cs
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
namespace AppHouseLibrary
{
public class ItemList : IComparable
{
private string _name;
public string WidgetName
{
get
{
return _name;
}
set
{
_name = value;
}
}
public int ID
{
get;
set;
}
private BitmapImage _Icon;
public BitmapImage Icon
{
get
{
return _Icon;
}
set
{
_Icon = value;
}
}
//public string arrow { get; set; }
public BitmapImage arrow { get; set; }
public int CompareTo(ItemList other)
{
return this.WidgetName.CompareTo(other.WidgetName);
}
}
}
I have a UIManager.cs class in which am refreshing the data before i load it on the UI to the user..
using System;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows.Media.Imaging;
using System.Collections.Generic;
using StirLibrary.com.mportal.data.bean;
using com.mportal.utils;
using StirLibrary.com.mportal.utils;
namespace StirLibrary.com.UI
{
public class UIManager : INotifyPropertyChanged
{
private static UIManager instance = null;
private static string TAG = "UIManager";
BitmapImage arrowImage = Utils.returnImage(ImageUtils.ARROW);
public List<ItemList> data = new List<ItemList>();
public static UIManager getInstance()
{
if (instance == null)
{
instance = new UIManager();
}
return instance;
}
private ObservableCollection<ItemList> _displayItem = new ObservableCollection<ItemList>();
public ObservableCollection<ItemList> DisplayItem
{
get
{
return _displayItem;
}
}
private UIManager()
{
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String PropertyName)
{
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
public WidgetBean[] serviceBeanList = null;
public WidgetBean[] wheelBeanList = null;
public WidgetBean getServiceWidgetBean(int selectedIndex)
{
try
{
if (serviceBeanList != null)
{
return serviceBeanList[selectedIndex];
}
}
catch (Exception e)
{
Logger.log(TAG, e.Message);
}
return null;
}
public WidgetBean getWheelWidgetBean(int selectedIndex)
{
try
{
if (wheelBeanList != null)
{
return wheelBeanList[selectedIndex];
}
}
catch (Exception e)
{
Logger.log(TAG, e.Message);
}
return null;
}
public void DisplayCatalog(string[] ServiceDisplayName, string[] WheelDisplayName, BitmapImage[] ServiceIcons, WidgetBean[] ServiceBeanList, WidgetBean[] WheelBeanList)
{
try
{
DisplayItem.Clear();
string disp1 = string.Empty;
string name = ServiceDisplayName[0];
wheelBeanList = WheelBeanList;
serviceBeanList = ServiceBeanList;
for (int i = 0; i < ServiceDisplayName.Length; i++)
{
WidgetBean bean = serviceBeanList[i];
if (bean.isCategory())
{
DisplayItem.Add(new ItemList { WidgetName = ServiceDisplayName[i], Icon = ServiceIcons[i], arrow = arrowImage });
}
else
{
DisplayItem.Add(new ItemList { WidgetName = ServiceDisplayName[i], Icon = ServiceIcons[i] });
}
}
NotifyPropertyChanged("UI");
}
catch (Exception e)
{
Logger.log(TAG,e.Message);
}
}
public void DisplayCatalog(string[] displayName, BitmapImage[] icons, WidgetBean[] beanArray)
{
try
{
serviceBeanList = beanArray;
DisplayItem.Clear();
for (int i = 0; i < displayName.Length; i++)
{
WidgetBean bean = serviceBeanList[i];
if (bean.isCategory())
{
DisplayItem.Add(new ItemList { WidgetName = displayName[i], Icon = icons[i], arrow = arrowImage });
}
else
{
DisplayItem.Add(new ItemList { WidgetName = displayName[i], Icon = icons[i] });
}
}
NotifyPropertyChanged("UI");
}
catch (Exception e)
{
Logger.log(TAG,e.Message);
}
}
}
}

Resources