Display Datagrid based on Binding item count in Xamarin Forms - xamarin.forms

I am currently using Syncfusion Sf Datagrid. I want to display the Datagrids based on count. For example I have button A and button B, if user click on A, it will display 1 datagrid. If user click on B, it will display 2 datagrid. FYI, the datagrid will display on the same page.
What my code does now is displaying all datagrid. I would like to display the datagrid only based on condition (in this case which is A or B). I am not sure how to achieve this because the datagrid is in xaml, how do I make sure the correct count of datagrid I want to appear? Let's say if I want to have more category that has different items, how do I display the correct number of datagrid according to the items inside a category?
MainPage.xaml
<ContentPage.Content>
<StackLayout>
<Button Text="A"/>
<Button Text="B"/>
<sfgrid:SfDataGrid ItemsSource="{Binding fruitA}"/>
<sfgrid:SfDataGrid ItemsSource="{Binding vegeB1}"/>
<sfgrid:SfDataGrid ItemsSource="{Binding vegeB2}"/>
</StackLayout>
</ContentPage.Content>
MainPage.cs
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
this.BindingContext = new ViewModel();
}
}
ViewModel
public class ViewModel
{
public ObservableCollection<Test> fruitA { get; set; }
public ObservableCollection<Test> vegeB1 { get; set; }
public ObservableCollection<Test> vegeB2 { get; set; }
public ViewModel()
{
fruitA = new ObservableCollection<ChildPart>();
fruitA.Add(new Test() { Title = "Orange", Value = "1.20" });
fruitA.Add(new Test() { Title = "Banana", Value = "1.40" });
fruitA.Add(new Test() { Title = "Apple", Value = "1.30" });
vegeB1 = new ObservableCollection<ChildPart>();
vegeB1.Add(new Test() { Title = "Spinach", Value = "1.20" });
vegeB1.Add(new Test() { Title = "Cabbage", Value = "1.40" });
vegeB2 = new ObservableCollection<ChildPart>();
vegeB2.Add(new Test() { Title = "Lettuce", Value = "1.20" });
vegeB2.Add(new Test() { Title = "Broccoli", Value = "1.40" });
vegeB2.Add(new Test() { Title = "Celery", Value = "1.30" });
}
}
Test
public class Test
{
public string Title { get; set; }
public string Value { get; set; }
}

There is a way to use Bindable layouts to achieve that , you can check whether is your want .
Modify MainPage.xaml as follow (Add ScrollView if count of items is too much):
<StackLayout>
<Button Text="A" Clicked="Button_Clicked_A"/>
<Button Text="B" Clicked="Button_Clicked_B"/>
<Button Text="C" Clicked="Button_Clicked_C"/>
<ScrollView>
<StackLayout x:Name="MyStackLayout" Orientation="Vertical">
<BindableLayout.ItemTemplate>
<DataTemplate>
<sfgrid:SfDataGrid ItemsSource="{Binding }" />
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
</StackLayout>
Modiy MainPage.cs asd follow :
public partial class MainPage : ContentPage
{
ViewModel viewModel;
public MainPage()
{
InitializeComponent();
viewModel = new ViewModel();
}
private void Button_Clicked_A(object sender, EventArgs e)
{
List<object> list = new List<object>();
list.Add(viewModel.fruitA);
BindableLayout.SetItemsSource(MyStackLayout, list);
}
private void Button_Clicked_B(object sender, EventArgs e)
{
List<object> list = new List<object>();
list.Add(viewModel.vegeB1);
list.Add(viewModel.vegeB2);
BindableLayout.SetItemsSource(MyStackLayout, list);
}
private void Button_Clicked_C(object sender, EventArgs e)
{
List<object> list = new List<object>();
list.Add(viewModel.fruitA);
list.Add(viewModel.vegeB1);
list.Add(viewModel.vegeB2);
BindableLayout.SetItemsSource(MyStackLayout, list);
}
}
After running , the effect as follow :

