Mocking of GPS not updating lon and lat - xamarin

Ok I am using Lockito from the app store andriod to mock my location and I am getting the first long and lat but its not updating as it should I am storing the location in a list
This function here locationObtained does not appear to be getting called more than once.
I am using a real device for testing and have granted pemission to location.
private async Task<int> StartGps()
{
var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Permission.Location);
if (status != PermissionStatus.Granted)
{
if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync(Permission.Location))
{
await DisplayAlert("Need location", "Gunna need that location", "OK");
}
var results = await CrossPermissions.Current.RequestPermissionsAsync(Permission.Location);
status = results[Permission.Location];
}
ILocation loc = DependencyService.Get<ILocation>();
loc.locationObtained += (object ss, ILocationEventArgs ee) =>
{
lat = ee.lat;
lng = ee.lng;
lbllat.Text = ee.lat.ToString();
lbllong.Text = ee.lng.ToString();
Position position = new Position(lat, lng);
postionsList.Add(position);
};
listPostions.ItemsSource = postionsList;
loc.ObtainMyLocation();
return 1;
}
In My Listview I have the following.
<ListView x:Name="listPostions" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="#eee"
Orientation="Vertical">
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Latitude}"
TextColor="#f35e20" />
<Label Text="{Binding Longitude}"
HorizontalOptions="EndAndExpand"
TextColor="#503026" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The problem is its not auto updating my app i have seti lockito to be the choosen app in developer options I have location on and can see the movement in Lockito fine but i cant see the orther cordinates from Lockito comming into my app.
This is my andriod function
public class GetMyLocation : Java.Lang.Object, ILocation, ILocationListener
{
public event EventHandler<ILocationEventArgs> locationObtained;
public void ObtainMyLocation()
{
LocationManager lm = (LocationManager)Forms.Context.GetSystemService(Context.LocationService);
lm.RequestLocationUpdates(LocationManager.NetworkProvider,0, 0, this);
}
public void OnLocationChanged(Location location)
{
if (location != null)
{
LocationEventArgs args = new LocationEventArgs();
args.lat = location.Latitude;
args.lng = location.Longitude;
locationObtained(this, args);
}
}
public void OnProviderDisabled(string provider)
{
}
public void OnProviderEnabled(string provider)
{
}
public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras)
{
}
}

Related

Xamarin MVVM image viewer with zoom and pan

