How to do FlowListView in XAML Xamarin.Forms?
Here is my Code:
XAML:
<flv:FlowListView FlowColumnCount="3" SeparatorVisibility="None" HasUnevenRows="true" x:Name="grid_list" ItemsSource="{Binding list_grid}" HeightRequest="100" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<Image Source="{Binding Image}" Margin="20" VerticalOptions="Fill" HorizontalOptions="Fill" XAlign="Center" YAlign="Center"/>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>
CODE.cs
public partial class PlanCampaign_DetailPage : ContentPage
{
ObservableCollection<CarosualImages> list_grid { get; set; }
public PlanCampaign_DetailPage()
{
InitializeComponent();
this.BindingContext = this;
list_grid = new ObservableCollection<CarosualImages>()
{
new CarosualImages { Image="maharastra.jpg"},
new CarosualImages {Image="delhi.jpg"},
new CarosualImages {Image="delhi.jpg"},
new CarosualImages {Image="delhi.jpg"},
new CarosualImages {Image="delhi.jpg"},
};
grid_list.ItemsSource = list_grid;
}
ModelClass:
public class CarosualImages
{
public string Image { get; set; }
}
Could anyone tell that where i did mistake here, this is showing Empty Screen.
Here is the code for INotifyPropertyChanged
public class CarosualImages : INotifyPropertyChanged
{
private string _name = String.Empty;
public CarosualImages()
{
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string ImageName
{
get { return _name; }
set
{
_name= value;
OnPropertyChanged();
}
}
}
Put Public before
ObservableCollection<CarosualImages> list_grid { get; set; }
Related
I have a Content page, which contain CollectionView inside CarouselView.
First time when the page is loading the double embedded binding is work fine. Show everithing correctly.
But when i try to change embedded property value nothing happen. How update these properties?
formChooseElement.formViewerElements[0].formViewerElementAnswares[0].color=Color.Green;
Like:
<CarouselView ItemsSource="{Binding formViewerElements}">
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding text}" />
<CollectionView ItemsSource="{Binding formViewerElements}" >
<CollectionView.ItemTemplate>
<DataTemplate >
<StackLayout BackgroundColor="{Binding color}">
<Label Text="{Binding text}" >
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
BindingContext in code behind:
this.BindingContext = new FormViewerViewModell();
ViewModell:
public class FormViewerViewModell : INotifyPropertyChanged
{
public FormViewerViewModell()
{
GenerateData
}
private FormChooseElement FormChooseElement;
public FormChooseElement formChooseElement
{
get => FormChooseElement;
set
{
FormChooseElement = value;
OnPropertyChanged(nameof(FormChooseElement));
}
}
public ObservableCollection<FormViewerElement> formViewerElements
{
get => formChooseElement.formViewerElements;
set
{ formChooseElement.formViewerElements = value;
OnPropertyChanged(nameof(formChooseElement.formViewerElements));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
FormChooseElement
public class FormChooseElement
{
public ...
public ObservableCollection<FormViewerElement> formViewerElements { get; set; }
}
FormViewerElement
public class FormViewerElement
{
public ...
public ObservableCollection<FormViewerElementAnsware> formViewerElementAnswares { get; set; }
}
FormViewerElementAnsware
public class FormViewerElementAnsware
{
public ...
public Color color { get; set; };
I'm trying to use a single Label to display one of the two data fields alternately in Xamarin Forms. Only Label 1 Displaying the binding field (Contact_Name), while second Label which I am trying to use a variable "DisplayField" is not displaying either 'Contact_Address' or 'Contact_eMail' .
Question posted before and Another user tried to help but it didn't work!
Model Class
public class Contacts
{
[PrimaryKey][Autoincrement]
public int Contact_ID { get; set; }
public string Contact_Name { get; set; }
public string Contact_Address { get; set; }
public string Contact_eMail { get; set; }
}
XAML Page
<StackLayout>
<Button Text="Display Address" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Fill" Clicked="Display_Address" />
<Button Text="Display Email" FontSize="Large" HorizontalOptions="Center" VerticalOptions="Fill" Clicked="Display_eMail" />
<Entry HorizontalOptions="FillAndExpand" Text="{Binding DisplayField}" />
<ListView x:Name="listView" HasUnevenRows="True" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout Orientation="Vertical" VerticalOptions="CenterAndExpand" >
<Frame >
<StackLayout Orientation="Vertical" VerticalOptions="Center">
<Label Text="{Binding Contact_Name}" FontSize="Medium" LineBreakMode="WordWrap" />
<Label Text="{Binding DisplayField}" LineBreakMode="WordWrap" />
</StackLayout>
</Frame>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
Code Behind
public partial class FieldSwap : ContentPage
{
readonly FieldViewModel _fieldViewModel;
readonly SQLiteAsyncConnection _connection = DependencyService.Get<ISQLite>().GetConnection();
public ObservableCollection<Contacts> CList { get; set; }
public static string DisplayField { get; private set; }
public static int caseSwitch { get; private set; }
public FieldSwap()
{
InitializeComponent();
_fieldViewModel = new FieldViewModel();
_fieldViewModel.Field = "Contact_Address";
this.BindingContext = _fieldViewModel;
}
public static void SelectField()
{
switch (caseSwitch)
{
case 1:
DisplayField = "Contact_Address";
break;
case 2:
DisplayField = "Contact_eMail";
break;
default:
DisplayField = ("Contact_Address");
break;
}
}
private void Display_Address(object sender, EventArgs e)
{
caseSwitch = 1;
SelectField();
ReadData();
}
private void Display_eMail(object sender, EventArgs e)
{
caseSwitch = 2;
SelectField();
ReadData();
}
public void ReadData()
{
var list = _connection.Table<Contacts>().ToListAsync().Result;
CList = new ObservableCollection<Contacts>(list);
listView.ItemsSource = CList;
}
}
View Model Class
public class FieldViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
String _field;
public string Field
{
set
{
if (!value.Equals(_field, StringComparison.Ordinal))
{
_field = value;
OnPropertyChanged("DisplayField");
}
}
get
{
return _field;
}
}
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new
PropertyChangedEventArgs(propertyName));
}
}
You could use IsVisible property to achieve that, not need to bind only one lable.
Therefore, binding Contact_Address and Contact_eMail with two lables in StackLayout as follows:
<StackLayout Orientation="Vertical" VerticalOptions="Center">
<Label Text="{Binding Contact_Name}" FontSize="Medium" LineBreakMode="WordWrap" />
<Label Text="{Binding Contact_Address}" IsVisible="{Binding AddressVisible}" LineBreakMode="WordWrap" />
<Label Text="{Binding Contact_eMail}" IsVisible="{Binding EMailVisible}" LineBreakMode="WordWrap" />
</StackLayout>
Then in Contacts add two visiable proerty:
public class Contacts: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
...
private bool addressVisible;
public bool AddressVisible
{
set
{
if (addressVisible != value)
{
addressVisible = value;
OnPropertyChanged("AddressVisible");
}
}
get
{
return addressVisible;
}
}
private bool eMailVisible;
public bool EMailVisible
{
set
{
if (eMailVisible != value)
{
eMailVisible = value;
OnPropertyChanged("EMailVisible");
}
}
get
{
return eMailVisible;
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Now in Contentpage, you could modify the visiable propery when button be clicked:
private void Display_Address(object sender, EventArgs e)
{
foreach(var item in CList )
{
item.AddressVisible = true;
item.EMailVisible = false;
}
}
private void Display_eMail(object sender, EventArgs e)
{
foreach (var item in CList )
{
item.AddressVisible = false;
item.EMailVisible = true;
}
}
Here is the effect:
I am trying to implement checkbox in listview and retrieve the data from the selected rows. I tried searching online, but i am not finding any proper resource and some plugins are already not working anymore. Any reference and approach from anyone will be very kind.
You can use MVVM to achieve it. Here is running GIF.
First of all, you can create a Model. Add your need binding properties.
public class MyModel:BaseViewModel
{
public bool IsChecked { get; set; }
public string Title { get; set; }
}
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var changed = PropertyChanged;
if (changed != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then create a Viewmodel to pop data.
public class MyViewModel
{
public ObservableCollection<MyModel> myModels { get; set; }
public MyViewModel()
{
myModels =new ObservableCollection<MyModel>();
myModels.Add(new MyModel() { IsChecked = false, Title = "test1" });
myModels.Add(new MyModel() { IsChecked = false, Title = "test2" });
myModels.Add(new MyModel() { IsChecked = false, Title = "test3" });
myModels.Add(new MyModel() { IsChecked = false, Title = "test4" });
myModels.Add(new MyModel() { IsChecked = false, Title = "test5" });
}
}
Then Create a layout to display the data.
<ListView x:Name="listView" ItemsSource="{Binding myModels}" ItemSelected="listView_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="#eee"
Orientation="Vertical">
<StackLayout Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}"></CheckBox>
<Label Text="{Binding Title}" TextColor="#f35e20" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Here is background code for the layout, then retrieve the data from the selected rows and make a bindingContext.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
this.BindingContext = new MyViewModel();
}
private void listView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var myModel=e.SelectedItem as MyModel;
DisplayAlert("title",myModel.Title+" "+myModel.IsChecked,"OK");
}
}
I retrieve data from the Azure database to show one of the tabbed pages. when calling the method from ViewModel in OnAppearing not retrieve data, but when click the button it retrieves and shows on the page.
Please advice If I have constructed ViewModel and view correctly? if so why it doesn't work. ?
Connection manager:
public partial class DatabaseManager
{
static DatabaseManager defaultInstance = new DatabaseManager();
MobileServiceClient client;
IMobileServiceTable<Person> personTable;
private DatabaseManager()
{
this.client = new MobileServiceClient(Constants.AzureMobileAppURL);
this.personTable = client.GetTable<Person>();
}
public static DatabaseManager DefaultManager
{
get
{
return defaultInstance;
}
private set
{
defaultInstance = value;
}
}
public MobileServiceClient CurrentClient
{
get { return client; }
}
}
Model:
public class Person
{
[JsonProperty(PropertyName = "FirstName")]
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
[JsonProperty(PropertyName = "DisplayName")]
public string DisplayName
{
get { return displayName; }
set { displayName = value; }
}
[JsonProperty(PropertyName = "LastName")]
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
}
ViewModel:
public class ProfilePageViewModel : ViewModelBase
{
DatabaseManager manager;
string firstName = "";
string lastName = "";
string displayName = "";;
IMobileServiceTable<Person> personTable;
public ProfilePageViewModel()
{
manager = DatabaseManager.DefaultManager;
this.personTable = manager.CurrentClient.GetTable<Person>();
RefreshCommand = new Command(
execute: async () =>
{
try
{
await GetProfileAsync();
}
catch
{
}
});
}
public async Task GetProfileAsync()
{
try
{
IEnumerable<Person> items = await personTable
.Where(pserson => pserson.Active)
.ToEnumerableAsync();
foreach (var item in items)
{
FirstName = item.FirstName;
LastName = item.LastName;
DisplayName = item.DisplayName;
}
}
catch (Exception e)
{
}
}
public string FirstName
{
private set { SetProperty(ref firstName, value); }
get { return firstName; }
}
public string LastName
{
private set { SetProperty(ref lastName, value); }
get { return lastName; }
}
public string DisplayName
{
private set { SetProperty(ref displayName, value); }
get { return displayName; }
}
public ICommand RefreshCommand { private set; get; }
}
View:
ProfilePage.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"
x:Class="SLSNZ.Views.ProfilePage"
xmlns:controls="clr-
namespace:ImageCircle.Forms.Plugin.Abstractions;
assembly=ImageCircle.Forms.Plugin"
xmlns:local="clr-namespace:SLSNZ.ViewModels"
Title="Profile">
<ContentPage.Resources>
<ResourceDictionary>
<local:ProfilePageViewModel x:Key="viewModel">
</local:ProfilePageViewModel>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Icon>
<OnPlatform x:TypeArguments="FileImageSource">
<On Platform="iOS" Value="icon-profile.png" />
</OnPlatform>
</ContentPage.Icon>
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<StackLayout BindingContext="{StaticResource viewModel}">
<Label Text="Display Name"
TextColor="Gray"
FontSize="Small"
HorizontalOptions="Start" />
<Label Text="{Binding DisplayName}"
VerticalOptions="Center"
HorizontalOptions="Start"
VerticalOptions="Start/>
<Label Text="First Name"
TextColor="Gray"
FontSize="Small"
HorizontalOptions="Start" />
<Label Text="{Binding FirstName}"
FontSize="Large"
HorizontalOptions="Start"
VerticalOptions="Start" />
<Label Text="Last Name"
TextColor="Gray"
FontSize="Small"
HorizontalOptions="Start" />
<Label Text="{Binding LastName}"
FontSize="Large"
HorizontalOptions="Start"
VerticalOptions="Start" />
<Button Text="Refresh"
Command="{Binding RefreshCommand}"
Grid.Row="0" Grid.Column="1"/>
</StackLayout>
</ContentPage>
View:
ProfilePage.cs
public partial class ProfilePage : ContentPage
{
ProfilePageViewModel viewModel;
public ProfilePage()
{
InitializeComponent();
viewModel = new ProfilePageViewModel();
}
protected override async void OnAppearing()
{
base.OnAppearing();
await viewModel.GetProfileAsync();
}
}
ViewModelBase:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value,
[CallerMemberName] string propertyName =
null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName
= null)
{
PropertyChanged?.Invoke(this, new
PropertyChangedEventArgs(propertyName));
}
}
In your view by the time you await viewModel.GetProfileAsync(); The view will already render.
Your GetProfileAsync in the View Model does an await so will get the data then update it.
I suggest changing the IMobileServiceTable personTable to a property and implement a on Property change to notify the view that the data has changes.
So your viewmodel should implement INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string name = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
Then when the Data Changes you can notify it in the view model like:
OnPropertyChanged("personTable");
Also in your view change your code to:
pre-initialize the viewmodel:
public ProfilePage()
{
InitializeComponent();
SetViewModel();
}
protected async void SetViewModel()
{
viewmodel = await viewModel.GetProfileAsync();
}
This way you wont block the UI thread and when you call the OnPropertyChnage it will notify your view to update.
UPDATE:
I have created a small sample Xamarin project for you to demonstrate how you can bind and notify the view of changes.
You had a few issues in your view as well where your DisplayName label was not closed properly and you had duplicate properties for HorizontalOptions in some labels.
Download this Xamarin sample. It had hard coded data but will show you the flow of setting the data and the Binding Context of the View without locking the UI thread.
https://github.com/loanburger/54430503
I'm developing an app with Xamarin.Forms (xaml), but now i have a strange behavior with the grouping of the ListView
I have a ListView with a CustomCell if i display it without grouping everything works as expected, but if I set IsGroupingEnabled to true the screen is getting black.
Before Grouping:
With grouping
I have no idea what i'm missing or what i did wrong.
MainPage.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:cell="clr-namespace:BrindaApp.Cells"
x:Class="BrindaApp.Tabs.MainTab" Title="Main">
<StackLayout>
<StackLayout Orientation="Horizontal">
<Entry Placeholder="Search" HorizontalOptions="StartAndExpand"></Entry>
<Image x:Name="image_Group" HorizontalOptions="End">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="Group_Tapped" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
<StackLayout VerticalOptions="FillAndExpand">
<ListView ItemsSource="{Binding ProductSource}" HasUnevenRows="True" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" x:Name="mainListView"
RelativeLayout.HeightConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=1,Constant=0}" IsPullToRefreshEnabled="True" BackgroundColor="Black"
GroupDisplayBinding="{Binding Category}" GroupShortNameBinding="{Binding Category}" IsGroupingEnabled="True">
<ListView.Resources>
</ListView.Resources>
<ListView.ItemTemplate>
<DataTemplate>
<cell:ProductCell ImageUrl="{Binding ProductImageUrl}" Difficult="{Binding Difficult}" Titel="{Binding Titel}" IsFavorit="{Binding IsFavorit}" ProductId="{Binding ProductId}"
RelativeLayout.HeightConstraint= "{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=.2,Constant=0}" Height="200" Tapped="ProductCell_Tapped"
></cell:ProductCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!--</RelativeLayout>-->
</StackLayout>
</StackLayout>
<!--<Label Text="Some Text"/>-->
</ContentPage>
MainPage.xaml.cs
public partial class MainTab : ContentPage
{
ProductsViewModel viewModel;
public bool IsGrouped { get; set; }
public MainTab()
{
viewModel = new ProductsViewModel();
BindingContext = viewModel;
InitializeComponent();
viewModel.mainListView = mainListView;
image_Group.Source = ImageSource.FromResource("BrindaApp.Imgs.group.png");
}
private void ProductCell_Tapped(object sender, EventArgs e)
{
Navigation.PushAsync(new ProductDetails());
}
private void Group_Tapped(object sender, EventArgs e)
{
if(IsGrouped)
{
mainListView.IsGroupingEnabled = false;
}
else
{
mainListView.IsGroupingEnabled = true;
}
IsGrouped = !IsGrouped;
}
}
Model:
public class ProductModel
{
public string ProductImageUrl { get; set; }
public string Titel { get; set; }
public int Difficult { get; set; }
public bool IsFavorit { get; set; }
public string ProductId { get; set; }
public string Category { get; set; }
}
ViewModel
public class ProductsViewModel:BaseViewModel
{
public ListView mainListView;
ObservableCollection<ProductModel> productSource;
public ObservableCollection<ProductModel> ProductSource
{
get
{
return productSource;
}
set
{
productSource = value;
FirePropertyChanged("ProductSource");
}
}
public ICommand RefreshListView { get; set; }
public ProductsViewModel()
{
ProductSource = new ObservableCollection<ProductModel>();
ProductSource.Add(new ProductModel() { ProductImageUrl = "https://media-cdn.tripadvisor.com/media/photo-s/02/d7/5a/1c/essen-trinken.jpg", IsFavorit = true, Category = "Test" });
ProductSource.Add(new ProductModel() { ProductImageUrl = "https://www.burgerking.at/003_at/website/slider/17_028_pop_cheesemas16_at/17_028_pop_cheesemas16_at_startseitenslider_01_product_angusclaus.png", Category = "Test" });
ProductSource.Add(new ProductModel() { ProductImageUrl = "https://media-cdn.tripadvisor.com/media/photo-s/02/d7/5a/1c/essen-trinken.jpg", IsFavorit = true });
ProductSource.Add(new ProductModel() { ProductImageUrl = "https://www.burgerking.at/003_at/website/slider/17_028_pop_cheesemas16_at/17_028_pop_cheesemas16_at_startseitenslider_01_product_angusclaus.png", Category = "Test" });
FirePropertyChanged("ProductSource");
RefreshListView = new Command(() =>
{
//TODO refresh list
mainListView.IsRefreshing = false;
},
() =>
{
return true;
});
}
}
I'm struggeling here for days and cannot find an answer, hopefuly someone can help me.
As guid i used: https://developer.xamarin.com/guides/xamarin-forms/user-interface/listview/customizing-list-appearance/#Grouping
When reading the link you also referred to yourself, you are required to create a list of lists:
Create a list of lists (a list of groups, each group being a list of elements).
Right now, you just have a flat list which is most likely why you experience your issue.
An example, also taken from the same link, is as follows:
static PageTypeGroup()
{
List<PageTypeGroup> Groups = new List<PageTypeGroup> {
new PageTypeGroup ("Alfa", "A"){
new PageModel("Amelia", "Cedar", new switchCellPage(),""),
new PageModel("Alfie", "Spruce", new switchCellPage(), "grapefruit.jpg"),
new PageModel("Ava", "Pine", new switchCellPage(), "grapefruit.jpg"),
new PageModel("Archie", "Maple", new switchCellPage(), "grapefruit.jpg")
},
new PageTypeGroup ("Bravo", "B"){
new PageModel("Brooke", "Lumia", new switchCellPage(),""),
new PageModel("Bobby", "Xperia", new switchCellPage(), "grapefruit.jpg"),
new PageModel("Bella", "Desire", new switchCellPage(), "grapefruit.jpg"),
new PageModel("Ben", "Chocolate", new switchCellPage(), "grapefruit.jpg")
}
}
All = Groups; //set the publicly accessible list
}