How to uncheck a checkbox after returning to a page - xamarin.forms

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;
}
}

Related

Selecting anf geting multiple data from different checkboxes

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();

Xamarin Firebase and Syncfusion DataGrid. How do I listen for Firebase changes?

I'm having trouble with the coding to properly listen for Firebase add or update events. My attempt below has the data loading into the Syncfusion Datagrid, but there is a weird glitch where when I click the mouse on the Datagrid and pull-down, the first record in my 4 record set gets added to the bottom of the Datagrid, showing a 5th record... if I update an element in the Datagrid, the change is not reflected in Firebase. If I add or change a value in firebase, it does not update in Datagrid. Any help to steer me in the right direction to get this to work would be appreciated. Here's the code:
the VisualStudio 2019
CookPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Chart_sample"
xmlns:gauge="clr-namespace:Syncfusion.SfGauge.XForms;assembly=Syncfusion.SfGauge.XForms"
xmlns:Syncfusion="clr-namespace:Syncfusion.SfDataGrid.XForms;assembly=Syncfusion.SfDataGrid.XForms"
mc:Ignorable="d"
x:Class="Chart_sample.Views.CookPage">
<StackLayout>
<Syncfusion:SfDataGrid x:Name="sfGrid">
</Syncfusion:SfDataGrid>
</StackLayout>
</ContentPage>
CookPage.xaml.cs
using Chart_sample.Services;
using Syncfusion.SfDataGrid.XForms;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Chart_sample.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CookPage : ContentPage
{
FirebaseHelper firebaseHelper = new FirebaseHelper();
public CookPage()
{
InitializeComponent();
// for Syncfusion DataGrid
firebaseHelper.listenForEvents();
sfGrid.ItemsSource = ViewProgramModel._returnedEvents;
sfGrid.ColumnSizer = ColumnSizer.Star;
sfGrid.AllowEditing = true;
sfGrid.NavigationMode = NavigationMode.Cell;
sfGrid.SelectionMode = Syncfusion.SfDataGrid.XForms.SelectionMode.Single;
}
}
}
FirebaseHelper.cs
using Firebase.Database;
using Firebase.Database.Query;
using System;
using System.Linq;
namespace Chart_sample.Services
{
public class FirebaseHelper
{
internal ViewProgramModel ViewProgramModel { get; set; }
FirebaseClient firebase = new FirebaseClient("https://pelletpirate.firebaseio.com/");
private readonly string ChildProgram = "ControllerData/Pellet_Pirate_1/Program";
public static IDisposable returnedEvents;
public async void listenForEvents()
{
ViewProgramModel._returnedEvents.Clear();
var programs = await firebase.Child(ChildProgram).OnceAsync<ViewProgramModel>();
for (int i = 0; i < programs.Count; i++)
{
ViewProgramModel._returnedEvents.Add(programs.ElementAt(i).Object);
}
returnedEvents = firebase.Child(ChildProgram).OrderByKey().AsObservable<ViewProgramModel>()
.Subscribe(eventReceived =>
{
if (eventReceived.EventType == Firebase.Database.Streaming.FirebaseEventType.InsertOrUpdate)
{
var found = ViewProgramModel._returnedEvents.FirstOrDefault(i => i._KEY == eventReceived.Key);
if (found == null)
{
// not in observable collection, add it
ViewProgramModel._returnedEvents.Add(eventReceived.Object);
}
else
{
// event was updated
int tempIndex = ViewProgramModel._returnedEvents.IndexOf(found);
ViewProgramModel._returnedEvents[tempIndex] = eventReceived.Object;
}
}
});
}
}
}
ViewProgrammodel.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace Chart_sample
{
public class ViewProgramModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _KEy;
private string MOde;
private int TArget;
private string TRigger;
private int TRiggerVAlue;
public string _KEY
{
get { return _KEy; }
set
{
this._KEy = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("_KEY"));
}
}
public string MODE
{
get { return MOde; }
set
{
this.MOde = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MODE"));
}
}
public int TARGET
{
get { return TArget; }
set
{
this.TArget = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TARGET"));
}
}
public string TRIGGER
{
get { return TRigger; }
set
{
this.TRigger = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TRIGGER"));
}
}
public int TRIGGERVALUE
{
get { return TRiggerVAlue; }
set
{
this.TRiggerVAlue = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TRIGGERVALUE"));
}
}
public static ObservableCollection<ViewProgramModel> _returnedEvents = new ObservableCollection<ViewProgramModel>();
}
}
I edit your demo, I achieve the update, Add, delete function.
Here is running GIF.
I change your ViewProgramModel like following code. Just move the _returnedEvents to the FirebaseHelper.cs
namespace Chart_sample
{
public class ViewProgramModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _KEy;
private string MOde;
private int TArget;
private string TRigger;
private int TRiggerVAlue;
public string _KEY
{
get { return _KEy; }
set
{
this._KEy = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("_KEY"));
}
}
public string MODE
{
get { return MOde; }
set
{
this.MOde = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("MODE"));
}
}
public int TARGET
{
get { return TArget; }
set
{
this.TArget = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TARGET"));
}
}
public string TRIGGER
{
get { return TRigger; }
set
{
this.TRigger = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TRIGGER"));
}
}
public int TRIGGERVALUE
{
get { return TRiggerVAlue; }
set
{
this.TRiggerVAlue = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TRIGGERVALUE"));
}
}
}
Here is FirebaseHelper.cs, Note: I achieve the update function just for the TARGET Column, I suggest your to add a Primary-key(Auto-increase) for every record in your database to achieve your search function.
public class FirebaseHelper
{
public ObservableCollection<ViewProgramModel> _returnedEvents { get; set; }
public FirebaseHelper()
{
_returnedEvents = new ObservableCollection<ViewProgramModel>();
}
// internal ViewProgramModel MyViewProgramModel { get; set; }
FirebaseClient firebase = new FirebaseClient("https://xxxxxxxxxx.firebaseio.com/");
private readonly string ChildProgram = "ControllerData/xxxxxx_Pirate_1/Program";
public static IDisposable returnedEvents;
public async Task AddViewProgramModel()
{
//new ViewProgramModel() { MODE="test", TARGET=122, TRIGGER="122", TRIGGERVALUE=333, }
await firebase
.Child(ChildProgram)
.PostAsync( new ViewProgramModel() { MODE = "test", TARGET = 122, TRIGGER = "122", TRIGGERVALUE = 333, });
GetAllData();
}
public async Task UpdateViewProgramModel(ViewProgramModel viewProgramModel , string oldValue)
{
var toUpdatePerson = (await firebase
.Child(ChildProgram)
.OnceAsync<ViewProgramModel>()).FirstOrDefault(a => a.Object.TARGET == Convert.ToInt32( oldValue));
await firebase
.Child(ChildProgram)
.Child(toUpdatePerson.Key)
.PutAsync(viewProgramModel);
GetAllData();
}
public async Task DeleteViewProgramModel(string mode)
{
var toDeletePerson = (await firebase
.Child(ChildProgram)
.OnceAsync<ViewProgramModel>()).FirstOrDefault(a => a.Object.MODE == mode);
await firebase.Child(ChildProgram).Child(toDeletePerson.Key).DeleteAsync();
GetAllData();
}
public async void GetAllData()
{
_returnedEvents.Clear();
var programs = await firebase.Child(ChildProgram).OnceAsync<ViewProgramModel>();
for (int i = 0; i < programs.Count; i++)
{
_returnedEvents.Add(programs.ElementAt(i).Object);
}
}
public async void listenForEvents()
{
_returnedEvents.Clear();
var programs = await firebase.Child(ChildProgram).OnceAsync<ViewProgramModel>();
for (int i = 0; i < programs.Count; i++)
{
_returnedEvents.Add(programs.ElementAt(i).Object);
}
//returnedEvents = firebase.Child(ChildProgram).OrderByKey().AsObservable<ViewProgramModel>()
// .Subscribe(eventReceived =>
// {
// if (eventReceived.EventType == Firebase.Database.Streaming.FirebaseEventType.InsertOrUpdate)
// {
// var found = _returnedEvents.FirstOrDefault(i => i._KEY == eventReceived.Key);
// if (found == null)
// {
// // not in observable collection, add it
// _returnedEvents.Add(eventReceived.Object);
// }
// else
// {
// // event was updated
// int tempIndex = _returnedEvents.IndexOf(found);
// _returnedEvents[tempIndex] = eventReceived.Object;
// }
// }
//});
}
}
}
Here is CookPage.xaml
<StackLayout>
<Button Text="add" Clicked="Button_Clicked"></Button>
<Button Text="delete" Clicked="Button_Clicked_1"></Button>
<Syncfusion:SfDataGrid x:Name="sfGrid" ItemsSource="{Binding _returnedEvents, Mode=TwoWay} " >
</Syncfusion:SfDataGrid>
</StackLayout>
Here is code about CookPage.cs.
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CookPage : ContentPage
{
FirebaseHelper firebaseHelper = new FirebaseHelper();
public CookPage()
{
InitializeComponent();
// for Syncfusion DataGrid
firebaseHelper.listenForEvents();
//sfGrid.ItemsSource = ViewProgramModel._returnedEvents;
BindingContext= firebaseHelper;
sfGrid.ColumnSizer = ColumnSizer.Star;
sfGrid.AllowEditing = true;
sfGrid.NavigationMode = NavigationMode.Cell;
sfGrid.AllowLoadMore = true;
sfGrid.AutoGenerateColumns = true;
//sfGrid.AutoGenerateColumnsMode= AutoGenerateColumnsMode.
sfGrid.SelectionMode = Syncfusion.SfDataGrid.XForms.SelectionMode.Single;
sfGrid.AllowPullToRefresh = true;
sfGrid.CurrentCellEndEdit += SfGrid_CurrentCellEndEdit; ;
}
private async void SfGrid_CurrentCellEndEdit(object sender, GridCurrentCellEndEditEventArgs e)
{
//throw new System.NotImplementedException();
var selectObj = sender as SfDataGrid;
RowColumnIndex index = e.RowColumnIndex;
int selectColumnIndex = index.ColumnIndex; //2
int selectRowIndex = index.RowIndex; //3
var ob=firebaseHelper._returnedEvents;
ViewProgramModel selectObject =ob[selectRowIndex-1];
var newVale = e.NewValue.ToString();
var oldeValue = e.OldValue.ToString();
//Here just judge TARGET Column, you should judge all Columns
if (selectColumnIndex == 2)
{
selectObject.TARGET = Convert.ToInt32(newVale);
}
//If you want to achieve the all Grid change function, you should judge the selectRowIndex for every change
//if (selectRowIndex==1)
//{
// selectObject.MODE = newVale;
//}else if (selectRowIndex==2)
//{
// selectObject.TARGET = Convert.ToInt32( newVale);
//}else if (selectRowIndex == 3)
//{
// selectObject.TRIGGER = newVale;
//}else if (selectRowIndex == 4)
//{
// selectObject.TRIGGERVALUE = Convert.ToInt32(newVale);
//}
await firebaseHelper.UpdateViewProgramModel(selectObject, oldeValue);
}
private async void Button_Clicked(object sender, System.EventArgs e)
{
await firebaseHelper.AddViewProgramModel();
}
private async void Button_Clicked_1(object sender, System.EventArgs e)
{
await firebaseHelper.DeleteViewProgramModel("test");
}
}

After phone restart 'unfortunately app has stopped' error

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));
}
}

Xamarin Forms pedometer application foreground service problem on android oreo 8.1 and android pie 9.0

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;
});
}
}

autocomplete for TKCustomMap from CustomList

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();
}
}
}

Resources