I have a Xamarin MVVM class that displays a full page image. The code is shown below. The single tap simply closes the view. My question is how to implement the pan or zoom. The only things that I can find are written for Xamarin Forms and I can't figure out how to adapt them to MVVM. Thanks.
<?xml version="1.0" encoding="utf-8" ?>
<views:MvxContentPage x:TypeArguments="viewModels:ImageViewModel"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"
xmlns:viewModels="clr-namespace:BLE.Client.ViewModels;assembly=BLE.Client"
x:Class="BLE.Client.Pages.ImagePage" Title="View Image">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<StackLayout Grid.Row="0" Orientation="Horizontal" >
<Image x:Name="WaypointImage" Source="{Binding MyImage}" HorizontalOptions="FillAndExpand">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}"/>
<PinchGestureRecognizer Command="{Binding PinchCommand}"/>
<PanGestureRecognizer Command="{Binding PanCommand}"/>
</Image.GestureRecognizers>
</Image>
</StackLayout>
</Grid>
</views:MvxContentPage>
using System;
using System.Windows.Input;
using Xamarin.Forms;
using Acr.UserDialogs;
using MvvmCross;
using MvvmCross.ViewModels;
using MvvmCross.Navigation;
using Plugin.BLE.Abstractions.Contracts;
namespace BLE.Client.ViewModels
{
public class ImageViewModel : BaseViewModel
{
private ImageSource _myImage;
public ImageSource MyImage
{
get => _myImage;
set
{
_myImage = value;
RaisePropertyChanged(() => MyImage);
}
}
private readonly IUserDialogs _userDialogs;
private readonly IMvxNavigationService _navigation;
public String _waypoint;
public Waypoint waypoint;
public ICommand tapCommand;
public ICommand TapCommand {
get { return tapCommand; }
}
public ICommand pinchCommand;
public ICommand PinchCommand {
get { return pinchCommand; }
}
public ICommand panCommand;
public ICommand PanCommand {
get { return panCommand; }
}
public ImageViewModel(IAdapter adapter, IUserDialogs userDialogs) : base(adapter)
{
_userDialogs = userDialogs;
_navigation = Mvx.IoCProvider.Resolve<IMvxNavigationService>();
tapCommand = new Command (OnTapped);
pinchCommand = new Command (OnPinched);
panCommand = new Command (OnPan);
}
void OnTapped (object s) {
Console.WriteLine($"OnTapped: {s}");
_navigation.Close(this);
}
void OnPinched (object s) {
Console.WriteLine($"OnPinched: {s}");
}
void OnPan (object s) {
Console.WriteLine($"OnPan: {s}");
}
public override async void Prepare(MvxBundle parameters)
{
base.Prepare(parameters);
_waypoint = await GetWaypointFromBundleAsync(parameters);
string[] tags = _waypoint?.Split(' ');
char[] trimChars = { 'I', 'D', '=' };
string id = tags[0].TrimStart(trimChars);
int ID = System.Convert.ToInt32(id);
waypoint = await Database.GetWaypointAsync(ID);
MyImage = ImageSource.FromFile(waypoint.FileName);
Console.WriteLine($"prepare ID={waypoint.ID} {waypoint.FileName} ");
}
public override void ViewAppeared()
{
base.ViewAppeared();
if (_waypoint != null)
{
return;
}
_navigation.Close(this);
}
public override void ViewDisappearing()
{
base.ViewDisappearing();
}
public override void ViewDisappeared()
{
base.ViewDisappeared();
}
}
}
Update:
I found an even better solution to the one below:
My answer to a pinch and pan question
This is my previous answer that works to a point but I could not get the pinch and pan gestures to trigger:
I have found an MVVM solution that takes advantage of the bindable properties Image: TranslationX, TranslationY, and Scale. Here are the relevant code changes. I tested this by modifying MyImageTranslationX in the OnTapped method and saw that the image shifts to the right.
Now I just need to get the Image.GestureRecognizers (PinchGestureRecognizer and PanGestureRecognizer) working and then add code that I have seen elsewhere to smoothly pan and zoom.
<Image x:Name="WaypointImage"
Source="{Binding MyImage}"
Scale = "{Binding MyImageScale}"
TranslationX = "{Binding MyImageTranslationX}"
TranslationY = "{Binding MyImageTranslationY}"
HorizontalOptions="FillAndExpand">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}"/>
<PinchGestureRecognizer Command="{Binding PinchCommand}"/>
<PanGestureRecognizer Command="{Binding PanCommand}"/>
</Image.GestureRecognizers>
</Image>
public double _myImageScale = 1.0;
public double MyImageScale
{
get => _myImageScale;
set
{
_myImageScale = value;
RaisePropertyChanged(() => MyImageScale);
}
}
public double _myImageTranslationX = 0;
public double MyImageTranslationX
{
get => _myImageTranslationX;
set
{
_myImageTranslationX = value;
RaisePropertyChanged(() => MyImageTranslationX);
}
}
public double _myImageTranslationY = 0;
public double MyImageTranslationY
{
get => _myImageTranslationY;
set
{
_myImageTranslationY = value;
RaisePropertyChanged(() => MyImageTranslationY);
}
}
private ImageSource _myImage;
public ImageSource MyImage
{
get => _myImage;
set
{
_myImage = value;
RaisePropertyChanged(() => MyImage);
}
}
void OnTapped (object s) {
Console.WriteLine($"OnTapped: {MyImage}");
MyImageTranslationX = MyImageTranslationX + 100;
// _navigation.Close(this);
}

How do i add items to a observablecollection from another list view

