Hi Xamarin Developers,
In one of the class I am having a listView and I am getting the Data From ViewModel. So When user is pressing header I am expanding the list and I am changing the value of expand Variable.. When I am loading the page for next time, then also that expand Variable. value is still true and by default the list is expanded. Can anybody tell me how to resetViewModel on every-time page loads??
My Model Class.
public class CourseCatalogModel : ObservableCollection<DashboardCard>, INotifyPropertyChanged
{
private bool _expanded;
public string Title { get; set; }
private int _dataCount;
public int DataCount
{
get { return _dataCount; }
set
{
if (_dataCount != value)
{
_dataCount = value;
OnPropertyChanged("StateIcon");
OnPropertyChanged("TitleColor");
}
}
}
public string TitleColor
{
get
{
if (DataCount == 0)
{
return "#FFAEB2B5";
}
return "#FF00588A";
}
}
public bool Expanded
{
get { return _expanded; }
set
{
if (_expanded != value)
{
_expanded = value;
OnPropertyChanged("Expanded");
OnPropertyChanged("StateIcon");
}
}
}
public string StateIcon
{
get
{
if (DataCount == 0)
{
return "expand_empty";
}
return Expanded ? "expand_iCon.png" : "collapse_icon.png";
}
}
public CourseCatalogModel(string title, bool expanded = true)
{
Title = title;
Expanded = expanded;
}
public static ObservableCollection<CourseCatalogModel> CourseCatalogAll { private set; get; }
public static ObservableCollection<CourseCatalogModel> CourseCatalogRequired { private set; get; }
public static ObservableCollection<CourseCatalogModel> CourseCatalogNotRequired { private set; get; }
static CourseCatalogModel()
{
// Course Awaiting Approvel...
CourseCatalogModel awaitingApprovel = new CourseCatalogModel("Awaiting Approval", false);
var awaitingCards = CourseCatalogModuleHelper.GetAwaitingApprovels();
foreach (var dashboardCard in awaitingCards)
{
awaitingApprovel.Add(dashboardCard);
}
// Course Pending Courses...
CourseCatalogModel pendingCourses = new CourseCatalogModel("Pending Courses", false);
var pendingCourseCards = CourseCatalogModuleHelper.GetPendingCourses();
foreach (var dashboardCard in pendingCourseCards)
{
pendingCourses.Add(dashboardCard);
}
// Course Completed Courses...
CourseCatalogModel completedCourses = new CourseCatalogModel("Completed Courses", false);
var completedCourseCards = CourseCatalogModuleHelper.GetCompletedCourses();
foreach (var dashboardCard in completedCourseCards)
{
completedCourses.Add(dashboardCard);
}
ObservableCollection<CourseCatalogModel>
CourseCatalogdata = new ObservableCollection<CourseCatalogModel>();
CourseCatalogdata.Add(awaitingApprovel);
CourseCatalogdata.Add(pendingCourses);
CourseCatalogdata.Add(completedCourses);
CourseCatalogAll = CourseCatalogdata;
GetRequiredCourseCatalogCards();
GetNotRequiredCourseCatalogCards();
}
private static void GetRequiredCourseCatalogCards()
{
// Course Awaiting Approvel...
CourseCatalogModel awaitingApprovel = new CourseCatalogModel("Awaiting Approval", false);
var awaitingCards = CourseCatalogModuleHelper.GetAwaitingApprovels(AppConstants.CourseFilterRequired);
foreach (var dashboardCard in awaitingCards)
{
awaitingApprovel.Add(dashboardCard);
}
// Course Pending Courses...
CourseCatalogModel pendingCourses = new CourseCatalogModel("Pending Courses", false);
var pendingCourseCards = CourseCatalogModuleHelper.GetPendingCourses(AppConstants.CourseFilterRequired);
foreach (var dashboardCard in pendingCourseCards)
{
pendingCourses.Add(dashboardCard);
}
// Course Completed Courses...
CourseCatalogModel completedCourses = new CourseCatalogModel("Completed Courses", false);
var completedCourseCards = CourseCatalogModuleHelper.GetCompletedCourses(AppConstants.CourseFilterRequired);
foreach (var dashboardCard in completedCourseCards)
{
completedCourses.Add(dashboardCard);
}
ObservableCollection<CourseCatalogModel>
CourseCatalogdata = new ObservableCollection<CourseCatalogModel>();
CourseCatalogdata.Add(awaitingApprovel);
CourseCatalogdata.Add(pendingCourses);
CourseCatalogdata.Add(completedCourses);
CourseCatalogRequired = CourseCatalogdata;
}
private static void GetNotRequiredCourseCatalogCards()
{
// Course Awaiting Approvel...
CourseCatalogModel awaitingApprovel = new CourseCatalogModel("Awaiting Approval", false);
var awaitingCards = CourseCatalogModuleHelper.GetAwaitingApprovels(AppConstants.CourseFilterNotRequired);
foreach (var dashboardCard in awaitingCards)
{
awaitingApprovel.Add(dashboardCard);
}
// Course Pending Courses...
CourseCatalogModel pendingCourses = new CourseCatalogModel("Pending Courses", false);
var pendingCourseCards = CourseCatalogModuleHelper.GetPendingCourses(AppConstants.CourseFilterNotRequired);
foreach (var dashboardCard in pendingCourseCards)
{
pendingCourses.Add(dashboardCard);
}
// Course Completed Courses...
CourseCatalogModel completedCourses = new CourseCatalogModel("Completed Courses", false);
var completedCourseCards = CourseCatalogModuleHelper.GetCompletedCourses(AppConstants.CourseFilterNotRequired);
foreach (var dashboardCard in completedCourseCards)
{
completedCourses.Add(dashboardCard);
}
ObservableCollection<CourseCatalogModel>
CourseCatalogdata = new ObservableCollection<CourseCatalogModel>();
CourseCatalogdata.Add(awaitingApprovel);
CourseCatalogdata.Add(pendingCourses);
CourseCatalogdata.Add(completedCourses);
CourseCatalogNotRequired = CourseCatalogdata;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
And in my page , this is how I am changing Value
public partial class CourseCatalogBaseClass : ContentPage
{
public ObservableCollection<CourseCatalogModel> _allGroups;
ObservableCollection<CourseCatalogModel> _expandedGroups;
List<DashboardCard> allListData;
ObservableCollection<DashboardCard> searchListData;
private string screenLabelString = string.Empty;
public ObservableCollection<FilterPopupModel> courseFilterPopupModels = new ObservableCollection<FilterPopupModel>();
public CourseCatalogBaseClass(bool isFromQualifications = false)
{
InitializeComponent();
if (isFromQualifications)
{
screenLabel.Text = "My Qualifications";
screenLabelString = screenLabel.Text;
}
allListData = App.DashboardResponse.TrainingContentCards;
CourseCatalogSearchListView.IsVisible = false;
_allGroups = CourseCatalogModel.CourseCatalogAll;
UpdateCourseCatalagListContent();
InitilizeFilters();
}
private void InitilizeFilters()
{
courseFilterPopupModels.Add(new FilterPopupModel()
{Title = "All Classes", TitleColor = Color.FromHex("#00588A")});
courseFilterPopupModels.Add(new FilterPopupModel()
{Title = "Required", TitleColor = Color.FromHex("#686868")});
courseFilterPopupModels.Add(new FilterPopupModel()
{Title = "Not Required", TitleColor = Color.FromHex("#686868")});
courseFilterPopupModels.Add(new FilterPopupModel() {Title = "Help", TitleColor = Color.FromHex("#686868")});
}
private void CourseListHeaderTapped(object sender, EventArgs args)
{
int selectedIndex = _expandedGroups.IndexOf(
((CourseCatalogModel) ((Button) sender).CommandParameter));
_allGroups[selectedIndex].Expanded = !_allGroups[selectedIndex].Expanded;
UpdateCourseCatalagListContent();
}
void Handle_Search_Bar_TextChanged(object sender, Xamarin.Forms.TextChangedEventArgs e)
{
var entry = (Entry) sender;
searchListData = new ObservableCollection<DashboardCard>();
if (string.IsNullOrWhiteSpace(entry.Text))
{
screenLabel.Text = screenLabelString;
CourseCatalogSearchListView.IsVisible = false;
CourseCatalogListView.IsVisible = true;
}
else
{
screenLabel.Text = "Search Course";
foreach (DashboardCard card in allListData)
{
var courseCode = card.Course;
if (courseCode.ToLower().Contains(entry.Text.ToLower()))
{
searchListData.Add(card);
}
}
searchListData = new ObservableCollection<DashboardCard>(allListData.Where(i =>
(i is DashboardCard && (((DashboardCard) i).Course.ToLower().Contains(entry.Text.ToLower())))));
CourseCatalogSearchListView.ItemsSource = searchListData;
CourseCatalogSearchListView.IsVisible = true;
CourseCatalogListView.IsVisible = false;
}
Console.WriteLine(searchListData.Count);
}
void Menu_Button_Clicked(object sender, System.EventArgs e)
{
Navigation.PushModalAsync(new MenuPage());
//
}
async void Filter_Handle_Clicked(object sender, System.EventArgs e)
{
if (!CourseCatalogSearchListView.IsVisible)
{
var page = new CourseCatalogFilterPopup(this);
await PopupNavigation.Instance.PushAsync(page);
}
else
{
await DisplayAlert(AppConstants.AppName, "Please Close the Search to access Filter",
AppConstants.OK);
}
}
async void Filter_three_dot_Handle_Clicked(object sender, System.EventArgs e)
{
var page = new CourseCatalogMorePopup();
await PopupNavigation.Instance.PushAsync(page);
}
async void Course_List_ItemSelected(object sender, Xamarin.Forms.SelectedItemChangedEventArgs e)
{
DashboardCard dashboardCard = (DashboardCard)e.SelectedItem;
if (!dashboardCard.Status.Equals("TAKEN") &&
!dashboardCard.Status.Equals("EQUIV") &&
!dashboardCard.Status.Equals("SKILL") &&
!dashboardCard.Pending.Equals("WRA") &&
dashboardCard.SelfTrain.Equals("Y"))
{
var page = new SelfTrainBasePage(dashboardCard);
await Navigation.PushModalAsync(page);
}
else
{
await DisplayAlert("iSOTrain", "Yet to be implemented.", "OK");
}
}
async void Course_Search_List_ItemSelected(object sender, Xamarin.Forms.SelectedItemChangedEventArgs e)
{
DashboardCard dashboardCard = (DashboardCard)e.SelectedItem;
if (!dashboardCard.Status.Equals("TAKEN") &&
!dashboardCard.Status.Equals("EQUIV") &&
!dashboardCard.Status.Equals("SKILL") &&
!dashboardCard.Pending.Equals("WRA") &&
dashboardCard.SelfTrain.Equals("Y"))
{
var page = new SelfTrainBasePage(dashboardCard);
await Navigation.PushModalAsync(page);
}
else
{
await DisplayAlert("iSOTrain", "Yet to be implemented.", "OK");
}
}
public void UpdateCourseCatalagListContent()
{
_expandedGroups = new ObservableCollection<CourseCatalogModel>();
foreach (CourseCatalogModel group in _allGroups)
{
//Create new FoodGroups so we do not alter original list
CourseCatalogModel newGroup = new CourseCatalogModel(group.Title, group.Expanded);
newGroup.DataCount = group.Count;
//Add the count of food items for Lits Header Titles to use
if (group.Expanded)
{
foreach (DashboardCard dataModel in group)
{
newGroup.Add(dataModel);
}
}
_expandedGroups.Add(newGroup);
}
CourseCatalogListView.ItemsSource = _expandedGroups;
}
}
Can anybody tell me how to resetViewModel on every-time page loads??
You can reset the data in OnAppearing every-time page loads, I would recommend two ways to refresh data.
1.reset models in _allGroups
2.reset _allGroups
public partial class MainPage : ContentPage
{
public ObservableCollection<CourseCatalogModel> _allGroups;
public MainPage()
{
InitializeComponent();
_allGroups = new ObservableCollection<CourseCatalogModel>();
}
protected override void OnAppearing()
{
base.OnAppearing();
//1. reset your properties in _allGroups
foreach (var CourseCatalogModel in _allGroups)
{
CourseCatalogModel.Expanded = false;
//...reset if you have other properties
}
//2.create a new _allGroup everytime load page
_allGroups = new ObservableCollection<CourseCatalogModel>();
//.... Add data to _allGroups
_allGroups.Add(new CourseCatalogModel());
...
}
}
Try to initialize your _allGroups like below:
ObservableCollection<CourseCatalogModel>
_allGroups = new ObservableCollection<CourseCatalogModel>();
foreach (var CourseCatalogModel in CourseCatalogModel.CourseCatalogAll)
{
_allGroups.Add(CourseCatalogModel);
}
Finally I nailed it.. The Problem was with static method. My Model class method I created as static and they were getting called only one time and thats why data was not refreshing.
Heres the code of Model Class .
public class CourseCatalogModel : ObservableCollection<DashboardCard>, INotifyPropertyChanged
{
private bool _expanded;
public string Title { get; set; }
private int _dataCount;
public int DataCount
{
get { return _dataCount; }
set
{
if (_dataCount != value)
{
_dataCount = value;
OnPropertyChanged("StateIcon");
OnPropertyChanged("TitleColor");
}
}
}
public string TitleColor
{
get
{
if (DataCount == 0)
{
return "#FFAEB2B5";
}
return "#FF00588A";
}
}
public bool Expanded
{
get { return _expanded; }
set
{
if (_expanded != value)
{
_expanded = value;
OnPropertyChanged("Expanded");
OnPropertyChanged("StateIcon");
}
}
}
public string StateIcon
{
get
{
if (DataCount == 0)
{
return "expand_empty";
}
return Expanded ? "expand_iCon.png" : "collapse_icon.png";
}
}
public CourseCatalogModel(string title, bool expanded = true)
{
Title = title;
Expanded = expanded;
}
public ObservableCollection<CourseCatalogModel> CourseCatalogAll { private set; get; }
public ObservableCollection<CourseCatalogModel> CourseCatalogRequired { private set; get; }
public ObservableCollection<CourseCatalogModel> CourseCatalogNotRequired { private set; get; }
public CourseCatalogModel()
{
// Course Awaiting Approvel...
CourseCatalogModel awaitingApprovel = new CourseCatalogModel("Awaiting Approval", false);
var awaitingCards = CourseCatalogModuleHelper.GetAwaitingApprovels();
foreach (var dashboardCard in awaitingCards)
{
awaitingApprovel.Add(dashboardCard);
}
// Course Pending Courses...
CourseCatalogModel pendingCourses = new CourseCatalogModel("Pending Courses", false);
var pendingCourseCards = CourseCatalogModuleHelper.GetPendingCourses();
foreach (var dashboardCard in pendingCourseCards)
{
pendingCourses.Add(dashboardCard);
}
// Course Completed Courses...
CourseCatalogModel completedCourses = new CourseCatalogModel("Completed Courses", false);
var completedCourseCards = CourseCatalogModuleHelper.GetCompletedCourses();
foreach (var dashboardCard in completedCourseCards)
{
completedCourses.Add(dashboardCard);
}
ObservableCollection<CourseCatalogModel>
CourseCatalogdata = new ObservableCollection<CourseCatalogModel>();
CourseCatalogdata.Add(awaitingApprovel);
CourseCatalogdata.Add(pendingCourses);
CourseCatalogdata.Add(completedCourses);
CourseCatalogAll = new ObservableCollection<CourseCatalogModel>();
CourseCatalogAll = CourseCatalogdata;
GetRequiredCourseCatalogCards();
GetNotRequiredCourseCatalogCards();
}
private void GetRequiredCourseCatalogCards()
{
// Course Awaiting Approvel...
CourseCatalogModel awaitingApprovel = new CourseCatalogModel("Awaiting Approval", false);
var awaitingCards = CourseCatalogModuleHelper.GetAwaitingApprovels(AppConstants.CourseFilterRequired);
foreach (var dashboardCard in awaitingCards)
{
awaitingApprovel.Add(dashboardCard);
}
// Course Pending Courses...
CourseCatalogModel pendingCourses = new CourseCatalogModel("Pending Courses", false);
var pendingCourseCards = CourseCatalogModuleHelper.GetPendingCourses(AppConstants.CourseFilterRequired);
foreach (var dashboardCard in pendingCourseCards)
{
pendingCourses.Add(dashboardCard);
}
// Course Completed Courses...
CourseCatalogModel completedCourses = new CourseCatalogModel("Completed Courses", false);
var completedCourseCards = CourseCatalogModuleHelper.GetCompletedCourses(AppConstants.CourseFilterRequired);
foreach (var dashboardCard in completedCourseCards)
{
completedCourses.Add(dashboardCard);
}
ObservableCollection<CourseCatalogModel>
CourseCatalogdata = new ObservableCollection<CourseCatalogModel>();
CourseCatalogdata.Add(awaitingApprovel);
CourseCatalogdata.Add(pendingCourses);
CourseCatalogdata.Add(completedCourses);
CourseCatalogRequired = CourseCatalogdata;
}
private void GetNotRequiredCourseCatalogCards()
{
// Course Awaiting Approvel...
CourseCatalogModel awaitingApprovel = new CourseCatalogModel("Awaiting Approval", false);
var awaitingCards = CourseCatalogModuleHelper.GetAwaitingApprovels(AppConstants.CourseFilterNotRequired);
foreach (var dashboardCard in awaitingCards)
{
awaitingApprovel.Add(dashboardCard);
}
// Course Pending Courses...
CourseCatalogModel pendingCourses = new CourseCatalogModel("Pending Courses", false);
var pendingCourseCards = CourseCatalogModuleHelper.GetPendingCourses(AppConstants.CourseFilterNotRequired);
foreach (var dashboardCard in pendingCourseCards)
{
pendingCourses.Add(dashboardCard);
}
// Course Completed Courses...
CourseCatalogModel completedCourses = new CourseCatalogModel("Completed Courses", false);
var completedCourseCards = CourseCatalogModuleHelper.GetCompletedCourses(AppConstants.CourseFilterNotRequired);
foreach (var dashboardCard in completedCourseCards)
{
completedCourses.Add(dashboardCard);
}
ObservableCollection<CourseCatalogModel>
CourseCatalogdata = new ObservableCollection<CourseCatalogModel>();
CourseCatalogdata.Add(awaitingApprovel);
CourseCatalogdata.Add(pendingCourses);
CourseCatalogdata.Add(completedCourses);
CourseCatalogNotRequired = CourseCatalogdata;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Here is My class
public partial class CourseCatalogBaseClass : ContentPage
{
public ObservableCollection<CourseCatalogModel> _allGroups = new ObservableCollection<CourseCatalogModel>();
ObservableCollection<CourseCatalogModel> _expandedGroups = new ObservableCollection<CourseCatalogModel>();
List<DashboardCard> allListData = new List<DashboardCard>();
CourseCatalogModel courseCatalogModel = new CourseCatalogModel();
ObservableCollection<DashboardCard> searchListData = new ObservableCollection<DashboardCard>();
private string screenLabelString = string.Empty;
public ObservableCollection<FilterPopupModel> courseFilterPopupModels = new ObservableCollection<FilterPopupModel>();
public CourseCatalogBaseClass(bool isFromQualifications = false)
{
InitializeComponent();
if (isFromQualifications)
{
screenLabel.Text = "My Qualifications";
screenLabelString = screenLabel.Text;
}
allListData = App.DashboardResponse.TrainingContentCards;
CourseCatalogSearchListView.IsVisible = false;
//2.create a new _allGroup everytime load page
_allGroups = new ObservableCollection<CourseCatalogModel>();
//.... Add data to _allGroups
foreach (CourseCatalogModel CourseCatalogModel in courseCatalogModel.CourseCatalogAll)
{
_allGroups.Add(CourseCatalogModel);
}
//1. reset your properties in _allGroups
foreach (var CourseCatalogModel in _allGroups)
{
CourseCatalogModel.Expanded = false;
//...reset if you have other properties
}
CourseCatalogSearchListView.IsVisible = false;
UpdateCourseCatalagListContent();
InitilizeFilters();
}
protected override void OnAppearing()
{
base.OnAppearing();
}
private void InitilizeFilters()
{
courseFilterPopupModels.Add(new FilterPopupModel()
{ Title = "All Classes", TitleColor = Color.FromHex("#00588A") });
courseFilterPopupModels.Add(new FilterPopupModel()
{ Title = "Required", TitleColor = Color.FromHex("#686868") });
courseFilterPopupModels.Add(new FilterPopupModel()
{ Title = "Not Required", TitleColor = Color.FromHex("#686868") });
courseFilterPopupModels.Add(new FilterPopupModel() { Title = "Help", TitleColor = Color.FromHex("#686868") });
}
private void CourseListHeaderTapped(object sender, EventArgs args)
{
int selectedIndex = _expandedGroups.IndexOf(
((CourseCatalogModel)((Button)sender).CommandParameter));
_allGroups[selectedIndex].Expanded = !_allGroups[selectedIndex].Expanded;
UpdateCourseCatalagListContent();
}
void Handle_Search_Bar_TextChanged(object sender, Xamarin.Forms.TextChangedEventArgs e)
{
var entry = (Entry)sender;
searchListData = new ObservableCollection<DashboardCard>();
if (string.IsNullOrWhiteSpace(entry.Text))
{
screenLabel.Text = screenLabelString;
CourseCatalogSearchListView.IsVisible = false;
CourseCatalogListView.IsVisible = true;
}
else
{
screenLabel.Text = "Search Course";
foreach (DashboardCard card in allListData)
{
var courseCode = card.Course;
if (courseCode.ToLower().Contains(entry.Text.ToLower()))
{
searchListData.Add(card);
}
}
searchListData = new ObservableCollection<DashboardCard>(allListData.Where(i =>
(i is DashboardCard && (((DashboardCard)i).Course.ToLower().Contains(entry.Text.ToLower())))));
CourseCatalogSearchListView.ItemsSource = searchListData;
CourseCatalogSearchListView.IsVisible = true;
CourseCatalogListView.IsVisible = false;
}
Console.WriteLine(searchListData.Count);
}
void Menu_Button_Clicked(object sender, System.EventArgs e)
{
Navigation.PushModalAsync(new MenuPage());
//
}
async void Filter_Handle_Clicked(object sender, System.EventArgs e)
{
if (!CourseCatalogSearchListView.IsVisible)
{
var page = new CourseCatalogFilterPopup(this);
await PopupNavigation.Instance.PushAsync(page);
}
else
{
await DisplayAlert(AppConstants.AppName, "Please Close the Search to access Filter",
AppConstants.OK);
}
}
async void Filter_three_dot_Handle_Clicked(object sender, System.EventArgs e)
{
var page = new CourseCatalogMorePopup();
await PopupNavigation.Instance.PushAsync(page);
}
async void Course_List_ItemSelected(object sender, Xamarin.Forms.SelectedItemChangedEventArgs e)
{
DashboardCard dashboardCard = (DashboardCard)e.SelectedItem;
if (!dashboardCard.Status.Equals("TAKEN") &&
!dashboardCard.Status.Equals("EQUIV") &&
!dashboardCard.Status.Equals("SKILL") &&
!dashboardCard.Pending.Equals("WRA") &&
dashboardCard.SelfTrain.Equals("Y"))
{
var page = new SelfTrainBasePage(dashboardCard);
await Navigation.PushModalAsync(page);
}
else
{
await DisplayAlert("iSOTrain", "Yet to be implemented.", "OK");
}
}
async void Course_Search_List_ItemSelected(object sender, Xamarin.Forms.SelectedItemChangedEventArgs e)
{
DashboardCard dashboardCard = (DashboardCard)e.SelectedItem;
if (!dashboardCard.Status.Equals("TAKEN") &&
!dashboardCard.Status.Equals("EQUIV") &&
!dashboardCard.Status.Equals("SKILL") &&
!dashboardCard.Pending.Equals("WRA") &&
dashboardCard.SelfTrain.Equals("Y"))
{
var page = new SelfTrainBasePage(dashboardCard);
await Navigation.PushModalAsync(page);
}
else
{
await DisplayAlert("iSOTrain", "Yet to be implemented.", "OK");
}
}
public void UpdateCourseCatalagListContent()
{
_expandedGroups = new ObservableCollection<CourseCatalogModel>();
foreach (CourseCatalogModel group in _allGroups)
{
//Create new FoodGroups so we do not alter original list
CourseCatalogModel newGroup = new CourseCatalogModel(group.Title, group.Expanded);
newGroup.DataCount = group.Count;
//Add the count of food items for Lits Header Titles to use
if (group.Expanded)
{
foreach (DashboardCard dataModel in group)
{
newGroup.Add(dataModel);
}
}
_expandedGroups.Add(newGroup);
}
CourseCatalogListView.ItemsSource = _expandedGroups;
}
}
Related
i have a checkboxes that i am setting in View Model and i am collecting user decision on a list, however once i filter my items and then go bakc on the page the checkbox is still checked even thought the list is empty so if i press again button to show filtered items i get nothing. I am clearing my list but i am not sure how to get the checkboxes unchecked once i come back. I have Mode = two way
private bool _filterBeginnerItems = false;
private bool _filterIntermediateItems = false;
private bool _filterAdvancedItems = false;
private bool _filterUpperIntermediateItems = false;
public bool FilterBeginnerItems
{
set
{
NotifyPropertyChanged();
_filterBeginnerItems = value;
if (_filterBeginnerItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 1);
}
}
get => _filterBeginnerItems;
}
public bool FilterIntermediateItems
{
set
{
NotifyPropertyChanged();
_filterIntermediateItems = value;
if (_filterIntermediateItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 2);
}
}
get => _filterIntermediateItems;
}
public bool FilterUpperIntermediateItems
{
set
{
NotifyPropertyChanged();
_filterUpperIntermediateItems = value;
if (_filterUpperIntermediateItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 3);
}
}
get => _filterUpperIntermediateItems;
}
public FilterArticlesForPurchaseViewModel(INavigation navigation)
: base()
{
Task.Run(async () => await LoadAllDataForArticlesAndCategories()).Wait();
FilterItemsCommand = new Command(async () => navigation.PushAsync(new ArticlesForPurchaseFiltered()));
UserDecision.Clear();
//FilterAdvancedItems = false;
// FilterBeginnerItems = false;
}
Have tried to set their value to false but it doesnt help.
I write a demo about clear the CheckBox
Here is running gif.
Here is FilterArticlesForPurchaseViewModel.cs to achieve the INotifyPropertyChanged interface. I used a Command to clear these checkbox.
public class FilterArticlesForPurchaseViewModel: INotifyPropertyChanged
{
private bool _filterBeginnerItems = true;
private bool _filterIntermediateItems = false;
private bool _filterAdvancedItems = false;
private bool _filterUpperIntermediateItems = false;
public bool FilterBeginnerItems
{
set
{
// NotifyPropertyChanged();
_filterBeginnerItems = value;
OnPropertyChanged("FilterBeginnerItems");
//if (_filterBeginnerItems)
//{
// FilterAllItems = false;
// UserDecision.Add(_parentCategoryId = 1);
//}
}
get => _filterBeginnerItems;
}
public bool FilterIntermediateItems
{
set
{
// NotifyPropertyChanged();
_filterIntermediateItems = value;
OnPropertyChanged("FilterIntermediateItems");
//if (_filterIntermediateItems)
//{
// FilterAllItems = false;
// UserDecision.Add(_parentCategoryId = 2);
//}
}
get => _filterIntermediateItems;
}
public bool FilterUpperIntermediateItems
{
set
{
// NotifyPropertyChanged();
_filterUpperIntermediateItems = value;
OnPropertyChanged("FilterUpperIntermediateItems");
//if (_filterUpperIntermediateItems)
//{
// FilterAllItems = false;
// UserDecision.Add(_parentCategoryId = 3);
//}
}
get => _filterUpperIntermediateItems;
}
public ICommand ClearCommand { protected set; get; }
public FilterArticlesForPurchaseViewModel(INavigation navigation)
{
ClearCommand = new Command(async () =>
{
FilterBeginnerItems = false;
FilterIntermediateItems = false;
FilterUpperIntermediateItems = false;
});
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Here is layout.xaml
<StackLayout>
<!-- Place new controls here -->
<CheckBox IsChecked="{Binding FilterBeginnerItems,Mode=TwoWay}"></CheckBox>
<CheckBox IsChecked="{Binding FilterIntermediateItems,Mode=TwoWay}"></CheckBox>
<CheckBox IsChecked="{Binding FilterUpperIntermediateItems,Mode=TwoWay}"></CheckBox>
<Button Text="clear" Command="{Binding ClearCommand}"></Button>
</StackLayout>
Here is background code.
public MainPage()
{
InitializeComponent();
this.BindingContext = new FilterArticlesForPurchaseViewModel(Navigation);
}
=================update===================
I make edit your viewmodel. Here is code, I achieve the remove data from the List<int> UserDecision
public class FilterViewModel : BaseViewModel
{
private bool _filterAllItems = true;
private bool _filterBeginnerItems = false;
private bool _filterIntermediateItems = false;
private bool _filterAdvancedItems = false;
private bool _filterUpperIntermediateItems = false;
private static List<Article> _allArticlesForPurchase;
private static List<Category> _allCategories;
private static List<CategoryGroup> _allUserCategoryGroups;
public static List<int> UserDecisionResult { get; set; }
private static int _parentCategoryId;
public ICommand FilterItemsCommand { get; private set; }
public static List<int> UserDecision { get; set; } = new List<int>();
public bool FilterAllItems
{
set
{
_filterAllItems = value;
OnPropertyChanged();
if (FilterAllItems == false)
{
if (UserDecision.Contains(_parentCategoryId = -1))
{
UserDecision.Remove(_parentCategoryId = -1);
}
}
if (FilterAllItems == true)
{
FilterBeginnerItems = false;
FilterIntermediateItems = false;
FilterUpperIntermediateItems = false;
FilterAdvancedItems = false;
if (!UserDecision.Contains(_parentCategoryId = -1))
{
UserDecision.Add(_parentCategoryId = -1);
}
if (UserDecision.Contains(_parentCategoryId=1))
{
UserDecision.Remove(_parentCategoryId = 1);
}
if (UserDecision.Contains(_parentCategoryId = 2))
{
UserDecision.Remove(_parentCategoryId = 2);
}
if (UserDecision.Contains(_parentCategoryId = 3))
{
UserDecision.Remove(_parentCategoryId = 3);
}
if (UserDecision.Contains(_parentCategoryId = 4))
{
UserDecision.Remove(_parentCategoryId = 4);
}
}
}
get => _filterAllItems;
}
public bool FilterBeginnerItems
{
set
{
_filterBeginnerItems = value;
OnPropertyChanged();
if (_filterBeginnerItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 1);
if (UserDecision.Contains(_parentCategoryId = -1))
{
UserDecision.Remove(_parentCategoryId = -1);
}
}
}
get => _filterBeginnerItems;
}
public bool FilterIntermediateItems
{
set
{
_filterIntermediateItems = value;
OnPropertyChanged();
if (_filterIntermediateItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 2);
if (UserDecision.Contains(_parentCategoryId = -1))
{
UserDecision.Remove(_parentCategoryId = -1);
}
}
}
get => _filterIntermediateItems;
}
public bool FilterUpperIntermediateItems
{
set
{
_filterUpperIntermediateItems = value;
OnPropertyChanged();
if (_filterUpperIntermediateItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 3);
if (UserDecision.Contains(_parentCategoryId = -1))
{
UserDecision.Remove(_parentCategoryId = -1);
}
}
}
get => _filterUpperIntermediateItems;
}
public bool FilterAdvancedItems
{
set
{
_filterAdvancedItems = value;
OnPropertyChanged();
if (_filterAdvancedItems)
{
FilterAllItems = false;
UserDecision.Add(_parentCategoryId = 4);
if (UserDecision.Contains(_parentCategoryId = -1))
{
UserDecision.Remove(_parentCategoryId = -1);
}
}
}
get => _filterAdvancedItems;
}
public FilterViewModel()
{
FilterItemsCommand = new Command(async () => await FilterItems());
FindAllArticlesForPurchase();
}
public ObservableCollection<Article> FilterArticlesForPurchase { get; } = new ObservableCollection<Article>();
private static void FindAllArticlesForPurchase()
{
foreach (var userDecision in UserDecision)
{
if (userDecision != -1)
{
if (UserDecision.Count > 1)
{
Console.WriteLine("more than one item");
}
else
{
Console.WriteLine("one item");
}
}
else
{
Console.WriteLine("not minus one");
}
}
}
private async Task FilterItems()
{
await Application.Current.MainPage.Navigation.PushAsync(new Filter());
}
}
If you want to binding same FilterViewModel in MainPage and Filter page.
You should use static FilterViewModel in the MainPage.xaml.cs
public partial class MainPage : ContentPage
{
public static FilterViewModel filterViewModel ;
public MainPage()
{
InitializeComponent();
filterViewModel= new FilterViewModel();
BindingContext = filterViewModel;
}
}
In Filter page.You can binding same FilterViewModel in MainPage.xaml.cs
public partial class Filter: ContentPage
{
public Filter()
{
InitializeComponent();
BindingContext = MainPage.filterViewModel;
//If this FilterAllItems is empty, you want AllItems the checkbox to unselect, just set the value to false, the checkbox will update in the MainPage
MainPage.filterViewModel.FilterAllItems = false;
}
}
i need some help with my check Boxes and filtering items.
I have 5 checkboxes, that each filters different values. 1 will give me back everything and the rest based on category. Now i need the user to be able to select multiple categories. I am able to get the data for each but i dont know how the get data for multiple categories. Once the user is finished with his selection he then presses a button that should filter the items and redirect to a page.
private static int? _userDiscount;
private static int _parentCategoryId;
private static List<Article> _allArticlesForPurchase;
private static List<Category> _allCategories;
private static List<CategoryGroup> _allUserCategoryGroups;
private static List<Article> _allUserArticles;
private static UserOrganization _userOrganization;
private bool _filterAllItems;
private bool _filterBeginnerItems;
private bool _filterIntermediateItems;
private bool _filterAdvancedItems;
private bool _filterUpperIntermediateItems;
public ICommand FilterItemsCommand { get; private set; }
public bool IsBusy { get; set; }
public bool FilterAllItems
{
set
{
_filterAllItems = value;
NotifyPropertyChanged();
if (_filterAllItems)
_parentCategoryId = -1;
FillArticles();
if (FilterAllItems == true)
{
FilterBeginnerItems = false;
FilterIntermediateItems = false;
FilterUpperIntermediateItems = false;
FilterAdvancedItems = false;
}
//var result = FilterArticlesForPurchase.Where(x => x.ArticleCategoryId == _parentCategoryId).ToList();
}
get => _filterAllItems;
}
public bool FilterBeginnerItems
{
set
{
_filterBeginnerItems = value;
NotifyPropertyChanged();
if (_filterBeginnerItems)
{
_parentCategoryId = 1;
FilterAllItems = false;
FillArticles();
}
}
get => _filterBeginnerItems;
}
public bool FilterIntermediateItems
{
set
{
_filterIntermediateItems = value;
NotifyPropertyChanged();
if (_filterIntermediateItems)
{
_parentCategoryId = 2;
FilterAllItems = false;
FillArticles();
}
}
get => _filterIntermediateItems;
}
public bool FilterUpperIntermediateItems
{
set
{
_filterUpperIntermediateItems = value;
NotifyPropertyChanged();
if (_filterUpperIntermediateItems)
{
_parentCategoryId = 3;
FilterAllItems = false;
FillArticles();
}
}
get => _filterUpperIntermediateItems;
}
public bool FilterAdvancedItems
{
set
{
_filterAdvancedItems = value;
NotifyPropertyChanged();
if (_filterAdvancedItems)
{
_parentCategoryId = 4;
FilterAllItems = false;
FillArticles();
}
}
get => _filterAdvancedItems;
}
public ObservableCollection<ArticleDetailData> FilterArticlesForPurchase { get; } = new ObservableCollection<ArticleDetailData>();
public FilterArticlesForPurchaseViewModel()
: base()
{
;
Task.Run(async () => await LoadAllDataForArticlesAndCategories()).Wait();
FilterItemsCommand = new Command(async () => await FilterItems());
}
private async Task LoadAllDataForArticlesAndCategories()
{
if (LangUpNetworkDelegate.IsOnline)
{
await FillCategories();
if (LangUpLoggedUser.LoggedIn)
{
await FillUsersArticles();
var userOrganizationApiResponse = await AVAT.App.ApiFactory.TryGetMainUserOrganization();
_userOrganization = userOrganizationApiResponse.MatchResult<UserOrganization>(default(UserOrganization), org => org);
if (_userOrganization != null &&
DateTime.ParseExact(_userOrganization.OrganizationPromocode.DateOfExpiration, "dd/MM/yyyy",
null) >= DateTime.Now)
{
_userDiscount = _userOrganization.OrganizationPromocode.DiscountPercentage;
}
}
else
{
await FillAnonymousArticles();
}
foreach (var group in _allUserCategoryGroups)
{
var listOfArticles = new List<Article>();
var allGroupCategories = _allCategories.Where(m => m.CategoryGroupId == group.Id).ToList();
foreach (var category in allGroupCategories)
{
var categoryArticles = _allUserArticles.Where(m => m.CategoryId == category.Id).ToList();
listOfArticles.AddRange(categoryArticles);
}
group.GroupArticles = listOfArticles;
}
FillArticles();
}
else
{
NotificationService.ShowToast("");
}
}
private async void FillArticles()
{
var allArticles = new List<Article>();
allArticles = FindAllArticlesForPurchase(allArticles);
var downloadedArticles = LangUpDataSaverLoader.DeserializeAllOptimizationData();
foreach (var article in allArticles)
{
var filename = string.Format(SharedConstants.ArticleImageUrl, SharedConstants.ApiBaseUri, article.Id);
var rating = article.FinalRate == -1 ? "-.-" : ((float)article.FinalRate).ToString("0.0");
if (downloadedArticles.DownloadedArticles.Any(m => m.Id == article.Id))
{
filename = article.Id.ArticleImageFile();
}
var detail = new ArticleDetailData()
{
Author = article.Author,
Avatar = filename,
BackgroundImage = filename,
Description = article.Description,
Body = article.Description,
Section = article.Category,
Id = article.Id,
Subtitle = article.Description,
Title = article.NameCz,
}
FilterArticlesForPurchase.Add(detail);
}
}
private static List<Article> FindAllArticlesForPurchase(List<Article> allArticles)
{
if (_parentCategoryId != -1)
{
foreach (var categoryGroup in _allUserCategoryGroups)
{
var allGroupCategories = _allCategories.Where(m => m.CategoryGroupId == categoryGroup.Id).ToList();
if (_parentCategoryId != -1)
{
foreach (var category in allGroupCategories)
{
if (category.ParentId == _parentCategoryId && _parentCategoryId != -1)
{
var categoryArticles = _allArticlesForPurchase.Where(m => m.CategoryId == category.Id).ToList();
allArticles.AddRange(categoryArticles);
}
}
}
}
}
else
{
allArticles = _allArticlesForPurchase;
}
return allArticles;
}
private async Task FilterItems()
{
await Application.Current.MainPage.Navigation.PushAsync(new ArticlesForPurchaseFiltered());
}
Update
public void GetUserDecision()
{
List<int> userDecision = new List<int>();
if (FilterAllItems) userDecision.Add(_parentCategoryId = -1);
if (FilterBeginnerItems) userDecision.Add(_parentCategoryId = 1);
if (FilterIntermediateItems) userDecision.Add(_parentCategoryId = 2);
if (FilterUpperIntermediateItems) userDecision.Add(_parentCategoryId = 3);
if (FilterAdvancedItems) userDecision.Add(_parentCategoryId = 4);
UserDecisionResult = userDecision;
}
private static List<Article> FindAllArticlesForPurchase(List<Article> allArticles)
{
var result = UserDecisionResult;
if (_parentCategoryId != -1)
{
foreach (var categoryGroup in _allUserCategoryGroups)
{
var allGroupCategories = _allCategories.Where(m => m.CategoryGroupId == categoryGroup.Id).ToList();
if (_parentCategoryId != -1)
{
foreach (var category in allGroupCategories)
{
if (category.ParentId == _parentCategoryId && _parentCategoryId != -1)
{
//var categoryArticles = _allArticlesForPurchase.Where(m => m.CategoryId == category.Id).ToList();
var categoryArticles = _allArticlesForPurchase.Where(m => m.CategoryId == category.Id && result.Contains(m.CategoryId)).ToList();
allArticles.AddRange(categoryArticles);
}
}
}
}
}
else
{
allArticles = _allArticlesForPurchase;
}
return allArticles;
}
you can filter by multiple selections using LINQ
// these are the ids selected by the user
var list = new List<int>() { 1, 2, 3 };
// this will return all articles whose CategoryID is in list
var result = FilterArticlesForPurchase.Where(list.Contains(x.ArticleCategoryId).ToList();
I get "unfortunately app has stopped" error after phone restart. My Phone is Oreo 8 but another phone with Nougat 7.1.1 also having the same error after phone restart. I use James Montemagnos' MyStepCounter bound services codes from GitHub with some changes in VS 2017 (Xamarin Cross-Platform App). The app is working fine if once started after phone restart with this error, else it is not counting steps and not working on the background. If I check the app in Phone Settings-General-Battery-Power saving exclusions then it works with no problems after phone restart and it is counting steps on the background without starting the app on Oreo phone. But there are no settings for battery power saving exclusions on the other phone
BootReceiver.cs
[BroadcastReceiver(Enabled = true, Exported = true, DirectBootAware = true)]
[IntentFilter(new string[] { Intent.ActionBootCompleted, Intent.ActionLockedBootCompleted, "android.intent.action.QUICKBOOT_POWERON", "com.htc.intent.action.QUICKBOOT_POWERON" })]
public class BootReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
var stepServiceIntent = new Intent(context, typeof(StepService));
context.StartService(stepServiceIntent);
}
}
StepServiceBinder.cs
public class StepServiceBinder : Binder
{
StepService stepService;
public StepServiceBinder(StepService service)
{
this.stepService = service;
}
public StepService StepService
{
get { return stepService; }
}
}
StepServiceConnection.cs
public class StepServiceConnection : Java.Lang.Object, IServiceConnection
{
MainActivity activity;
public StepServiceConnection(MainActivity activity)
{
this.activity = activity;
}
public void OnServiceConnected(ComponentName name, IBinder service)
{
var serviceBinder = service as StepServiceBinder;
if (serviceBinder != null)
{
activity.Binder = serviceBinder;
activity.IsBound = true;
}
}
public void OnServiceDisconnected(ComponentName name)
{
activity.IsBound = false;
}
}
StepService.cs
public class StepServiceConnection : Java.Lang.Object, IServiceConnection
{
MainActivity activity;
public StepServiceConnection(MainActivity activity)
{
this.activity = activity;
}
public void OnServiceConnected(ComponentName name, IBinder service)
{
var serviceBinder = service as StepServiceBinder;
if (serviceBinder != null)
{
activity.Binder = serviceBinder;
activity.IsBound = true;
}
}
public void OnServiceDisconnected(ComponentName name)
{
activity.IsBound = false;
}
}
StepService.cs
[Service(Enabled = true)]
[IntentFilter(new String[] { "com.PedometerApp.StepService" })]
public class StepService : Service, ISensorEventListener, INotifyPropertyChanged
{
private SensorManager sManager;
private bool isRunning;
private long stepsToday = 0;
public bool WarningState
{
get;
set;
}
public long StepsToday
{
get { return stepsToday; }
set
{
if (stepsToday == value)
return;
stepsToday = value;
OnPropertyChanged("StepsToday");
Settings.CurrentDaySteps = value;
MessagingCenter.Send<object, long>(this, "Steps", Settings.CurrentDaySteps);
}
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
var alarmManager = ((AlarmManager)ApplicationContext.GetSystemService(AlarmService));
var intent2 = new Intent(this, typeof(StepService));
intent2.PutExtra("warning", WarningState);
var stepIntent = PendingIntent.GetService(ApplicationContext, 200, intent2, PendingIntentFlags.UpdateCurrent);
alarmManager.Set(AlarmType.Rtc, Java.Lang.JavaSystem
.CurrentTimeMillis() + 1000 * 60 * 60, stepIntent);
var warning = false;
if (intent != null)
warning = intent.GetBooleanExtra("warning", false);
Startup();
return StartCommandResult.Sticky;
}
public override void OnTaskRemoved(Intent rootIntent)
{
base.OnTaskRemoved(rootIntent);
UnregisterListeners();
var intent = new Intent(this, typeof(StepService));
intent.PutExtra("warning", WarningState);
((AlarmManager)GetSystemService(AlarmService)).Set(AlarmType.Rtc, Java.Lang.JavaSystem
.CurrentTimeMillis() + 500,
PendingIntent.GetService(this, 201, intent, 0));
}
private void Startup(bool warning = false)
{
CrunchDates(true);
if (!isRunning)
{
RegisterListeners();
WarningState = warning;
}
isRunning = true;
}
public override void OnDestroy()
{
base.OnDestroy();
UnregisterListeners();
isRunning = false;
CrunchDates();
}
void RegisterListeners()
{
sManager = GetSystemService(SensorService) as SensorManager;
sManager.RegisterListener(this, sManager.GetDefaultSensor(SensorType.StepCounter), SensorDelay.Ui);
}
void UnregisterListeners()
{
if (!isRunning)
return;
try
{
var sensorManager = (SensorManager)GetSystemService(Context.SensorService);
sensorManager.UnregisterListener(this);
isRunning = false;
}
catch (Exception ex)
{
}
}
StepServiceBinder binder;
public override Android.OS.IBinder OnBind(Android.Content.Intent intent)
{
binder = new StepServiceBinder(this);
return binder;
}
public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy)
{
//do nothing here
}
public void AddSteps(long count)
{
if (lastSteps == 0)
{
lastSteps = count;
}
newSteps = count - lastSteps;
if (newSteps < 0)
newSteps = 1;
else if (newSteps > 100)
newSteps = 1;
lastSteps = count;
CrunchDates();
Settings.TotalSteps += newSteps;
StepsToday = Settings.TotalSteps - Settings.StepsBeforeToday;
}
long newSteps = 0;
long lastSteps = 0;
public void OnSensorChanged(SensorEvent e)
{
if (lastSteps < 0)
lastSteps = 0;
var count = (long)e.Values[0];
WarningState = false;
AddSteps(count);
}
private void CrunchDates(bool startup = false)
{
if (!Utils.IsSameDay)
{
var yesterday = Settings.CurrentDay;
var dayEntry = StepEntryManager.GetStepEntry(yesterday);
if (dayEntry == null || dayEntry.Date.DayOfYear != yesterday.DayOfYear)
{
dayEntry = new StepEntry();
}
dayEntry.Date = yesterday;
dayEntry.Steps = Settings.CurrentDaySteps;
Settings.CurrentDay = DateTime.Today;
Settings.CurrentDaySteps = 0;
Settings.StepsBeforeToday = Settings.TotalSteps;
StepsToday = 0;
try
{
StepEntryManager.SaveStepEntry(dayEntry);
}
catch (Exception ex)
{
Console.WriteLine("Error {0}", ex.Message);
}
}
else if (startup)
{
StepsToday = Settings.TotalSteps - Settings.StepsBeforeToday;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
if (PropertyChanged == null)
return;
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
I am using foreground service if OS version >= 8.0. On android 8.1 and 9.0 when my pedometer app is open or on the background it is counting steps, but not when the app is closed. Also after closing the app notification icon disappearing from the phone screen. Tested on Oreo 8.0 using foreground service, it is working fine and counting steps when the app is closed. Tested also on android Nougat 7.0 with background service and working with no problems.
BootReceiver.cs
[BroadcastReceiver(Enabled = true, Exported = true, DirectBootAware = true)]
[IntentFilter(new string[] { Intent.ActionBootCompleted, Intent.ActionLockedBootCompleted, "android.intent.action.QUICKBOOT_POWERON", "com.htc.intent.action.QUICKBOOT_POWERON" })]
public class BootReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
var stepServiceIntent = new Intent(context, typeof(StepService));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
context.StartForegroundService(stepServiceIntent);
}
else
{
context.StartService(stepServiceIntent);
}
}
}
StepServiceBinder.cs
public class StepServiceBinder : Binder
{
StepService stepService;
public StepServiceBinder(StepService service)
{
this.stepService = service;
}
public StepService StepService
{
get { return stepService; }
}
}
StepServiceConnection.cs
public class StepServiceConnection : Java.Lang.Object, IServiceConnection
{
MainActivity activity;
public StepServiceConnection(MainActivity activity)
{
this.activity = activity;
}
public void OnServiceConnected(ComponentName name, IBinder service)
{
var serviceBinder = service as StepServiceBinder;
if (serviceBinder != null)
{
activity.Binder = serviceBinder;
activity.IsBound = true;
}
}
public void OnServiceDisconnected(ComponentName name)
{
activity.IsBound = false;
}
}
*Manifest.xml *
<manifest android:versionName="1.1" package="com.PedometerApp" android:installLocation="internalOnly" android:versionCode="11">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="27" />
<application android:label="My Pedometer" android:icon="#drawable/logo"> </application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
</manifest>
StepService.cs
[Service(Enabled = true)]
[IntentFilter(new String[] { "com.PedometerApp.StepService" })]
public class StepService : Service, ISensorEventListener, INotifyPropertyChanged
{
private SensorManager sManager;
private bool isRunning;
private long stepsToday = 0;
public bool WarningState
{
get;
set;
}
public long StepsToday
{
get { return stepsToday; }
set
{
if (stepsToday == value)
return;
stepsToday = value;
OnPropertyChanged("StepsToday");
Settings.CurrentDaySteps = value;
MessagingCenter.Send<object, long>(this, "Steps", Settings.CurrentDaySteps);
}
}
public const string PRIMARY_NOTIF_CHANNEL = "exampleChannel";
public const int SERVICE_RUNNING_NOTIFICATION_ID = 10000;
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
RegisterForService();
var warning = false;
if (intent != null)
warning = intent.GetBooleanExtra("warning", false);
Startup();
return StartCommandResult.Sticky;
}
private void RegisterForService()
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
var channel = new NotificationChannel(PRIMARY_NOTIF_CHANNEL, "Pedometer Service Channel", NotificationImportance.Low)
{
Description = "Foreground Service Channel"
};
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.CreateNotificationChannel(channel);
var notification = new Notification.Builder(this, PRIMARY_NOTIF_CHANNEL)
.SetContentTitle("Service")
.SetContentText("Running")
.SetSmallIcon(Resource.Drawable.ic_stat_name)
.SetContentIntent(BuildIntentToShowMainActivity())
.SetOngoing(true)
.Build();
StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notification);
}
else
{
BuildIntentToShowMainActivity();
}
}
PendingIntent BuildIntentToShowMainActivity()
{
var alarmManager = ((AlarmManager)ApplicationContext.GetSystemService(AlarmService));
var intent2 = new Intent(this, typeof(StepService));
intent2.PutExtra("warning", WarningState);
var stepIntent = PendingIntent.GetService(ApplicationContext, 200, intent2, PendingIntentFlags.UpdateCurrent);
alarmManager.Set(AlarmType.Rtc, Java.Lang.JavaSystem
.CurrentTimeMillis() + 1000 * 60 * 60, stepIntent);
return stepIntent;
}
public override void OnTaskRemoved(Intent rootIntent)
{
base.OnTaskRemoved(rootIntent);
UnregisterListeners();
var intent = new Intent(this, typeof(StepService));
intent.PutExtra("warning", WarningState);
((AlarmManager)GetSystemService(AlarmService)).Set(AlarmType.Rtc, Java.Lang.JavaSystem
.CurrentTimeMillis() + 500,
PendingIntent.GetService(this, 201, intent, 0));
}
private void Startup(bool warning = false)
{
CrunchDates(true);
if (!isRunning)
{
RegisterListeners();
WarningState = warning;
}
isRunning = true;
}
public override void OnDestroy()
{
base.OnDestroy();
UnregisterListeners();
isRunning = false;
CrunchDates();
}
void RegisterListeners()
{
sManager = GetSystemService(SensorService) as SensorManager;
sManager.RegisterListener(this, sManager.GetDefaultSensor(SensorType.StepCounter), SensorDelay.Ui);
}
void UnregisterListeners()
{
if (!isRunning)
return;
try
{
var sensorManager = (SensorManager)GetSystemService(Context.SensorService);
sensorManager.UnregisterListener(this);
isRunning = false;
}
catch (Exception ex)
{
}
}
StepServiceBinder binder;
public override Android.OS.IBinder OnBind(Android.Content.Intent intent)
{
binder = new StepServiceBinder(this);
return binder;
}
public void OnAccuracyChanged(Sensor sensor, SensorStatus accuracy)
{
//do nothing here
}
public void AddSteps(long count)
{
if (lastSteps == 0)
{
lastSteps = count;
}
newSteps = count - lastSteps;
if (newSteps < 0)
newSteps = 1;
else if (newSteps > 100)
newSteps = 1;
lastSteps = count;
CrunchDates();
Settings.TotalSteps += newSteps;
StepsToday = Settings.TotalSteps - Settings.StepsBeforeToday;
}
long newSteps = 0;
long lastSteps = 0;
public void OnSensorChanged(SensorEvent e)
{
if (lastSteps < 0)
lastSteps = 0;
var count = (long)e.Values[0];
WarningState = false;
AddSteps(count);
}
private void CrunchDates(bool startup = false)
{
if (!Utils.IsSameDay)
{
var yesterday = Settings.CurrentDay;
var dayEntry = StepEntryManager.GetStepEntry(yesterday);
if (dayEntry == null || dayEntry.Date.DayOfYear != yesterday.DayOfYear)
{
dayEntry = new StepEntry();
}
dayEntry.Date = yesterday;
dayEntry.Steps = Settings.CurrentDaySteps;
Settings.CurrentDay = DateTime.Today;
Settings.CurrentDaySteps = 0;
Settings.StepsBeforeToday = Settings.TotalSteps;
StepsToday = 0;
try
{
StepEntryManager.SaveStepEntry(dayEntry);
}
catch (Exception ex)
{
Console.WriteLine("Error {0}", ex.Message);
}
}
else if (startup)
{
StepsToday = Settings.TotalSteps - Settings.StepsBeforeToday;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
if (PropertyChanged == null)
return;
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
MainActivity.cs
[Activity(Label = "My Pedometer", Icon = "#mipmap/icon", Theme = "#style/MainTheme", LaunchMode = LaunchMode.SingleTask, MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
public bool IsBound { get; set; }
private StepServiceBinder binder;
private bool registered;
private Handler handler;
private bool firstRun = true;
private StepServiceConnection serviceConnection;
public StepServiceBinder Binder
{
get { return binder; }
set
{
binder = value;
if (binder == null)
return;
HandlePropertyChanged(null, new System.ComponentModel.PropertyChangedEventArgs("StepsToday"));
if (registered)
binder.StepService.PropertyChanged -= HandlePropertyChanged;
binder.StepService.PropertyChanged += HandlePropertyChanged;
registered = true;
}
}
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
Xamarin.Forms.Forms.Init(this, savedInstanceState);
StartStepService();
handler = new Handler();
handler.PostDelayed(() => UpdateUI(), 500);
LoadApplication(new App());
}
private void StartStepService()
{
try
{
var service = new Intent(this, typeof(StepService));
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
StartForegroundService(service);
}
else
{
StartService(service);
}
}
catch (Exception ex)
{
Console.WriteLine("Exception {0}.", ex.Message);
}
}
protected override void OnStop()
{
base.OnStop();
if (IsBound)
{
UnbindService(serviceConnection);
IsBound = false;
}
}
protected override void OnDestroy()
{
base.OnDestroy();
if (IsBound)
{
UnbindService(serviceConnection);
IsBound = false;
}
}
protected override void OnStart()
{
base.OnStart();
if (!firstRun)
StartStepService();
if (IsBound)
return;
var serviceIntent = new Intent(this, typeof(StepService));
serviceConnection = new StepServiceConnection(this);
BindService(serviceIntent, serviceConnection, Bind.AutoCreate);
}
protected override void OnPause()
{
base.OnPause();
if (registered && binder != null)
{
binder.StepService.PropertyChanged -= HandlePropertyChanged;
registered = false;
}
}
protected override void OnResume()
{
base.OnResume();
if (!firstRun)
{
if (handler == null)
handler = new Handler();
handler.PostDelayed(() => UpdateUI(), 500);
}
firstRun = false;
if (!registered && binder != null)
{
binder.StepService.PropertyChanged += HandlePropertyChanged;
registered = true;
}
}
void HandlePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName != "StepsToday")
return;
UpdateUI();
}
private void UpdateUI()
{
RunOnUiThread(() =>
{
long steps = 0;
var showWaring = false;
if (Binder == null)
{
if (Utils.IsSameDay)
steps = Settings.CurrentDaySteps;
}
else
{
steps = Binder.StepService.StepsToday;
showWaring = binder.StepService.WarningState;
}
Settings.CurrentDaySteps = steps;
});
}
}
I took from a GitHub TkCustomMap project TK.CustomMap, and I want to call my custom service, to fill my custom list, and on ItemSelected event, from autocomplete searchBar to MapCenter it with Coordinates from my list model.
I've tried and I stopped at binding and on ItemSelect event.
Here is my MapPage:
using Xamarin.Forms;
using Xamarin.Forms.Maps;
namespace TK.CustomMap.Sample
{
public partial class SamplePage : ContentPage
{
public SamplePage()
{
//InitializeComponent();
this.CreateView();
this.BindingContext = new SampleViewModel();
}
private async void CreateView()
{
var autoComplete = new PlacesAutoComplete { ApiToUse = PlacesAutoComplete.PlacesApi.CustomList };
autoComplete.SetBinding(PlacesAutoComplete.MapSelectedCommandProperty, "MapCenter");
var newYork = new Position(40.7142700, -74.0059700);
var mapView = new TKCustomMap(MapSpan.FromCenterAndRadius(newYork, Distance.FromKilometers(2)));
mapView.IsShowingUser = true;
mapView.SetBinding(TKCustomMap.CustomPinsProperty, "Pins");
mapView.SetBinding(TKCustomMap.MapClickedCommandProperty, "MapClickedCommand");
mapView.SetBinding(TKCustomMap.MapLongPressCommandProperty, "MapLongPressCommand");
mapView.SetBinding(TKCustomMap.MapCenterProperty, "MapCenter");
mapView.SetBinding(TKCustomMap.PinSelectedCommandProperty, "PinSelectedCommand");
mapView.SetBinding(TKCustomMap.SelectedPinProperty, "SelectedPin");
mapView.SetBinding(TKCustomMap.RoutesProperty, "Routes");
mapView.SetBinding(TKCustomMap.PinDragEndCommandProperty, "DragEndCommand");
mapView.SetBinding(TKCustomMap.CirclesProperty, "Circles");
mapView.SetBinding(TKCustomMap.CalloutClickedCommandProperty, "CalloutClickedCommand");
mapView.SetBinding(TKCustomMap.PolylinesProperty, "Lines");
mapView.SetBinding(TKCustomMap.PolygonsProperty, "Polygons");
mapView.SetBinding(TKCustomMap.MapRegionProperty, "MapRegion");
mapView.SetBinding(TKCustomMap.RouteClickedCommandProperty, "RouteClickedCommand");
mapView.SetBinding(TKCustomMap.RouteCalculationFinishedCommandProperty, "RouteCalculationFinishedCommand");
mapView.SetBinding(TKCustomMap.TilesUrlOptionsProperty, "TilesUrlOptions");
mapView.SetBinding(TKCustomMap.MapFunctionsProperty, "MapFunctions");
mapView.IsRegionChangeAnimated = true;
autoComplete.SetBinding(PlacesAutoComplete.BoundsProperty, "MapRegion");
RelativeLayout _baseLayout = new RelativeLayout();
_baseLayout.Children.Add(
mapView,
Constraint.RelativeToView(autoComplete, (r, v) => v.X),
Constraint.RelativeToView(autoComplete, (r, v) => autoComplete.HeightOfSearchBar),
heightConstraint: Constraint.RelativeToParent((r) => r.Height - autoComplete.HeightOfSearchBar),
widthConstraint: Constraint.RelativeToView(autoComplete, (r, v) => v.Width));
_baseLayout.Children.Add(
autoComplete,
Constraint.Constant(0),
Constraint.Constant(0));
Content = _baseLayout;
}
}
}
Here is my PlacesAutoComplete class:
using System;
using System.Collections.Generic;
using System.Linq;
using TK.CustomMap.Api;
using TK.CustomMap.Api.Google;
using TK.CustomMap.Api.OSM;
using Xamarin.Forms;
using Xamarin.Forms.Maps;
using static TK.CustomMap.Sample.SearchBarModel;
namespace TK.CustomMap.Sample
{
public class SearchBarModel : IPlaceResult
{
public string Subtitle { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
}
public class PlacesAutoComplete : RelativeLayout
{
public static BindableProperty BoundsProperty = BindableProperty.Create<PlacesAutoComplete, MapSpan>(
p => p.Bounds,
default(MapSpan));
// TODO: SUMMARIES
public enum PlacesApi
{
//Google,
//Osm,
//Native,
//THIS IS MY LIST!
CustomList
}
private readonly bool _useSearchBar;
private bool _textChangeItemSelected;
private SearchBar _searchBar;
private Entry _entry;
private ListView _autoCompleteListView;
private IEnumerable<IPlaceResult> _predictions;
public PlacesApi ApiToUse { get; set; }
public static readonly BindableProperty MapSelectedCommandProperty =
BindableProperty.Create<PlacesAutoComplete, Command<Position>>(
p => p.SetMap, null);
public List<SearchBarModel> myList = new List<SearchBarModel>();
public Command<Position> SetMap
{
get { return (Command<Position>)this.GetValue(MapSelectedCommandProperty); }
set { this.SetValue(MapSelectedCommandProperty, value); }
}
public double HeightOfSearchBar
{
get
{
return this._useSearchBar ? this._searchBar.Height : this._entry.Height;
}
}
private string SearchText
{
get
{
return this._useSearchBar ? this._searchBar.Text : this._entry.Text;
}
set
{
if (this._useSearchBar)
this._searchBar.Text = value;
else
this._entry.Text = value;
}
}
public new MapSpan Bounds
{
get { return (MapSpan)this.GetValue(BoundsProperty); }
set { this.SetValue(BoundsProperty, value); }
}
public PlacesAutoComplete(bool useSearchBar)
{
this._useSearchBar = useSearchBar;
this.Init();
}
public string Placeholder
{
get { return this._useSearchBar ? this._searchBar.Placeholder : this._entry.Placeholder; }
set
{
if (this._useSearchBar)
this._searchBar.Placeholder = value;
else
this._entry.Placeholder = value;
}
}
public PlacesAutoComplete()
{
this._useSearchBar = true;
this.Init();
}
private void Init()
{
OsmNominatim.Instance.CountryCodes.Add("de");
this._autoCompleteListView = new ListView
{
IsVisible = false,
RowHeight = 40,
HeightRequest = 0,
BackgroundColor = Color.White
};
this._autoCompleteListView.ItemTemplate = new DataTemplate(typeof(MapSearchCell));
View searchView;
if (this._useSearchBar)
{
this._searchBar = new SearchBar
{
Placeholder = "Search for address..."
};
this._searchBar.TextChanged += SearchTextChanged;
this._searchBar.SearchButtonPressed += SearchButtonPressed;
searchView = this._searchBar;
}
else
{
this._entry = new Entry
{
Placeholder = "Sarch for address"
};
this._entry.TextChanged += SearchTextChanged;
searchView = this._entry;
}
this.Children.Add(searchView,
Constraint.Constant(0),
Constraint.Constant(0),
widthConstraint: Constraint.RelativeToParent(l => l.Width));
this.Children.Add(
this._autoCompleteListView,
Constraint.Constant(0),
Constraint.RelativeToView(searchView, (r, v) => v.Y + v.Height));
this._autoCompleteListView.ItemSelected += ItemSelected;
this._textChangeItemSelected = false;
}
private void SearchButtonPressed(object sender, EventArgs e)
{
if (this._predictions != null && this._predictions.Any())
this.HandleItemSelected(this._predictions.First());
else
this.Reset();
}
private void SearchTextChanged(object sender, TextChangedEventArgs e)
{
if (this._textChangeItemSelected)
{
this._textChangeItemSelected = false;
return;
}
this.SearchPlaces();
}
private async void SearchPlaces()
{
try
{
if (string.IsNullOrEmpty(this.SearchText))
{
this._autoCompleteListView.ItemsSource = null;
this._autoCompleteListView.IsVisible = false;
this._autoCompleteListView.HeightRequest = 0;
return;
}
IEnumerable<IPlaceResult> result = null;
if (this.ApiToUse == PlacesApi.CustomList)
{
myList.Add(new SearchBarModel
{
Name = "Test1",
Description = "On item select, show me on map!",
Longitude = 20.4680701,
Latitude = 44.8152658
});
myList.Add(new SearchBarModel
{
Name = "Test2",
Description = "On item select, show me on map!",
Longitude = 20.4233035,
Latitude = 44.805651,
});
myList.Add(new SearchBarModel
{
Name = "Test3",
Description = "On item select, show me on map!",
Longitude = 20.456054,
Latitude = 44.8839925
});
myList.Add(new SearchBarModel
{
Name = "Test4",
Description = "On item select, show me on map!",
Longitude = 20.4328035,
Latitude = 44.8071928,
});
result = myList.OfType<IPlaceResult>().ToList<IPlaceResult>();
}
else
{
result = await OsmNominatim.Instance.GetPredictions(this.SearchText);
}
if (result != null && result.Any())
{
this._predictions = result;
this._autoCompleteListView.HeightRequest = result.Count() * 40;
this._autoCompleteListView.IsVisible = true;
this._autoCompleteListView.ItemsSource = this._predictions;
}
else
{
this._autoCompleteListView.HeightRequest = 0;
this._autoCompleteListView.IsVisible = false;
}
}
catch (Exception x)
{
// TODO
}
}
//From here my code partially works
private void ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null) return;
var prediction = (IPlaceResult)e.SelectedItem;
this.HandleItemSelected(prediction);
}
private void HandleItemSelected(IPlaceResult prediction)
{
if (this.SetMap != null && this.SetMap.CanExecute(this))
{
this.SetMap.Execute(prediction);
}
this._textChangeItemSelected = true;
this.SearchText = prediction.Description;
this._autoCompleteListView.SelectedItem = null;
this.Reset();
}
private void Reset()
{
this._autoCompleteListView.ItemsSource = null;
this._autoCompleteListView.IsVisible = false;
this._autoCompleteListView.HeightRequest = 0;
if (this._useSearchBar)
this._searchBar.Unfocus();
else
this._entry.Unfocus();
}
}
}