You can refer the following updated code snippet to achieve your requirement “Based on the button click I have to show respective datagrid”.
Code snippet:
<StackLayout>
<Button x:Name="A" Text="A" Clicked="A_Clicked" />
<Button x:Name="B1" Text="B1" Clicked="B1_Clicked" />
<Button x:Name="B2" Text="B2" Clicked="B2_Clicked" />
<sfgrid:SfDataGrid x:Name="fruitA" IsVisible="False" ItemsSource="{Binding fruitA}"/>
<sfgrid:SfDataGrid x:Name="vegeB1" IsVisible="False" ItemsSource="{Binding vegeB1}"/>
<sfgrid:SfDataGrid x:Name="vegeB2" IsVisible="False" ItemsSource="{Binding vegeB2}"/>
</StackLayout>
private void A_Clicked(object sender, EventArgs e)
{
//// Displays only fruit datagrid.
fruitA.IsVisible = true;
vegeB1.IsVisible = false;
vegeB2.IsVisible = false;
}
private void B1_Clicked(object sender, EventArgs e)
{
//// Displays only vegeB1 datagrid.
fruitA.IsVisible = false;
vegeB1.IsVisible = true;
vegeB2.IsVisible = false;
}
private void B2_Clicked(object sender, EventArgs e)
{
//// Displays only vegeB2 datagrid.
fruitA.IsVisible = false;
vegeB1.IsVisible = false;
vegeB2.IsVisible = true;
}
Sample link
Regards,
Pradeep Kumar

Related

Change Background Color of ListView Selected Item in Xamarin