Hi I am a beginner with Xamarin forms and need some help. I have tried looking for this method everywhere.
I have a List view with a lot of animal names. When a item is clicked it shows more info about that particular animal. I have added a button that is on each animals info page. I would like to click that "add" button, that would then add the name off the animal to another List view.
But I am stuck on how to do this, any help would be greatly appreciated.
this is the first list page in code behind
public partial class BirdListAZ : ContentPage
{
IEnumerable<birdlistmodel> GetBirds(string searchText = null)
{
var birds = new List<birdlistmodel>
{
new birdlistmodel (){Id = 1, BirdNames = "Apalis, Bar-throated" },
new birdlistmodel (){Id = 2, BirdNames = "Apalis, Yellow-breasted"},//there are alot more birds here
};
if (String.IsNullOrWhiteSpace(searchText))
return birds;
var lowerBirds = searchText.ToLower();
return birds.Where(c => c.BirdNames.ToLower().StartsWith(lowerBirds));
}
public BirdListAZ()
{
InitializeComponent();
blistview.ItemsSource = GetBirds();
}
private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
{
blistview.ItemsSource = GetBirds(e.NewTextValue);
}
private void blistview_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var birds = e.SelectedItem as birdlistmodel;
Navigation.PushAsync(new BirdPages(birds.BirdNames, birds.BirdSelect));
}
}
}
this is the content page for that code behind
<ScrollView HeightRequest="3000">
<StackLayout>
<SearchBar
TextChanged="SearchBar_TextChanged"
Placeholder="Search Bird"
PlaceholderColor="Gray"
HorizontalTextAlignment="Center"
FontSize="Small"
FontAttributes="Italic"
VerticalOptions="Center" HorizontalOptions="Start"/>
<ListView x:Name="blistview" BackgroundColor ="AliceBlue" HasUnevenRows="True" ItemSelected="blistview_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Padding="5">
<Label Text="{Binding BirdNames}" HorizontalOptions="StartAndExpand" VerticalOptions="Center"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ScrollView>
when item is clicked on list it displays that info in a separate page
the contentpage
<ContentPage.Content>
<StackLayout>
<Label x:Name="BirdNameCall" FontSize="30" FontAttributes="Bold"
VerticalOptions="StartAndExpand"
HorizontalOptions="CenterAndExpand" />
<Button Text="+" x:Name="AddToList" VerticalOptions="Center" HorizontalOptions="Center" WidthRequest="200" HeightRequest="100"
FontSize="30" BackgroundColor="Transparent" Clicked="AddToList_Clicked"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
So this is what i have done. I know the filewritealltext makes a new file each time. how can i just add to that file so a new file is not created?
public BirdPages(string BirdNames, Button BirdSelect)
{
InitializeComponent();
BirdNameCall.Text = BirdNames;
AddToList = BirdSelect;
localPath = Path.Combine(FileSystem.AppDataDirectory, birdfile);
}
const string birdfile = "birdlist.txt";
string localPath;
private void AddToList_Clicked(object sender, EventArgs e)
{
string BirdNames = BirdNameCall.Text;
File.WriteAllText(localPath, BirdNames);
DisplayAlert(BirdNames, "added to list", "Ok");
}
So it works when i populate the list view but it will be a letter per row and not the entire string in a row
public partial class myBirdList : ContentPage
{
public myBirdList()
{
InitializeComponent();
localPath = Path.Combine(FileSystem.AppDataDirectory, birdfile);
birdlistview.ItemsSource = File.ReadAllText(localPath);
}
const string birdfile = "birdlist.txt";
string localPath;
}
So this is what I have done. I had to change a bit.
The added Bird Name needs to go to a blank list. So I created a new Observable Collection here. And this is where the Bird Name needs to be added.
public partial class myBirdList : ContentPage
{
public ObservableCollection<string> Birdsadded { get; set; } = new ObservableCollection<string>();
public myBirdList()
{
InitializeComponent();
BindingContext = this;
MessagingCenter.Subscribe<BirdPages, birdlistmodel>(this, "Add", (sender, arg) =>
{
Birdsadded.Add(arg.ToString());
});
}
}
}
Then the sender is where I am having issues. And can't figure out how to send the bird name.
public partial class BirdPages : ContentPage
{
public BirdPages(string BirdNames, Button BirdSelect)
{
InitializeComponent();
BirdNameCall.Text = BirdNames;
AddToList = BirdSelect;
}
private void AddToList_Clicked(object sender, EventArgs e)
{
birdlistmodel bird = xxx// this is what i don't understand, what should be added here
MessagingCenter.Send<BirdListAZ, birdlistmodel>(this, "Add", bird );
}
}
}
thanks for your time and input I appreciate it.
You could use MessagingCenter to achieve this.
Using MessagingCenter.Send to pass the new data in your AddToList_Clicked method of BirdPages
then you will get the callback in another page which you want to add the new items with MessagingCenter.Subscribe method.In the callback method,you could add the new data to the new listview.
For example:
In the listview page which you want display a list and add the new data.
public partial class BirdListAZ : ContentPage
{
public ObservableCollection<string> Birdsadded { get; set; } = new ObservableCollection<string>();
public BirdListAZ()
{
InitializeComponent();
blistview.ItemsSource = GetBirds();
MessagingCenter.Subscribe<BirdListAZ, string>(this, "Add", async (sender, arg) =>
{
Birdsadded.Add(arg);// when you click add button in other page,it will handle this
});
}
}
in the page which you want to add the data:
public partial class BirdPages : ContentPage
{
public BirdPages(string BirdNames, Button BirdSelect)
{
InitializeComponent();
BirdNameCall.Text = BirdNames;
AddToList = BirdSelect;
}
private void AddToList_Clicked(object sender, EventArgs e)
{
string birdname = xxxx;
MessagingCenter.Send<BirdListAZ, string>(this, "Add",birdname );
}
}
OK so i got it to work to some extent. I am not creating and writing to a txt file and then reading from it in mybirdlist page. This is where i write to text file
public BirdPages(string BirdNames, Button BirdSelect)
{
InitializeComponent();
BirdNameCall.Text = BirdNames;
AddToList = BirdSelect;
localPath = Path.Combine(FileSystem.AppDataDirectory, birdfile);
}
const string birdfile = "birdlist.txt";
string localPath;
private void AddToList_Clicked(object sender, EventArgs e)
{
string BirdNames = BirdNameCall.Text;
using (var writer = new StreamWriter(localPath, true))
{
writer.WriteLine(BirdNames);
}
DisplayAlert(BirdNames, "added to list", "Ok");
}
Then i read from it into a list. Last question i have is how can i read each name into a lable. Now all the added birds displays in one label. And is it possible to not duplicate a name? Here is the code
public myBirdList()
{
localPath = Path.Combine(FileSystem.AppDataDirectory, birdfile);
string text = "";
using (var reader = new System.IO.StreamReader(localPath))
{
text = reader.ReadToEnd();
}
InitializeComponent();
birdlistview.ItemsSource = new List<birdlistmodel>
{
new birdlistmodel {Voellist = text }
};
}
const string birdfile = "birdlist.txt";
string localPath;
}

