I want to create items in a ListView to be displayed in a View, how do I go about doing this?
Code-Behinds and the other View's ViewModel, are basically empty, except for a Binding Context and a manually created item in the ViewModel for viewing and testing stuff.
I have been trying for a while and this is basically me admitting defeat, I am sorry for literally copy-pasting my code, but I am getting desperate, if you can, please do explain the solution and thank you very much
Model - Item.cs is
{
public string Name { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public int Quantity { get; set; }
public string TypeOfQuantity { get; set; }
}
Xaml for creating items V
<StackLayout BackgroundColor="AliceBlue" Padding="10">
<Button Text="Button"
Command="{Binding ButtonCommand}"
Clicked="Mover_Clicked"/>
<Grid BackgroundColor="Black"
ColumnSpacing="3"
RowSpacing="3"
Padding="3"
HeightRequest="200">
<Entry Placeholder="Enter Name"
BackgroundColor="AliceBlue" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" Text="{Binding NewItem.Name}" />
<Entry Placeholder="Enter Description"
Grid.Column="1" BackgroundColor="AliceBlue" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" Text="{Binding NewItem.Description}"/>
<Entry Placeholder="Enter Quantity"
Grid.Row="1" BackgroundColor="AliceBlue" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" Text="{Binding NewItem.Quantity}"/>
<Entry Placeholder="Enter Type of Quantity"
Grid.Row="1" Grid.Column="1" BackgroundColor="AliceBlue" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" Text="{Binding NewItem.TypeOfQuantity}"/>
</Grid>
</StackLayout>
</ContentPage.Content>
Xaml for Displaying items V
<viewmodels:ViewModelBase/>
</ContentPage.BindingContext>
<ListView
BackgroundColor="Transparent"
ItemsSource="{Binding Items}"
HasUnevenRows="True"
SeparatorVisibility="None">
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:Item">
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Text="Delete" ></MenuItem>
<MenuItem Text="Edit" ></MenuItem>
</ViewCell.ContextActions>
<Grid Padding="20">
<Frame CornerRadius="15">
<StackLayout Orientation="Horizontal">
<Frame BackgroundColor="AliceBlue">
<Image HeightRequest="90"
Source="{Binding Image}"/>
</Frame>
<StackLayout>
<Label
WidthRequest="150"
Text="{Binding Description}"
FontSize="Large"
VerticalTextAlignment="Center"/>
<Label
WidthRequest="150"
Text="{Binding Name}"
FontSize="Large"
VerticalTextAlignment="Center"/>
<Grid HeightRequest="50" WidthRequest=" 170" Padding="10" VerticalOptions="Start">
<Label
Text="{Binding Quantity}"
HorizontalOptions="End"
FontSize="Large"/>
<Label
Text="{Binding TypeOfQuantity}"
FontSize="Large" Grid.Column="1"/>
<Button HeightRequest="25"
WidthRequest="25"
Text="+"
FontSize="Large" Grid.Column="2"
BackgroundColor="OrangeRed"/>
<Button HeightRequest="25"
Text="-"
FontSize="Large" Grid.Column="3"/>
</Grid>
</StackLayout>
</StackLayout>
</Frame>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Header>
<Button x:Name="Mover" Clicked="Mover_Clicked" Text="Add new"></Button>
</ListView.Header>
</ListView>
</ContentPage>
ViewModelBase V
{
public ObservableRangeCollection<Item> Items { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public int Quantity { get; set; }
public string TypeOfQuantity { get; set; }
public Item NewItem { get; set; }
public ViewModelBase()
{
Items = new ObservableRangeCollection<Item>();
}
}
ViewModel for item creation(which inherits ViewModelBase) V
{
public Command ButtonCommand { set; get; }
public ItemEntryPageViewModel()
{
ButtonCommand = new Command(AddItemCommand);
}
private void AddItemCommand(object obj)
{
Items.Add(NewItem);
}
} ```
I have a CollectionView with a few items in it. I'm trying to adjust the size of the CollectionView to be just big enough to fit all of its children. Right now, it's much larger than the amount of children it has.
The Blue color represents the size of the CollectionView. As you can see, it's well beyond the size of it's children. I'd like it to fit them perfectly, or at the very least be closer to the same size.
I don't have any height requests on any of the elements on the page, including the CollectionView.
Here's my code. It's not particularly pretty at the moment, but it's a work in progress.
<StackLayout>
<CollectionView x:Name="assessmentsCollectionView"
BackgroundColor="Blue">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Spacing="10"
Padding="5">
<Frame CornerRadius="5"
Padding="0"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal">
<Frame Padding="5"
CornerRadius="0"
WidthRequest="50">
<Label Text="{Binding TypeLetter}"
TextColor="#37474f"
FontSize="24"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"/>
</Frame>
<StackLayout Padding="10">
<Label Text="{Binding Name}"
TextColor="Black"
FontSize="24"/>
<StackLayout Orientation="Horizontal">
<Image Source="calendarIcon.png"
WidthRequest="12"
HeightRequest="12"/>
<Label Text="{Binding Date}"
FontSize="12"
TextColor="Gray"/>
</StackLayout>
</StackLayout>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
I changed CollectionView to FlexLayout with BindableLayout.ItemsSource and BindableLayout.ItemTemplate
What was previously
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
What was done
<FlexLayout Direction="Column"
x:Name="MessagesList"
AutomationId="MessagesList"
BindableLayout.ItemsSource="{Binding Messages}" >
<BindableLayout.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</BindableLayout.ItemTemplate>
</FlexLayout>
For me works well, no need to set Height for item or FlexLayout, all are dynamic
If you have little rows in Collectionview, you can set a value to collectionView.HeightRequest. when item increase, the height will increase as well.
I create a property called.RowHeigth. If I add item in the CollectionView(with AddCommand), RowHeigth will increase.
<StackLayout>
<CollectionView
x:Name="assessmentsCollectionView"
BackgroundColor="Blue"
HeightRequest="{Binding rowHeigth}"
ItemsSource="{Binding letters}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="5" Spacing="10">
<Frame
Padding="0"
CornerRadius="5"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal">
<Frame
Padding="5"
CornerRadius="0"
WidthRequest="50">
<Label
FontSize="24"
HorizontalTextAlignment="Center"
Text="{Binding TypeLetter}"
TextColor="#37474f"
VerticalTextAlignment="Center" />
</Frame>
<StackLayout Padding="10">
<Label
FontSize="24"
Text="{Binding Name}"
TextColor="Black" />
<StackLayout Orientation="Horizontal">
<Image
HeightRequest="12"
Source="c1.png"
WidthRequest="12" />
<Label
FontSize="12"
Text="{Binding Date}"
TextColor="Gray" />
</StackLayout>
</StackLayout>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Button
x:Name="btn1"
Command="{Binding AddCommand}"
Text="btn1" />
</StackLayout>
public partial class Page4 : ContentPage
{
public Page4()
{
InitializeComponent();
this.BindingContext = new letterviewmodel(); ;
}
}
public class letterviewmodel: INotifyPropertyChanged
{
public ObservableCollection<lettermodel> letters { get; set; }
private int _rowHeigth;
public int rowHeigth
{
get { return _rowHeigth; }
set
{
_rowHeigth = value;
RaisePropertyChanged("rowHeigth");
}
}
public ICommand AddCommand { protected set; get; }
public letterviewmodel()
{
letters = new ObservableCollection<lettermodel>()
{
new lettermodel(){TypeLetter="A",Name="letter 1",Date="2021-01-01"},
new lettermodel(){TypeLetter="B",Name="letter 2",Date="2021-01-01"},
new lettermodel(){TypeLetter="C",Name="letter 3",Date="2021-01-01"}
};
rowHeigth = letters.Count * 100 ;
AddCommand = new Command<lettermodel>(async (key) => {
letters.Add(new lettermodel() { TypeLetter = "D", Name = "test letter ", Date = "2021-01-01" });
rowHeigth = letters.Count * 100 ;
});
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class lettermodel
{
public string TypeLetter { get; set; }
public string Name { get; set; }
public string Date { get; set; }
}
Don't forget toimplement INotifyPropertyChanged interface, to inotify data update.
Im trying to bind my ListView to an observableCollection on my ViewModel. The other bindings on the same class are working but i dont see any data where my list is supposed to be.
Ive tried setting the rows uneven, instantiating a separate Collection, and using breakpoints to confirm there is data.
Here is the xaml code:
<StackLayout Spacing="10" Padding="7" Grid.Row="1" Grid.Column="0">
<Label Text="Name:" FontSize="Medium"/>
<Label Text="{Binding order.Name}" FontSize="Small"/>
<Label Text="Price:" FontSize="Medium"/>
<Label Text="{Binding order.Price}" FontSize="Small"/>
</StackLayout>
<ListView ItemsSource="{Binding order.foodItems}" Grid.Row="0" Grid.Column="0" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10" Orientation="Horizontal" HorizontalOptions="Fill">
<Label Text="{Binding Name}" FontSize="Medium"/>
<Label Text="{Binding Quantity}" FontSize="Medium" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Here is my ViewModel
Order _order;
public Order order
{
get { return _order; }
set { SetProperty<Order>(ref _order, value); }
}
public OrderDetailViewModel(Order value)
{
order = value;
}
The order class:
public class Order
{
public string Name { get; set; }
public ObservableCollection<IFoodItems> foodItems;
public double Price { get; set; }
public Order(string name)
{
Name = name;
foodItems = new ObservableCollection<IFoodItems>();
}
public void SetPrice(double value)
{
Price = value;
}
public void AddItem(IFoodItems food)
{
foodItems.Add(food);
}
}
I am using Xamarin.Forms.I want to remove the selected item in listview after clicking Remove button.
My xaml
<ListView x:Name="ProductsListView"
HasUnevenRows="True"
BackgroundColor="#ecf0f1"
SeparatorVisibility="None"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Margin="6,4,6,4"
BackgroundColor="White">
<StackLayout Orientation="Horizontal">
<Label Text="Item ID" Margin="25,10,4,4" FontSize="Small" TextColor="Black" />
<Label Text="{Binding retail_modified_item_id}" Margin="25,10,4,4" TextColor="Black" FontSize="12" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Name" Margin="25,2,8,4" TextColor="Black" FontSize="Small" />
<Label Text="{Binding name}" Margin="32,1,8,4" TextColor="Black" FontSize="Small" />
<Switch IsToggled="false" Margin="210,2,2,2" Toggled="Switch_Toggled" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="OldPrice" Margin="25,2,8,4" TextColor="Black" FontSize="Small"/>
<Label Text="{Binding old_price}" Margin="32,1,8,4" TextColor="Black" FontSize="Small" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="NewPrice" Margin="25,2,8,4" TextColor="Black" FontSize="Small" />
<Label Text="{Binding new_price}" Margin="32,1,8,4" TextColor="Black" FontSize="Small" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My cs code
private void reject(object sender, EventArgs args)
{
foreach (var v in ProductsListView.SelectedItems)
{
ProductsListView.ItemSelected.Remove(v);
}
DisplayAlert("Rejected","Request Rejected!!", "OK");
}
I am getting this error:
listview does not contain a definition for selecteditem, ItemSelected
You can try cast it to ProductListView,
var selectedItems = (ListView/* or ProductListView*/)sender; //-> you need casting to access it.
And you can change list view item source
public void reject(your_list_of_model_type your_list_of_model)
{
your_list_of_model.RemoveRange(selectedItems);
ProductListView.ItemSource = your_list_of_model;
}
Solution 2 :
Here is what you could do :
This be my model class :
public class Item
{
public string ItemName { get; set; }
public string ItemDetails { get; set; }
}
And in my XAML or you can write this in code as well, bind to the Command Parameter of your Item template :
<Button Text="Delete" CommandParameter="{Binding ItemName}" Clicked="DeleteClicked"></Button>
Full Item Template will be like below :
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding ItemName}" HorizontalOptions="StartAndExpand" FontSize="30"></Label>
<Button Text="Delete" CommandParameter="{Binding ItemName}" Clicked="DeleteClicked">
</Button>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
And in you code file you can do this :
public void DeleteClicked(object sender, EventArgs e)
{
var item = (Xamarin.Forms.Button)sender;
Item listitem = (from itm in allItems
where itm.ItemName == item.CommandParameter.ToString()
select itm)
.FirstOrDefault<Item>();
allItems.Remove(listitem);
}
IMPORTANT : This would only delete the item from the bound collection. To delete it from the original list you need to use ObservableCollection
You can add all the toggled items to a list, suppose selectedItems. And when you click REJECT button, delete the selectedItems from the datasource of listview.
The full code is like this:
MainPage.xaml:
<StackLayout Orientation="Vertical">
<!-- Place new controls here -->
<Button Text="APPROVE"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="REJECT"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="reject"/>
<ListView x:Name="ProductsListView"
HasUnevenRows="True"
BackgroundColor="#ecf0f1"
SeparatorVisibility="None"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" Margin="6,4,6,4"
BackgroundColor="White">
<StackLayout Orientation="Horizontal">
<Label Text="{Binding name}" Margin="32,1,8,4" TextColor="Black" FontSize="Small" />
<Switch IsToggled="false" Margin="210,2,2,2" Toggled="Switch_Toggled" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding retail_modified_item_id}" Margin="25,10,4,4" TextColor="Black" FontSize="12" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="OldPrice" Margin="25,2,8,4" TextColor="Black" FontSize="Small"/>
<Label Text="{Binding old_price}" Margin="32,1,8,4" TextColor="Black" FontSize="Small" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="NewPrice" Margin="25,2,8,4" TextColor="Black" FontSize="Small" />
<Label Text="{Binding new_price}" Margin="32,1,8,4" TextColor="Black" FontSize="Small" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
MainPage.xaml.cs:
public partial class MainPage : ContentPage
{
ObservableCollection<ItemModel> allItems = new ObservableCollection<ItemModel>();
List<ItemModel> selectedItems = new List<ItemModel>();
public MainPage()
{
InitializeComponent();
InitializeData();
ProductsListView.ItemsSource = allItems;
}
private void reject(object sender, EventArgs e)
{
foreach (var v in selectedItems)
{
allItems.Remove(v);
}
DisplayAlert("Rejected", "Request Rejected!!", "OK");
}
private void Switch_Toggled(object sender, ToggledEventArgs e)
{
var switch1 = (Switch)sender;
var item = (ItemModel)switch1.BindingContext;
var isSelected = !item.selected;
if (isSelected)
{
selectedItems.Add(item);
}
else
{
selectedItems.Remove(item);
}
}
private void InitializeData() {
allItems.Add(new ItemModel { name = "Onion Rings, Medium",
retail_modified_item_id = 1000630,
old_price = 1.29,
new_price = 9.45,
selected = false
});
allItems.Add(new ItemModel
{
name = "Hashbrowns",
retail_modified_item_id = 1000739,
old_price = 0.99,
new_price = 8.5,
selected = false
});
allItems.Add(new ItemModel
{
name = "Amstel Light, Single",
retail_modified_item_id = 1002038,
old_price = 3.5,
new_price = 18,
selected = false
});
}
}
ItemModel.cs:
class ItemModel
{
public string name { get; set; }
public int retail_modified_item_id { get; set; }
public double old_price { get; set; }
public double new_price { get; set; }
public bool selected { get; set; }
}
i am trying to pass data from a child page to to a parent class this is the parent
namespace App11
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class OrderedItemsPage : ContentPage
{
public string aSize;
public string size, Main, Milk;
public List<String> sizeList = new List<string>();
public List<String> mainList = new List<string>();
public List<String> milkList = new List<string>();
public ObservableCollection<ElementsViewModel> elements { get; set; }
public void OrderedItemsPageBlank()
{
aSize = "";
Main = "";
Milk = "";
}
public OrderedItemsPage ()
{
InitializeComponent ();
}
public void displayToList()
{
elements = new ObservableCollection<ElementsViewModel>();
for(int i = 0;i< mainList.Count;i++)
{
string Coffee = sizeList[i] + " : " + mainList[i];
elements.Add(new ElementsViewModel
{
Image = "icon.png",
Coffee = Coffee,
Details = "$2.50 each"
});
}
listView.ItemsSource = elements;
}
}
}
and this is the child class...
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App11.OrderedItemsPage">
<ContentPage.Content>
<StackLayout >
<!--Top Section-->
<ListView x:Name="listView" RowHeight="60">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout
Orientation="Horizontal"
HorizontalOptions="Fill">
<Image x:Name="BgImage" Source="{Binding Image}"
AbsoluteLayout.LayoutBounds="250.25, 0.25, 50, 50"/>
<StackLayout Orientation="Vertical">
<Label Text="{Binding Coffee}"
FontSize="24"
AbsoluteLayout.LayoutBounds="0.25, 0.25, 400, 40"
></Label>
<Label Text="{Binding Details}"
AbsoluteLayout.LayoutBounds="50, 50, 200, 25"
></Label>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout Orientation="Horizontal">
<!--Second half-->
<Button
x:Name="AddButton"
Text="Add Drink"
VerticalOptions="EndAndExpand"
HorizontalOptions="CenterAndExpand"
Clicked="addDrinkButtonClick">
</Button>
<Button Text="Add Food"
VerticalOptions="EndAndExpand"
HorizontalOptions="CenterAndExpand">
</Button>
</StackLayout>
<!--third half ( cause thats a thing)-->
<StackLayout Orientation="Vertical">
<Button Text="Process Order"
VerticalOptions="EndAndExpand"
HorizontalOptions="CenterAndExpand"
></Button>
</StackLayout>
</StackLayout>
</ContentPage.Content>
i basically need to receive the data, now when i debug the program the information is passed through perfect but when i populate is into the list view it does not display when i run the app?
any help would be awesome, thanks
This probably is the culprit: elements = new ObservableCollection<ElementsViewModel>();.
Do not new a ObservableCollection every time. This will cause the binding to updating the UI and your changes will not show up. Just instantiate the elements once: public ObservableCollection<ElementsViewModel> elements { get; set; } = new ObservableCollection<ElementsViewModel>(); and clear it every time you need an empty one. Then just add items to it one-by-one.
A helpful package here is the MVVM Helpers by James Montemagno. It has the ObservableRangeCollection, which lets you replace whole ranges and such, saving you some foreaches.