I created a Master-Detail type project in Xamarin. When I selected an item from the Master page the background color is orange by default. How can I change this to a color of my choosing?
You can bind BackgroundColor for ContentView of ViewCell , then use ViewModel and ItemTapped method of ListView to modify the selected item background color .
For example , the xaml code as follow:
<ListView x:Name="ListViewMenu"
HasUnevenRows="True" ItemTapped="ListViewMenu_ItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<Grid Padding="10"
BackgroundColor="{Binding SelectedBackgroundColor}">
<Label Text="{Binding Title}" d:Text="{Binding .}" FontSize="20"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Then in HomeMenuItem model add SelectedBackgroundColor property :
public enum MenuItemType
{
Browse,
About
}
public class HomeMenuItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public MenuItemType Id { get; set; }
public string Title { get; set; }
private Color selectedBackgroundColor;
public Color SelectedBackgroundColor
{
set
{
if (selectedBackgroundColor != value)
{
selectedBackgroundColor = value;
OnPropertyChanged("SelectedBackgroundColor");
}
}
get
{
return selectedBackgroundColor;
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Then in MenuPage modify ItemSource as follow:
public partial class MenuPage : ContentPage
{
MainPage RootPage { get => Application.Current.MainPage as MainPage; }
List<HomeMenuItem> menuItems;
List<HomeMenuItem> tmpItems; // add a tmp list to remove setted backgroud color
public MenuPage()
{
InitializeComponent();
tmpItems = new List<HomeMenuItem>();
menuItems = new List<HomeMenuItem>
{
new HomeMenuItem {Id = MenuItemType.Browse, Title="Browse" },
new HomeMenuItem {Id = MenuItemType.About, Title="About" }
};
menuItems[0].SelectedBackgroundColor = Color.Red; // default set the first item be selected, you can modify as your wants
tmpItems.Add(menuItems[0]); // add the selected item (default is the first)
ListViewMenu.ItemsSource = menuItems;
ListViewMenu.SelectedItem = menuItems[0];
ListViewMenu.ItemSelected += async (sender, e) =>
{
if (e.SelectedItem == null)
return;
var id = (int)((HomeMenuItem)e.SelectedItem).Id;
await RootPage.NavigateFromMenu(id);
};
}
private void ListViewMenu_ItemTapped(object sender, ItemTappedEventArgs e)
{
menuItems[e.ItemIndex].SelectedBackgroundColor = Color.Red;
tmpItems[0].SelectedBackgroundColor = Color.Transparent;
tmpItems[0] = menuItems[e.ItemIndex];
}
}
The effect :
This problem is specific to Android. In the Android project add this line to Resources\values\styles.xml inside the <style> tag:
<item name="android:colorActivatedHighlight">#00FFFFFF</item>

How to implement checkbox in listview xamarin form

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

Xamarin Forms : Access list data when click of a Button inside listview-viewcell

I have a button inside listview-viewcell. For the button, I am using clicked event. So on click of the button, I need the details of the selected list item like the first name, email etc. I tried like following:
Xaml code:
<ListView x:Name="MyDirectories"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Button
BorderRadius="25"
HeightRequest="40"
WidthRequest="150"
TextColor="White"
HorizontalOptions="CenterAndExpand"
Font="Bold,15"
Margin="0,0,0,5"
BackgroundColor="#004F7E"
Clicked="MoreDetails"
Text="More Details"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Xaml.cs code:
public class MyListItemEventArgs : EventArgs
{
public UserProfileTO MyItem { get; set; }
public MyListItemEventArgs(UserProfileTO item)
{
this.MyItem = item;
}
}
public void MoreDetails(Object sender, MyListItemEventArgs args)
{
var item = args.MyItem;
if (item != null)
{
Debug.WriteLine("Firstname:>"+item.firstName);
}
}
When I run getting InvalidCastException: Specified cast is not valid.
Anybody, please suggest any other solution.
Thanks in advance.
The problem was with the model class given in MyListEventArgs:
public class MyListItemEventArgs : EventArgs
{
public UserProfileHBList MyItem { get; set; }
public MyListItemEventArgs(UserProfileHBList item)
{
this.MyItem = item;
}
}
public void MoreDetails(Object sender, MyListItemEventArgs args)
{
var item = args.MyItem;
if (item != null)
{
Debug.WriteLine("Firstname:>" + item.userProfileTO.firstName);
}
}
The firstname, email etc are another json(userProfileTO) inside of the main json(UserProfileHBList). Also forget to add stacklayout, thank you Alessandro Caliaro.

Xamarin ListView Grouping results in blackscreen

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
}

program blows up on navigate using observable collections WP7

In maine, on my button click event handler I do:
private void addIconButton_Click(object sender, EventArgs e)
{
if (test)
{
MessageBox.Show("enters addIcon Main");
Note note = new Note();
note.Modified = DateTimeOffset.Now;
if (note != null)
{
Settings.NotesList.Add(note); //this causes the issue.
//Settings.NotesList[0] = note;
}
Settings.CurrentNoteIndex = 0;
test = false;
MessageBox.Show("right before navigate");
this.NavigationService.Navigate(new Uri("/DetailsPage.XAML", UriKind.Relative));
MessageBox.Show("after navigate");
}
//DetailsPage mynewPage = new DetailsPage();
//this.Content = mynewPage;
}
and on my on navigatedTo I do:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
MessageBox.Show("enters onNav Main");
DataContext = null;
DataContext = Settings.NotesList;
Settings.CurrentNoteIndex = -1;
Listbox.SelectedIndex = -1;
if (Settings.NotesList != null)
{
if (Settings.NotesList.Count == 0)
{
Notes.Text = "No Notes";
}
else
{
Notes.Text = "";
}
}
}
Inside my front end code I do:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox x:Name="Listbox" SelectionChanged="listbox_SelectionChanged" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border Width="800" MinHeight="60">
<StackPanel>
<TextBlock x:Name="Title" VerticalAlignment="Center" FontSize="{Binding TextSize}" Text="{Binding Name}"/>
<TextBlock x:Name="Date" VerticalAlignment="Center" FontSize="{Binding TextSize}" Text="{Binding Modified,
Mode=TwoWay, Converter={StaticResource dateConverter}}"/>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
I have an observable collections in a static class where in the constructor I set it to:
public static class Settings
{
public static ObservableCollection<Note> NotesList;
static IsolatedStorageSettings settings;
private static int currentNoteIndex;
static Settings()
{
NotesList = new ObservableCollection<Note>();
settings = IsolatedStorageSettings.ApplicationSettings;
MessageBox.Show("enters constructor settings");
}
and then inside the Notes class it just looks like this:
public class Note
{
public DateTimeOffset Modified { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int TextSize { get; set; }
}
when I click the app button and it calls the invent handler right after the navigationService is called I get:
// Code to execute on Unhandled Exceptions
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
// An unhandled exception has occurred; break into the debugger
System.Diagnostics.Debugger.Break();
}
}
this only happens when Settings.NotesList.Add(note); is added in the addIconButton_click method..
Any suggestions???
I fixed it by setting default values to the instance variables in the Notes class inside the constructor...

Resources