Xamarin - Bind ActivityIndicator visibility to async Task finished

I'm loading images async into my Listview according to this answer: Xamarin - Asynchronous data binding
I'd like to display a ActivityIndicator while the page is loading the data from the web, but cannot figure out how to bind the visibility it to the task, so that it disappears when the task is done loading..
I've created a isLoading bool variable in my ViewModel.
I tried it this way in my ViewModel, but It's not working:
isLoading = true;
GetImagesCommand = new Command(async () => await DoGetImagesCommand(pCode, gCode, gUrl));
isLoading = false;
I also tried setting it in the Task, but isLoading is always false..
private async Task DoGetImagesCommand(string pCode, string gCode, string gUrl)
{
isLoading = true;
var images = await _galleryService.GetImageList(pCode, gCode, gUrl);
foreach (var image in images)
Galleries.Add(image);
isLoading = false;
}
my 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:vm="clr-namespace:GalShare.ViewModel"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms" xmlns:forms="clr-namespace:RedCorners.Forms;assembly=RedCorners.Forms"
mc:Ignorable="d"
x:Class="GalShare.Views.Gallery">
<ContentPage.Content>
<AbsoluteLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<StackLayout
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1">
<CollectionView ItemsSource="{Binding Galleries}" x:Name="MyCollection" SelectionMode="Single" SelectionChanged="CollectionView_SelectionChanged">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<ContentView Padding="1">
<forms:Frame2 CornerRadius="15"
HasShadow="True"
ShadowRadius="8"
Padding="0">
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="LightGray" Padding="2">
<ffimageloading:CachedImage x:Name="myImage" Source="{Binding ThumbUrl}" Aspect="AspectFit" CacheDuration="0" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" DownsampleToViewSize="False"></ffimageloading:CachedImage>
<Label x:Name="Picname" Text="{Binding ImageName}" IsVisible="{Binding showName}" VerticalOptions="StartAndExpand" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" ></Label>
</StackLayout>
</forms:Frame2>
</ContentView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
<StackLayout IsVisible="{Binding isLoading}" x:Name="LoadingLayout" Padding="12"
AbsoluteLayout.LayoutFlags="PositionProportional"
AbsoluteLayout.LayoutBounds="0.5,0.5,-1,-1">
<ActivityIndicator />
<Label Text="Loading gallery..." HorizontalOptions="Center" TextColor="Black"/>
</StackLayout>
</AbsoluteLayout>
</ContentPage.Content>
my ViewModel:
namespace GalShare.ViewModel
{
class GalleryViewModel
{
public string pCode { get; set; }
public string gCode { get; set; }
public string gUrl { get; set; }
public bool isLoading { get; set; }
public bool showname { get; set; }
public ObservableCollection<picdata> Galleries { get; } = new ObservableCollection<picdata>();
public ICommand GetImagesCommand { get; }
private GalleryService _galleryService;
public GalleryViewModel(string pCode, string gCode, string gUrl, string showName)
{
this.pCode = pCode;
this.gCode = gCode;
this.gUrl = gUrl;
_galleryService = new GalleryService();
GetImagesCommand = new Command(async () => DoGetImagesCommand(pCode, gCode, gUrl, showName));
}
private async Task DoGetImagesCommand(string pCode, string gCode, string gUrl, string showName)
{
isLoading = true;
var images = await _galleryService.GetImageList(pCode, gCode, gUrl, showName);
foreach (var image in images)
Galleries.Add(image);
isLoading = false;
}
}
}
galleryservice:
class GalleryService
{
private HttpClient _httpClient;
public GalleryService()
{
_httpClient = new HttpClient();
}
public async Task<IEnumerable<picdata>> GetImageList(string pCode, string gCode, string gUrl, string showName)
{
var response = await _httpClient.GetAsync(gUrl).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
// var json = response.Content.GetStringAsync().ConfigureAwait(false);
var deserialized = JsonConvert.DeserializeObject<JsonTxt>(json);
bool shownametemp;
if (showName == "1")
{
shownametemp = true;
}
else
{
shownametemp = false;
}
var images = new List<picdata>();
foreach (var img in deserialized.Files)
{
images.Add(new picdata()
{
ImageName = img.file,
BaseUrl = deserialized.Settings.Path.ToString(),
ThumbUrl = deserialized.Settings.Path.ToString() + "thumbs/" + img.file,
showname = shownametemp
}) ;
}
return images;
}
return new picdata[0]; // return empty set
}
}
You sould use ActivityIndicator like that
<ActivityIndicator AbsoluteLayout.LayoutBounds="0, 0, 1, 1"
AbsoluteLayout.LayoutFlags="All"
IsVisible="{Binding IsBusy}"
IsRunning="{Binding IsBusy}"
Color="{StaticResource PrimaryColor}"
VerticalOptions="Center"
HorizontalOptions="Center" />
Use IsRunning property with IsBusy property
private bool _isBusy;
public bool IsBusy
{
get
{
return _isBusy;
}
set
{
_isBusy = value;
RaisePropertyChanged(() => IsBusy);
}
}
in viewmodel
class GalleryViewModel : ExtendedBindableObject
{
...
private async Task DoGetImagesCommand(string pCode, string gCode, string gUrl)
{
IsBusy = true;
var images = await _galleryService.GetImageList(pCode, gCode, gUrl);
foreach (var image in images)
Galleries.Add(image);
IsBusy = false;
}
}
in another class
public abstract class ExtendedBindableObject : BindableObject
{
public void RaisePropertyChanged<T>(Expression<Func<T>> property)
{
var name = GetMemberInfo(property).Name;
OnPropertyChanged(name);
}
private MemberInfo GetMemberInfo(Expression expression)
{
MemberExpression operand;
LambdaExpression lambdaExpression = (LambdaExpression)expression;
if (lambdaExpression.Body is UnaryExpression)
{
UnaryExpression body = (UnaryExpression)lambdaExpression.Body;
operand = (MemberExpression)body.Operand;
}
else
{
operand = (MemberExpression)lambdaExpression.Body;
}
return operand.Member;
}
}

