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));
}
}
Related
I have a collectionview which has a [Label(day of the week] - [checkbox] - [picker with times].
I want the user to be able to select a day and time, after that I want to then pass those values to my database. So far I am able to select the day and pass this value on. However I am struggling to refence the value in the picker. I think this is due to it being a list in my object. I have tried booking.Listtimes but that is just a list. I want the value selected.
My ViewModel:
public class RepeatMonthly
{
public string Day { get; set; }
public bool Selected { get; set; }
public List<WalkTimes> _ListTimes { get; set; }
}
private WalkTimes _selectedTimes;
public WalkTimes SelectedTimes
{
get
{
return _selectedTimes;
}
set
{
SetProperty(ref _selectedTimes, value);
}
}
public ObservableCollection<RepeatMonthly> DayList { get; set; }
public CreateWeeklyScheduleViewModel()
{
ListTimes = WalkTimesService.GetTimes().OrderBy(c => c.Key).ToList();
DayList = new ObservableCollection<RepeatMonthly>()
{
new RepeatMonthly(){Day="Every Monday", Selected = false, _ListTimes = ListTimes},
new RepeatMonthly(){Day="Every Tuesday", Selected = false, _ListTimes = ListTimes},
new RepeatMonthly(){Day="Every WednesDay", Selected = false, _ListTimes = ListTimes},
new RepeatMonthly(){Day="Every Thursday", Selected = false, _ListTimes = ListTimes},
new RepeatMonthly(){Day="Every Friday", Selected = false, _ListTimes = ListTimes},
new RepeatMonthly(){Day="Every Saturday", Selected = false, _ListTimes = ListTimes},
new RepeatMonthly(){Day="Every Sunday", Selected = false, _ListTimes = ListTimes}
};
source = new ObservableCollection<PetProfile>();
}
My Xaml:
<CollectionView x:Name="RepeatCollectionView" HorizontalOptions="Center" ItemsSource="{Binding DayList}" HeightRequest="350">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="0" RowDefinitions="25, 20" ColumnDefinitions="*,*">
<Label Text="{Binding Day}" FontAttributes="Bold" FontSize="Medium"
Margin="5,0"
VerticalTextAlignment="Center" HorizontalTextAlignment="Start"/>
<CheckBox x:Name="SelectDayCheckBox" Grid.Row="0" HorizontalOptions="End" IsChecked="{Binding Selected, Mode=TwoWay}" BindingContext="{Binding .}" CheckedChanged="SelectDayCheckBox_CheckedChanged"/>
<Picker x:Name="SelectTimeOfWalkPicker" Title="--Select Walk Start Time--" Grid.Column="1" ItemsSource="{Binding _ListTimes}" ItemDisplayBinding="{Binding Value}" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" SelectedItem="{Binding SelectedTimes}" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
my .cs page:
private async void SubmitBtn_Clicked(object sender, EventArgs e)
{
foreach (RepeatMonthly booking in (BindingContext as CreateWeeklyScheduleViewModel).DayList)
{
if (booking.Selected)
{
await passtoDataBase(booking.Day, "where time variable goes");
}
}
await DisplayAlert("Success", "Booked Successfully", "OK");
await Shell.Current.GoToAsync($"//{nameof(MyBookingsPage)}");
}
properties of WalkTimes object:
public class WalkTimes
{
public int Key { get; set; }
public string Value { get; set; }
}
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;
}
I have a CarouselPage having 5 children and every child has a horizontal collection view. When selecting an item in Collectionview or swiping the pages, I need to give a different text color and need to add an underline for the selected item. I have tried like below:
CarouselHomePage.cs
public partial class CarouselHomePage : CarouselPage
{
public List<Activity> activityList { get; set; }
public CarouselHomePage()
{
InitializeComponent();
activityList = new List<Activity>();
AddActivities();
MessagingCenter.Subscribe<App, string>((App)Xamarin.Forms.Application.Current, "child", (s, child) =>
{
CurrentPage = Children[Int32.Parse(child)];
});
}
private void AddActivities()
{
activityList.Add(new Activity() { Title = "PageNumber1" });
activityList.Add(new Activity() { Title = "PageNumber2" });
activityList.Add(new Activity() { Title = "PageNumber3" });
activityList.Add(new Activity() { Title = "PageNumber4" });
activityList.Add(new Activity() { Title = "PageNumber5" });
AddChild(activityList);
}
public void AddChild(List<Activity> activityList)
{
this.Children.Add(new PageNumber1(activityList));
this.Children.Add(new PageNumber2(activityList));
this.Children.Add(new PageNumber3(activityList));
this.Children.Add(new PageNumber4(activityList));
this.Children.Add(new PageNumber5(activityList));
}
}
Activity.cs
public class Activity
{
public string Title { get; set; }
public bool visibility { get; set; }
public bool Visibility
{
set
{
if (value != null)
{
visibility = value;
NotifyPropertyChanged();
}
}
get
{
return visibility;
}
}
private Color textColor;
public Color TextColor
{
set
{
if (value != null)
{
textColor = value;
NotifyPropertyChanged();
}
}
get
{
return textColor;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
PageNumber1.xaml
<ContentPage.Content>
<StackLayout Orientation="Vertical">
<CollectionView
SelectionMode="Single"
x:Name="ActivityList"
Margin="5,10,5,10"
SelectionChanged="TagItemTapped"
ItemsLayout="HorizontalList">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout
Orientation="Vertical"
Margin="15">
<Label
TextColor="{Binding TextColor}"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
Text="{Binding Title}">
<Label.FontSize>
<OnIdiom x:TypeArguments="x:Double">
<OnIdiom.Phone>18</OnIdiom.Phone>
<OnIdiom.Tablet>27</OnIdiom.Tablet>
<OnIdiom.Desktop>18</OnIdiom.Desktop>
</OnIdiom>
</Label.FontSize>
</Label>
<BoxView
HeightRequest="2"
IsVisible="{Binding Visibility}"
BackgroundColor="{Binding TextColor}"
HorizontalOptions="CenterAndExpand"
VerticalOptions="Start"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.HeightRequest>
<OnIdiom x:TypeArguments="x:Double">
<OnIdiom.Phone>30</OnIdiom.Phone>
<OnIdiom.Tablet>60</OnIdiom.Tablet>
<OnIdiom.Desktop>30</OnIdiom.Desktop>
</OnIdiom>
</CollectionView.HeightRequest>
</CollectionView>
<Label Text="Welcome to PageNumber1"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
PageNumber1.xaml.cs
public partial class PageNumber1 : ContentPage
{
public PageNumber1(List<Activity> activityList)
{
InitializeComponent();
if (activityList == null)
{
ActivityList.IsVisible = false;
}
else
{
for (int i = 0; i < activityList.Count; i++)
{
if (activityList[i].Title == "PageNumber1")
{
activityList[i].TextColor = Color.FromHex("#26b4d8");
activityList[i].Visibility = true;
}
else
{
activityList[i].TextColor = Color.Gray;
activityList[i].Visibility = false;
}
}
ActivityList.ItemsSource = activityList;
}
}
public void TagItemTapped(object sender, SelectionChangedEventArgs e)
{
var selectedItem = (e.CurrentSelection.FirstOrDefault() as Activity);
if (selectedItem != null)
{
string childnumber = "";
if (selectedItem.Title == "PageNumber1")
{
childnumber = "0";
}
else if (selectedItem.Title == "PageNumber2")
{
childnumber = "1";
}
else if (selectedItem.Title == "PageNumber3")
{
childnumber = "2";
}
else if (selectedItem.Title == "PageNumber4")
{
childnumber = "3";
}
else if (selectedItem.Title == "PageNumber5")
{
childnumber = "4";
}
MessagingCenter.Send<App, string>((App)Xamarin.Forms.Application.Current, "child", childnumber);
}
}
}
I have added the same code on all the other child pages with the corresponding title in the if statement. But the selected page title color is not working and underline is not showing.
Screenshot:
Also if I select the last item in the collectionview, I need to scroll the collection on the last child to the last item. For this I have used ScrollTo feature of Collectioview. But that is also not working.
protected override void OnAppearing()
{
ActivityList.ScrollTo(4);
}
The above code will work if I manually swipe the pages. When directly tap the collectionview item, the scrolling is not working.
I have uploaded a sample project here.
About underline not showing , the reason is HeightRequest of CollectionView setted too small with 30 .
Modify that to above 35 , it will show correcttly . Such as :
<CollectionView.HeightRequest>
<OnIdiom x:TypeArguments="x:Double">
<OnIdiom.Phone>40</OnIdiom.Phone>
<OnIdiom.Tablet>60</OnIdiom.Tablet>
<OnIdiom.Desktop>30</OnIdiom.Desktop>
</OnIdiom>
</CollectionView.HeightRequest>
The effect :
About selected problem , this is the sample project here .
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;
}
}
In Xamarin Forms, I have a listview that shows all the items of the item table. I want to show only the items that have the 'status' approved. how can I do this? where do I pass the 'where status = 'approved'' condition.
This is my XAML Code:
<ViewModels:ItemViewModel/>
</ContentPage.BindingContext>
<ListView ItemsSource="{Binding ItemsList}"
HasUnevenRows="True"
x:Name="lstItems"
ItemTapped="LstItems_OnItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding ItemCode}" TextColor="Blue"/>
<Label Text="{Binding ItemDesc}" TextColor="Blue"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My View Model is as below:
namespace MyFirstDbApp.ViewModels
{
public class ItemViewModel: INotifyPropertyChanged
{
private List _itemsList;
public List<Item> ItemsList
{
get { return _itemsList; }
set
{
_itemsList = value;
OnPropertyChanged();
}
}
public ItemViewModel()
{
InitializeDataAsync();
}
private async Task InitializeDataAsync()
{
var ItemServices = new ItemServices();
ItemsList = await ItemServices.GetItemsAsync();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Errors on implementing my new code:
var result = await ItemServices.GetItemsAsync().ConfigureAwait();
ItemsList = result.Where(x => x.Status == "Approved"
Line:1 -An object reference is required for the non-static field, method or property ItemServices.GetItemsAsync
Line:1-No Overload For Method 'ConfigureAwait' takes 0 argurments
Line:2-Cannot Convert SourceType 'Systems.Collection.Generic.IEnumerable ' To Target Type 'System.
Colelction.GenericList '
Filtering should be done on the ItemsList in your ViewModel, not in XAML.
_viewModel.ItemsList.Where(x => x.Status == "Approved");
Good luck :-)