Two search bar Xamarin Forms

I have a question here (I imagine it is for beginners: P).
I have a listview and a searchbar already working. I can make the right filter.
Then my question comes in, this listview has more than one column.
I can't think of a way to make 2 complementary filters.
For example:
Filter column 1 and then filter the result of that initial filter by column 2 (with another searchbar), that is, a filter on top of another filter.
My ListViewItem is like this with the filter:
C#
void InitList()
{
Items = new List<ListViewItem>
{
new ListViewItem { Name = "Guilherme", Bairro = "BOTAFOGO"},
new ListViewItem { Name = "João", Bairro = "FLAMENGO"},
new ListViewItem { Name = "Maria", Bairro = "CENTRO"}
}
}
void InitSearchBarBloco()
{
sb_search_bloco.TextChanged += (s, e) => FilterItem(sb_search_bloco.Text);
sb_search_bloco.SearchButtonPressed += (s, e) =>
FilterItem(sb_search_bloco.Text);
}
private void FilterItem(string filter)
{
exampleListView.BeginRefresh();
if (string.IsNullOrWhiteSpace(filter))
{
exampleListView.ItemsSource = Items;
}
else
{
exampleListView.ItemsSource = Items.Where(x => x.Name.ToLower().Contains(filter.ToLower()));
}
exampleListView.EndRefresh();
}
XAML
<SearchBar x:Name="sb_search_bloco" Placeholder="Nome..." />
<ListView x:Name="exampleListView" RowHeight="22" SelectedItem="{Binding Name}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<Grid>
<Label Text="{Binding Name}" LineBreakMode="TailTruncation" />
<Label Grid.Column="1" Text="{Binding Bairro}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
With this structure I can implement this ... "filtrate filter"?
thanks
I guess the below code should do fine for you. You just need to alter your linq code inside the FilterItem(string filter) method to achieve your requirement.
Note:
I have used OR condition inside the where clause to search if the enter text is available in both Name and Bairro. However, you can modify the condition as you require.
private void FilterItem(string filter)
{
exampleListView.BeginRefresh();
if (string.IsNullOrWhiteSpace(filter))
{
exampleListView.ItemsSource = Items;
}
else
{
//Alter the condition like below or based on requirement to achieve the desired result.
exampleListView.ItemsSource = Items.Where(x => x.Name.ToLower().Contains(filter.ToLower()) || x.Bairro.ToLower().Contains(filter.ToLower()));
}
exampleListView.EndRefresh();
}
I make a sample code for your referece.
xmal:
<StackLayout>
<StackLayout>
<SearchBar x:Name="sb_search_bloco" Placeholder="Nome..." TextChanged="sb_search_bloco_TextChanged"/>
<SearchBar x:Name="searchBar2" Margin="0,10" TextChanged="searchBar2_TextChanged" />
</StackLayout>
<ListView
x:Name="exampleListView"
RowHeight="22"
ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Label LineBreakMode="TailTruncation" Text="{Binding Name}" />
<Label Grid.Column="1" Text="{Binding Bairro}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
ListViewItem.cs
public class ListViewItem
{
public string Name { get; set; }
public string Bairro { get; set; }
}
MainPage.xml.cs
public partial class MainPage : ContentPage
{
public List<ListViewItem> Items { get; set; }
public MainPage()
{
InitializeComponent();
Items = new List<ListViewItem>
{
new ListViewItem { Name = "AAAA", Bairro = "BBCFS"},
new ListViewItem { Name = "ABBB", Bairro = "SSDCA"},
new ListViewItem { Name = "AAAA", Bairro = "AAAD"},
new ListViewItem { Name = "CCCC", Bairro = "SSS"},
new ListViewItem { Name = "DAAB", Bairro = "CCC"},
new ListViewItem { Name = "DDDC", Bairro = "QWDAS"}
};
this.BindingContext = this;
}
private void sb_search_bloco_TextChanged(object sender, TextChangedEventArgs e)
{
exampleListView.ItemsSource = FilterItem1(e.NewTextValue);
}
IEnumerable<ListViewItem> FilterItem1(string filter = null)
{
if (string.IsNullOrEmpty(filter))
return Items;
return Items.Where(p => p.Name.StartsWith(filter));
}
private void searchBar2_TextChanged(object sender, TextChangedEventArgs e)
{
exampleListView.ItemsSource = FilterItem2(e.NewTextValue);
}
IEnumerable<ListViewItem> FilterItem2(string filter = null)
{
if (string.IsNullOrEmpty(filter))
return Items;
return Items.Where(p => p.Bairro.StartsWith(filter));
}
}

How do I solve Xamarin.Forms.Xaml.XamlParseException

I am new to Xamarin Forms and C# too. Kindly help me to get rid of the above issue.
I am getting
Xamarin.Forms.Xaml.XamlParseException
while I am trying to add the string format of my selected image source to CandidateDetails.cs.
The pages are as follow:
CandidateDetails.cs
public event PropertyChangedEventHandler PropertyChanged;
private string imageBase64;
public string ImageBase64
{
get { return imageBase64; }
set
{
imageBase64 = value;
OnPropertyChanged("ImageBase64");
CandImage = Xamarin.Forms.ImageSource.FromStream(
() => new MemoryStream(Convert.FromBase64String(imageBase64)));
}
}
private Xamarin.Forms.ImageSource _candImage;
public Xamarin.Forms.ImageSource CandImage
{
get { return _candImage; }
set
{
_candImage = value;
OnPropertyChanged("CandImage");
}
}
public string _candName;
public string CandName
{
get { return _candName; }
set
{
if (_candName == value)
return;
_candName = value;
OnPropertyChanged("CandName");
}
}
public string _candInst;
public string CandInst
{
get { return _candInst; }
set
{
if (_candInst == value)
return;
_candInst = value;
OnPropertyChanged("CandInst");
}
}
public string _candEmailId;
public string CandEmailId
{
get { return _candEmailId; }
set
{
if (_candEmailId == value)
return;
_candEmailId = value;
OnPropertyChanged("CandEmailId");
}
}
public string _candMob;
public string CandMob
{
get { return _candMob; }
set
{
if (_candMob == value)
return;
_candMob = value;
OnPropertyChanged("CandMob");
}
}
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
CandidateDetailsModalPage.xaml.cs
public partial class CandidateDetailsModalPage : ContentPage
{
Stream input;
string imageAsString;
public static ObservableCollection<CandidateDetails> _candidate = new ObservableCollection<CandidateDetails>();
async void OnDoneClicked(object sender, System.EventArgs e)
{
_candidate.Add(new CandidateDetails
{
CandName = (string)candNameEntry.Text,
CandEmailId = (string)candEmailId.Text,
CandMob = (string)candMobNumber.Text,
ImageBase64 = imageAsString
});
await Navigation.PopModalAsync();
}
public CandidateDetailsModalPage()
{
InitializeComponent();
pickPhoto.Clicked += async (sender, args) =>
{
if (!CrossMedia.Current.IsPickPhotoSupported)
{
await DisplayAlert("Photos Not Supported", ":( Permission not granted to photos.", "OK");
return;
}
var file = await CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions
{
PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium
});
if (file == null)
return;
input = file.GetStream();
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
imageAsString = Convert.ToBase64String(ms.ToArray());
}
//image.Source = ImageSource.FromStream(() => new MemoryStream(Convert.FromBase64String(imageAsString)));
image.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
file.Dispose();
return stream;
});
};
}
}
CandidateDetailsModalPage.xaml
<StackLayout Orientation="Vertical" BackgroundColor="#3B4371" Padding="0">
<Button Text="Done" Clicked="OnDoneClicked" />
<ic:CircleImage x:Name="image"/>
<Button x:Name="pickPhoto" Text="Pick Photo"/>
<StackLayout VerticalOptions="FillAndExpand">
<Entry x:Name="candNameEntry" Placeholder="Candidate Name" />
<Entry x:Name="candInst" Placeholder="Candidate Institution / Party"/>
<Entry x:Name="candEmailId" Placeholder="Candidate Email Id" />
<Entry x:Name="candMobNumber" Placeholder="Candidate Mobile Number"/>
</StackLayout>
</StackLayout>
The following is the backend of the xaml page where I am displaying the data CandidateDisplayPage.xaml.cs
candidateListView.ItemsSource = CandidateDetailsModalPage._candidate;
CandidateDisplayPage
<ListView x:Name="candidateListView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Image x:Name="candImage" ImageSource="{Binding Path=CandImage}"/>
<Label Text="{Binding CandName}" x:Name="candName"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You say in a comment (that should have been part of the original report):
This is the error that's causing the exception Cannot assign property "ImageSource": Property does not exists, or is not assignable, or mismatching type between value and property
Indeed, Image doesn't have an ImageSource property, but instead a Source property of type ImageSource.
public ImageSource Source { get; set; }
So your Xaml should look like
Image x:Name="candImage" Source="{Binding Path=CandImage}"/>

Resources