Binding image in listview - c#

I am relatively new to xamarin, and I am currently trying to bind images to my listview, but no matter what I try, I can't seem to get them to display.
Here is my code:
Xaml:
<ListView x:Name="memDisplayGrid" BackgroundColor="Transparent" HeightRequest="575" WidthRequest="200" ItemsSource="{Binding Members}"
RelativeLayout.XConstraint="{ConstraintExpression Type=RelativeToParent, Property=X, Factor=1, Constant=40}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Y, Factor=1, Constant=330}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image x:Name="memAVI" Grid.Column="0" Source="{x:Binding AviSource}" Aspect="AspectFill"/>
<Label Grid.Column="1" Text="{x:Binding name}" FontAttributes="Bold" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code behind:
private void InitializeMembersBlank()
{
Members = new List<Member>();
for (int i = 0; i < App.UserDB.GetSpecificUser((int)App.Current.Properties["currentUser"]).MemeberNum; i++)
{
Members.Add(new Member
{
AviSource = new Image { Source = "defaultAVI_48x48.jpg" },
systemID = i,
name = "Member " + (i + 1)
}) ;
}
}
Member.cs:
public class Member
{
public string name { get; set; }
public string pro_noun { get; set; }
public string birthday { get; set; }
public string role { get; set; }
public int systemID { get; set; } // how is this being set???
public string description { get; set; }
public Image AviSource { get; set; }
public override string ToString()
{
return "" + name + " /" + pro_noun + " /" + role + " /" + systemID;
}
}
Please note that I have tried changing AviSource to ImageSource and a String, but neither was working for me. I can get other things to display but not the image.
Any suggestions?
Thanks

try like this example
<ListView ItemsSource="{Binding Monkeys}"
HasUnevenRows="true"
ItemSelected="OnListViewItemSelected"
ItemTapped="OnListViewItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
VerticalOptions="End" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
or you can use xamarin.forms listview image cells
TableView tableView = new TableView
{
Intent = TableIntent.Form,
Root = new TableRoot
{
new TableSection
{
new ImageCell
{
// Some differences with loading images in initial release.
ImageSource =
Device.OnPlatform(ImageSource.FromUri(new Uri("http://xamarin.com/images/index/ide-xamarin-studio.png")),
ImageSource.FromFile("ide_xamarin_studio.png"),
ImageSource.FromFile("Images/ide-xamarin-studio.png")),
Text = "This is an ImageCell",
Detail = "This is some detail text",
}
}
}
};
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/listview/customizing-cell-appearance#imagecell[enter link description here]1
and I found same question in here
xamarin form listview image binding

Related

Xamarin Forms Could Not Find DataContext

I am trying to bind properties of views in the view page to a class that I have in a carpet called ViewModel, and then from an instance of another class called Category (a model) in a carpet called Model I am trying to access to properties contained there, the problem is that it does not seem to work .Although there are no error codes in the codes, I cannot access the bindings when I run the application. The warning I get is:
Datacontext not found for binding SelectedCategory .CategoryName(I get the same warning in ProductItemByCategory binding)
Do you have any solution suggestions?
Thank You!!
I will explain it with more details in the code:
1.CategoryView.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pancake="clr-namespace:Xamarin.Forms.PancakeView;assembly=Xamarin.Forms.PancakeView"
x:Class="DirencNetClone.Views.CategoryView">
<ContentPage.Content>
<ScrollView>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="1" Text="{Binding SelectedCategory.CategoryName}" FontSize="Body" Margin="25,-85,0,0" TextColor="Black" />
<ImageButton Source="logo.png" Grid.Row="0" HorizontalOptions="Start" Aspect="AspectFill" VerticalOptions="Start" Margin="10,30" Clicked="ImageButton_Clicked"/>
<pancake:PancakeView Grid.Row="2" BackgroundColor="Wheat" Margin="0,40">
<Grid Padding="25,30" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="{Binding TotalProductItems,StringFormat= '{0} Total Items'}" FontAttributes="Bold" FontSize="10" TextColor="Black"/>
<Image Grid.Row="0" Grid.Column="1" Source="info.png"/>
<CollectionView ItemsSource="{Binding ProductItemsByCategory}"
VerticalOptions="Start"
VerticalScrollBarVisibility="Never"
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
SelectionMode="Single"
SelectionChanged="CollectionView_SelectionChanged">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame HasShadow="False" BackgroundColor="White" HeightRequest="90" Margin="0,10">
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<pancake:PancakeView Grid.Column="0" Grid.Row="0" Grid.RowSpan="3" Margin="0,0,10,0 " >
<Image Source="{Binding ImageUrl}" HeightRequest="100" WidthRequest="95" Aspect="AspectFill"/>
</pancake:PancakeView>
<Label Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding Name}" FontSize="15" TextColor="Black"/>
<Label Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding Description}" FontSize="15" TextColor="Black"/>
<Label Grid.Row="2 " Grid.Column="1" Margin="30,0,0,0" VerticalOptions="Center" FontSize="15" >
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding Rating}" FontAttributes="Bold" />
<Span Text="{Binding RatingDetail} " TextColor="Yellow"/>
</FormattedString>
</Label.FormattedText>
</Label>
<Image Grid.Row="0" Grid.Column="2" Source="{Binding HomeSelected}" HeightRequest="15"/>
<Label Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Text="{Binding Price}" FontSize="15" TextColor="Black"/>
</Grid>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</pancake:PancakeView>
</Grid>
</ScrollView>
</ContentPage.Content>
2.CategoryViewModel.cs
public class CategoryViewModel:BaseViewModel
{
private Category _SelectedCategory;
public Category SelectedCategory
{
set
{
_SelectedCategory = value;
OnPropertyChanged();
}
get
{
return _SelectedCategory;
}
}
public ObservableCollection<ProductItem> ProductItemsByCategory { get; set; }
private int _TotalProductItems;
public int TotalProductItems
{
set
{
this._TotalProductItems = value;
OnPropertyChanged();
}
get
{
return this._TotalProductItems;
}
}
public CategoryViewModel( Category category)
{
SelectedCategory = category;
ProductItemsByCategory = new ObservableCollection<ProductItem>();
GetProductItems(category.CategoryID);
}
async void GetProductItems(int categoryID)
{
var data = await new ProductItemService().GetProductItemsByCategoryAsync(categoryID);
ProductItemsByCategory.Clear();
foreach (var item in data)
{
ProductItemsByCategory.Add(item);
}
TotalProductItems = ProductItemsByCategory.Count;
}
}
3.Category.cs(Model)
public class Category
{
public int CategoryID { get; set; }
public string ImageUrl { get; set; }
public string CategoryName { get; set; }
}
4.CategoryView.cs
public partial class CategoryView : ContentPage
{
CategoryViewModel cvm;
public CategoryView(Category category )
{
InitializeComponent();
cvm = new CategoryViewModel(category);
this.BindingContext=cvm
;
}
async void ImageButton_Clicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
async void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedProduct = e.CurrentSelection.FirstOrDefault() as ProductItem;
if (selectedProduct == null)
return;
await Navigation.PushModalAsync(new ProductsDetailsView(selectedProduct));
((CollectionView)sender).SelectedItem = null;
}
}
5.BaseViewModel
public class BaseViewModel: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string name = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
6.ProductItem(Model)
public class ProductItem
{
public int ProductID { get; set; }
public int CategoryID { get; set; }
public string Rating { get; set;
}
public string Description { get; set;
}
public string RatingDetail { get; set; }
public string HomeSelected { get; set; }
public string ImageUrl { get; set; }
public string Name { get; set; }
public double Price { get; set; }
}
7.ProductView.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="DirencNetClone.Views.ProductsView"
xmlns:vm="clr-namespace:DirencNetClone.ViewModels"
xmlns:pancake ="clr-namespace:Xamarin.Forms.PancakeView;assembly=Xamarin.Forms.PancakeView"
>
<ContentPage.BindingContext>
<vm:ProductsViewModel/>
</ContentPage.BindingContext>
<ContentPage.Content>
<Grid Margin="20,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Source="logo.png " Grid.Row="0" Grid.Column="0" HorizontalOptions="Center"/>
<Label Text="{Binding UserEmail} " Grid.Row="1" Grid.Column="0" FontSize="Body"/>
<ImageButton Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" Source="ic_menu_categories.png" Margin="0,0,10,0" HorizontalOptions="End"/>
<Label Text="{Binding UserCartItemsCount}" FontSize="Subtitle" Grid.Row="0" Grid.Column="2" Grid.RowSpan="2" HorizontalTextAlignment="End" VerticalTextAlignment="Start"/>
<ImageButton Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" Source="ic_menu_basket.png" Margin="0,0,10,0" HorizontalOptions="Center"
Command="{Binding ViewCartCommand } "/>
<ImageButton Grid.Row="0" Grid.Column="3" Grid.RowSpan="2" Source="ic_menu_profile.png" Margin="0,0,10,0" HorizontalOptions="End" Command="{Binding LogoutCommand}"/>
</Grid>
<Grid Grid.Row="1" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<SearchBar Grid.Column="0" Placeholder="Ürün Ara" BackgroundColor="Transparent" HorizontalOptions="Fill"/>
</Grid>
<CollectionView ItemsSource="{Binding Categories} "
Margin="0,20"
HeightRequest="125"
VerticalOptions="FillAndExpand"
HorizontalScrollBarVisibility="Never"
ItemsLayout="HorizontalList"
SelectionChanged="CollectionView_SelectionChanged"
SelectionMode="Single"
Grid.Row="2">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame HeightRequest="50" HasShadow="False" BackgroundColor="White" CornerRadius="10">
<Image Source="{Binding ImageUrl}"/>
</Frame>
<Label Text="{Binding CategoryName} " HorizontalTextAlignment="Center"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Label Grid.Row="3" Text="Latest Items" FontSize="25" FontAttributes="Bold"/>
<CollectionView ItemsSource="{Binding LatestItems}" Margin="0,20,10,0" VerticalOptions="Start" VerticalScrollBarVisibility="Never" Grid.Row="4">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto "/>
</Grid.RowDefinitions>
<pancake:PancakeView Grid.Row="0" Margin="0,0,10,0">
<Image Source="{Binding ImageUrl}" HeightRequest="220" Aspect="Fill"/>
</pancake:PancakeView>
<Frame Grid.Row="1" Margin="20,-80,20,70" BackgroundColor="Wheat" HorizontalOptions="End">
<Label Text="{Binding Price,StringFormat='{0:c}'}" FontSize="Medium" FontAttributes="Bold" TextColor="Black" HeightRequest="10"/>
</Frame>
<Label Grid.Row="1" Text="{Binding Name}" FontSize=" 22" FontAttributes="Bold" VerticalTextAlignment="Center" />
<Label Grid.Row="2" Margin="30,0,0,0" FontSize="15" VerticalOptions="Center" >
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding Rating}" FontAttributes="Bold"/>
<Span Text="{Binding Description}" TextColor="White"/>
</FormattedString>
</Label.FormattedText>
</Label>
</Grid>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</ContentPage.Content>
**8.ProductViewModel**
public class ProductsViewModel :BaseViewModel
{
private string _UserEMail;
public string UserEmail
{
set
{
this._UserEMail = value;
OnPropertyChanged();
}
get
{
return this._UserEMail;
}
}
public ObservableCollection<Category> Categories { get; set; }
public ObservableCollection<ProductItem> LatestItems { get; set; }
private int _UserCartItemsCount;
public int UserCartItemsCount
{
set
{
this._UserCartItemsCount = value;
OnPropertyChanged();
}
get
{
return this._UserCartItemsCount;
}
}
public Command ViewCartCommand { get; set; }
public Command LogoutCommand
{
get; set;
}
public ProductsViewModel()
{
var uemail = Preferences.Get("UserEmail", String.Empty);
if (String.IsNullOrEmpty(uemail))
UserEmail = "Guest";
else
UserEmail = uemail;
UserCartItemsCount = new CartItemService().GetUserCartCount();
Categories = new ObservableCollection<Category>();
LatestItems = new ObservableCollection<ProductItem>();
GetCategories();
GetLatestItems();
ViewCartCommand = new Command(async () => ViewCartAsync());
LogoutCommand = new Command(async () => await LogoutAsync());
}
async void GetLatestItems()
{
var data = await new ProductItemService().GetLatestProductItemsAsync();
LatestItems.Clear();
foreach(var item in data)
{
LatestItems.Add(item);
}
}
private async Task LogoutAsync()
{
await Application.Current.MainPage.Navigation.PushModalAsync(new LogoutVew());
}
private async void GetCategories()
{
var data = await new CategoryDataService().GetCategoriesAsync();
Categories.Clear();
foreach (var item in data)
{
Categories.Add(item);
}
}
private async Task ViewCartAsync()
{
await Application.Current.MainPage.Navigation.PushModalAsync(new CartView());
}

CollectionView, DataBinding, MVVM

Hi everyone,
I am trying to implement MVVM in my application but i am failing to load data.
I have a main page and it works fine, but once I want to navigate to the detail of my Ad and then the detail page is blank. There are my controls so i know that the pages is loaded just my data are missing. I cant seem to figure out where i have made the mistake. I am new to coding so i sometimes tend to make very silly mistakes. I been trying to solve this for past few hours otherwise would not post it over here. Thank you of any opinion.
My HomePage
<Grid Grid.Row="1" Margin="0,25,0,0">
<CollectionView x:Name="ads"
ItemsSource="{Binding AdLogEntries}"
ItemTemplate="{StaticResource HomePageTemplate}"
SelectionMode="Single"
SelectedItem="{Binding SelectedAd, Mode=TwoWay}"
SelectionChanged="CollectionView_SelectionChanged"
Margin="12,0">
</CollectionView>
</Grid>
public partial class HomePage : ContentPage
{
public HomePage()
{
InitializeComponent();
BindingContext = new HomePage ViewModel();
}
async void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedAd = (AdLogEntry)e.CurrentSelection.FirstOrDefault();
if (selectedAd != null)
{
await Navigation.PushAsync(new AdDetail(selectedAd));
}
}
}
namespace Baltazar.ViewModel
{
public class HomePageViewModel : BaseViewModel
{
ObservableCollection<AdLogEntry> _adLogEntries;
public ObservableCollection<AdLogEntry> AdLogEntries { get => _adLogEntries; set { _adLogEntries = value; OnPropertyChanged(); } }
public AdLogEntry selectedAd;
public HomePageViewModel()
{
AdLogEntries = new ObservableCollection<AdLogEntry>()
{
new AdLogEntry (){Id = 0, Image = "cat.jpg", Name = "Kocka" , Description = "seda kocka na prodej, mayliva, hrava, spolecenska " ,Price = 120, },
new AdLogEntry (){Id = 1, Image = "cat2.jpg", Name = "Kocka", Description = "seda kocka na prodej, mayliva, hrava, spolecenska " ,Price = 120, },
new AdLogEntry (){Id = 2, Image = "bobtailjpg.jpg", Name = "Kocka",Description = "seda kocka na prodej, mayliva, hrava, spolecenska ", Price = 120, },
};
}
}
}
//Detail
public class AdDetailViewModel : BaseViewModel
{
AdLogEntry _adDetail;
public AdLogEntry AdDetail { get => _adDetail;set { _adDetail = value;OnPropertyChanged(); } }
public AdDetailViewModel(AdLogEntry adDetail)
{
AdDetail = adDetail;
}
}
public partial class AdDetail : ContentPage
{
//private AdLogEntry selectedAd;
public AdDetail(AdLogEntry adDetail)
{
InitializeComponent();
BindingContext = new AdDetailViewModel(adDetail);
}
}
//BaseViewModel
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected BaseViewModel()
{
}
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="300" />
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ffimageloading:CachedImage
x:Name="HeaderView"
Grid.Row="0"
Grid.RowSpan="2"
Aspect="AspectFill"
Source="{Binding AdLogEntries.Image}"/>
<controls:Parallax Control
x:Name="Parallax"
Grid.Row="0"
Grid.RowSpan="3">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="300" />
<RowDefinition />
</Grid.RowDefinitions>
<yummy:Pancake View
Grid.Row="1"
CornerRadius="24, 24, 0, 0"
BackgroundColor="{StaticResource BackgroundColor}"
Margin="0, 20, 0, 0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Animal NAME -->
<Label
Grid.Row="0"
Text="{Binding AdLogEntries.Name}"
/>
<!-- QUANTITY -->
<Grid
Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label
Grid.Column="1"
Text="{Binding AdLogEntries.Price, StringFormat='{0:C0}'}"
/>
</Grid>
<!-- ABOUT -->
<Label
Grid.Row="2"
Text="Popis"
/>
<!-- DESCRIPTION -->
<Label
Grid.Row="3"
Text="{Binding AdLogEntries.Description}"
/>
<Grid
Grid.Row="4"
Margin="0, 12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- BUY NOW BUTTON -->
<yummy:PancakeView
Grid.Column="1"
HeightRequest="48"
CornerRadius="24, 0, 24, 0"
Background Color="Accent"
Margin="24, 0, 0, 0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label
Grid.Column="1"
Text="Buy now"
/>
<Label
Grid.Column="2"
Text=">"
/>
</Grid>
</yummy:Pancake View>
</Grid>
</Grid>
</yummy:Pancake View>
</Grid>
</controls:Parallax Control>
</Grid>
</ContentPage.Content>
Your SelectedItem never changes because you are not trigger OnPropertyChange. You can change your view model logic like this:
private AdLogEntry selectedAd;
public AdLogEntry SelectedAd { get => selectedAd; set { selectedAd = value; OnPropertyChanged("SelectedAd"); } }
public ICommand AdSelectionChangedCommand => new Command(AdSelectionChanged);
private void AdSelectionChanged()
{
OnPropertyChanged("SelectedAd");
Application.Current.MainPage.Navigation.PushModalAsync(new DetailPage(SelectedAd));
}
And in your XAML:
<CollectionView x:Name="ads"
ItemsSource="{Binding AdLogEntries}"
SelectionMode="Single"
SelectionChangedCommand="{Binding AdSelectionChangedCommand}"
SelectedItem="{Binding SelectedAd, Mode=TwoWay}"
Margin="12,0">
Your detail page:
public DetailPage(AdLogEntry detail)
{
this.BindingContext = new AdDetailViewModel(adDetail);
InitializeComponent();
}
In Detail XAML:
<Label Text="{Binding AdDetail.Name}"/>
your BindingContext is AdDetailViewModel
BindingContext = new AdDetailViewModel(adDetail);
and your binding paths are like
<Label Grid.Row="3" Text="{Binding AdLogEntries.Description}"
AdDetailViewModel does not have a AdLogEntries property. It does have a AdDetail, so presumably you should use this as a binding path
<Label Grid.Row="3" Text="{Binding AdDetail.Description}"
The problem is in your detail page XAML. To be precise, the problem is in your XAML Binding Expressions. All the bindings in the detail page has wrong path set. For example, for image control it should be Source="{Binding AdDetail.Image}" instead of Source="{Binding AdLogEntries.Image}". It happens all the time and you catch these kind of errors in the output log when you debug the application.

How to databind a class object to a ViewCell?

I need to databind a class object to a custom ViewCell. I used the {Binding propName} for the fields on the controls inside the ViewCell. I'm not sure if I am adding the ViewCell correctly since it shows as [AppName.GridView] and does not show the control I built. What is the correct way to bind this control with the custom class?
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Height="50">
<Frame HeightRequest="50" Padding="0" Margin="1" BorderColor="blue" CornerRadius="4" BackgroundColor="lightBlue">
<Grid BindingContext="Binding local:di" >
<Grid.RowDefinitions >
<RowDefinition Height="34"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" BackgroundColor="Transparent" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3"/>
<ColumnDefinition Width="10*" />
<ColumnDefinition Width="5*" />
<ColumnDefinition Width="5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions >
<RowDefinition Height="40"></RowDefinition>
</Grid.RowDefinitions>
<Button x:Name="btnItem" Text="{Binding itemName}" Clicked="BtnClicked" Padding="0" Grid.Column="1" FontSize="20" />
<Label x:Name="lbAmt" Text="{Binding amt}" Grid.Column="2" Margin="2" VerticalTextAlignment="Center" HorizontalTextAlignment="End" FontSize="20" BackgroundColor="lightBlue" />
<Label x:Name="lbType" Text="{Binding amtType}" Grid.Column="3" Margin="2" VerticalTextAlignment="Center" FontSize="20" BackgroundColor="lightBlue" />
</Grid>
...
</Grid>
</Frame>
The code to add the object.
DItem di = new DItem() { itemName = "someName", amt = 1, amtType = xf };
GridItems gi = new GridItems() { di = di };
ObservableCollection<GridItems> lv = new ObservableCollection<GridItems>();
lv.Add(gi);
lvItems.ItemsSource = lv;
If you want to achieve the databinding with listview(MVVM),
Here is running screenshot.
First of all, you can create a model DItem.I achieve the INotifyPropertyChanged interface, layout will changed when the value was changed
public class DItem: INotifyPropertyChanged
{
string _itemName;
public string itemName
{
set
{
if (_itemName != value)
{
_itemName = value;
OnPropertyChanged("itemName");
}
}
get
{
return _itemName;
}
}
int _amt;
public int amt
{
set
{
if (_amt != value)
{
_amt = value;
OnPropertyChanged("amt");
}
}
get
{
return _amt;
}
}
string _amtType;
public string amtType
{
set
{
if (_amtType != value)
{
_amtType = value;
OnPropertyChanged("amtType");
}
}
get
{
return _amtType;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Then, achieve the ModelView.DItemViewModel, We do not need create GridItems just add the DItem to the ObservableCollection<DItem>
public class DItemViewModel
{
public ObservableCollection<DItem> lv { get; set; }
public DItemViewModel()
{
DItem di = new DItem() { itemName = "someName", amt = 1, amtType = "xf" };
lv = new ObservableCollection<DItem>();
lv.Add(di);
}
}
Here is layout of listview. add the ItemsSource="{Binding lv}" for listview.
<ListView ItemsSource="{Binding lv}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame HeightRequest="50" Padding="0" Margin="1" BorderColor="blue" CornerRadius="4" BackgroundColor="lightBlue">
<Grid >
<Grid.RowDefinitions >
<RowDefinition Height="34"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" BackgroundColor="Transparent" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3"/>
<ColumnDefinition Width="10*" />
<ColumnDefinition Width="5*" />
<ColumnDefinition Width="5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions >
<RowDefinition Height="40"></RowDefinition>
</Grid.RowDefinitions>
<Button x:Name="btnItem" Text="{Binding itemName}" Clicked="btnItem_Clicked" Padding="0" Grid.Column="1" FontSize="20" />
<Label x:Name="lbAmt" Text="{Binding amt}" Grid.Column="2" Margin="2" VerticalTextAlignment="Center" HorizontalTextAlignment="End" FontSize="20" BackgroundColor="lightBlue" />
<Label x:Name="lbType" Text="{Binding amtType}" Grid.Column="3" Margin="2" VerticalTextAlignment="Center" FontSize="20" BackgroundColor="lightBlue" />
</Grid>
</Grid>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And here is background code for the listview.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new DItemViewModel();
}
private void btnItem_Clicked(object sender, EventArgs e)
{
}
}
Here are helpful articles about MVVM in Xamarin forms.
https://almirvuk.blogspot.com/2017/02/xamarinforms-listview-simple-mvvm.html
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/data-bindings-to-mvvm

Xamarin Forms ListView grouping bind issue

I have been trying to play around Xamarin Forms for a while and then came across to the Listview Grouping. I am not getting done its showing blank list. Please give me help to find where I am going wrong? Thanks in advance
However, My class domain looks like:
public class LineItemTaxDto
{
public int InvoiceLineItemId { get; set; }
public int InvoiceId { get; set; }
public int TaxId { get; set; }
public decimal TaxRate { get; set; }
public decimal TaxAmount { get; set; }
public string TaxName { get; set; }
}
My View Model property look like
public IEnumerable<KeyValuePair<string, ObservableCollection<LineItemTaxDto>>> ReceiptTaxList { get; set; }
My expecting result look like:
My xaml code below
<ListView x:Name="TaxListView"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
ItemsSource="{Binding Invoice.ReceiptTaxList}"
IsGroupingEnabled="true">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Key}" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid RowSpacing="0" ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Label Text="{Binding TaxName}" Grid.Row="0" Grid.Column="0" FontSize="22" FontFamily="{x:Static resources:Fonts.ArialMTFont}" HorizontalOptions="End" HorizontalTextAlignment="End" Margin="0,5,0,5" />
<Label Grid.Row="0" Grid.Column="1" Text="{Binding TaxAmount, Converter={Helpers:CurrencyAmountConverter}}" FontSize="22" FontFamily="{x:Static resources:Fonts.ArialMTFont}" HorizontalOptions="End" Margin="0,5,0,5" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
EDIT
I am set value in view will appear method
Invoice.ReceiptTaxList = Invoice.InvoiceLineItems.Select(x => { return new KeyValuePair<string, ObservableCollection<LineItemTaxDto>>(x.TaxName, x.LineItemTaxes); });
The value was set properly
I have solved this tricky code not using grouping but now its work as expected
My ViewModel Code
var TaxList = Invoice.InvoiceLineItems.Where(x => x.TaxId > 1).GroupBy(y=>y.TaxId > 1).Select(x =>
{
return new KeyValuePair<LineItemTaxDto, ObservableCollection<LineItemTaxDto>>(new LineItemTaxDto()
{
InvoiceLineItemId = x.First().Id,
InvoiceId = x.First().InvoiceId,
TaxId = x.First().TaxId,
TaxRate = x.First().TaxRate,
TaxAmount = x.Sum(a=>a.TaxAmount),
TaxName = taxlabel + " (" + x.First().TaxName + ")"
}, x.First().LineItemTaxes);
});
var taxes = new ObservableCollection<LineItemTaxDto>();
foreach (var tax in TaxList.GroupBy(tax => tax.Key.TaxId).Select(grp => grp.First()))
{
taxes.Add(tax.Key);
foreach (var subtax in tax.Value.Where(x => x.TaxId > 0))
{
taxes.Add(subtax);
}
}
Invoice.ReceiptTaxList = taxes;
My Xaml Code
<ListView
x:Name="TaxListView"
ItemsSource="{Binding Invoice.ReceiptTaxList}"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
SeparatorVisibility="None"
HasUnevenRows="false"
RowHeight="35"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid RowSpacing="0" ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="{Binding TaxName}" FontSize="22" FontFamily="{x:Static resources:Fonts.ArialMTFont}" HorizontalOptions="End" HorizontalTextAlignment="End" Margin="0,5,0,5" />
<Label Grid.Row="0" Grid.Column="1" Text="{Binding TaxAmount, Converter={Helpers:CurrencyAmountConverter}}" FontSize="22" FontFamily="{x:Static resources:Fonts.ArialMTFont}" HorizontalOptions="End" Margin="0,5,0,5" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
You must use a list of list as items source on listview to get it working. I recommend you to create a class with the properties you want to show at header like this:
public class TaxesObservableCollection<T> : ObservableCollection<T> // Think about to implement INotifyPropertyChanged too, I guess it will be usefull
{
public TaxesObservableCollection(IEnumerable<T> collection, string taxGroupName) : base(collection)
{
TaxGroupName = taxGroupName;
}
private bool taxGroupName;
public bool TaxGroupName
{
get { return taxGroupName; }
set { taxGroupName = value; }
}
}
In your view model:
public IEnumerable<TaxesObservableCollection<LineItemTaxDto>> ReceiptTaxList { get; set; }
Your ListView:
(...) // The rest of it as you did
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding TaxGroupName}" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
(...) // The rest of it as you did
And you fill it this way:
Invoice.ReceiptTaxList = Invoice.InvoiceLineItems.Select(x => { return new TaxesObservableCollection<LineItemTaxDto>(x.LineItemTaxes, x.TaxName); }).ToList();
It should works, please let me know if is that what you wanted.

WPF - adding item of different template in listview

When item on my ListView is clicked I want to make another one of different template to appear below it. I have defined templates in Window.Resources and I thought about changing ItemTemplate when item is clicked, adding new item and changing it to default template, but i am using list with my ListView as ItemsSource it showed only one template and only because (for now) both of them are the same in bindings. What should i do?
Code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<TransactionItem> item = new List<TransactionItem>();
item.Add(new TransactionItem() { category="Deska", index="2", name="Topielec"});
List<object> transactions = new List<object>();
transactions.Add(new Transaction() { name = "Maciek", surname = "Chludzinski", begin = "Dzisiaj 20:14", end = "Dzisiaj 21:14", price = "240 zł", remain = "42 minuty", items = item });
obMainListBinding.ItemTemplate = (DataTemplate)this.FindResource("LessClientTemplate");
MessageBox.Show(obMainListBinding.ItemTemplate.DataTemplateKey.ToString());
transactions.Insert(1, new Transaction() { name = "jhadf", surname = "Chludzhadfi", begin = "Dhad:14", end = "Dzisiajah", price = "240 zł", remain = "42 minuty"});
obMainListBinding.ItemTemplate = (DataTemplate)this.FindResource("BasicTransactionTemplate");
obMainListBinding.ItemsSource = transactions;
}
public class Transaction
{
public string name { get; set; }
public string surname { get; set; }
public string begin { get; set; }
public string end { get; set; }
public string remain { get; set; }
public string price { get; set; }
public List<TransactionItem> items { get; set; }
}
public class TransactionItem
{
public string category { get; set; }
public string index { get; set; }
public string name { get;set; }
}
public class LessTransaction
{
public string name { get; set; }
public string surname { get; set; }
public string begin { get; set; }
public string end { get; set; }
public string remain { get; set; }
public string price { get; set; }
}
}
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="SurfManager.MainWindow"
Title="MainWindow" Height="524.5" Width="1078">
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded"/>
</Window.Triggers>
<Window.Resources>
<DataTemplate x:Key="BasicTransactionTemplate">
<Grid MaxHeight="50">
<Grid.RowDefinitions>
<RowDefinition Height="41*"/>
<RowDefinition Height="42*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0*"/>
<ColumnDefinition Width="192*"/>
<ColumnDefinition Width="234*"/>
<ColumnDefinition Width="189*"/>
<ColumnDefinition Width="443*"/>
</Grid.ColumnDefinitions>
<Label Name="Name" Content="{Binding name}" Grid.RowSpan="1" Grid.Column="1" Grid.ColumnSpan="1" />
<Label Name="Surname" Content="{Binding surname}" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="1"/>
<Label Name="Begin" Content="{Binding begin}" Grid.Column="2"/>
<Label Name="End" Content="{Binding end}" Grid.Row="1" Grid.Column="2"/>
<Label Name="Remain" Content="{Binding remain}" Grid.Column="3"/>
<Label Name="Price" Content="{Binding price}" Grid.Row="1" Grid.Column="3"/>
<ListView Name="lvItems" ItemsSource="{Binding items}" Grid.Column="4" Grid.RowSpan="2">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding category}" />
<TextBlock Text=", Nr" />
<TextBlock Text="{Binding index}" />
<TextBlock Text="{Binding name}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
<DataTemplate x:Key="LessClientTemplate">
<Grid MaxHeight="50">
<Grid.RowDefinitions>
<RowDefinition Height="41*"/>
<RowDefinition Height="42*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0*"/>
<ColumnDefinition Width="192*"/>
<ColumnDefinition Width="234*"/>
<ColumnDefinition Width="189*"/>
<ColumnDefinition Width="443*"/>
</Grid.ColumnDefinitions>
<Label Name="Name" Content="{Binding name}" Grid.RowSpan="1" Grid.Column="1" Grid.ColumnSpan="1" />
<Label Name="Surname" Content="{Binding surname}" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="1"/>
<Label Name="Begin" Content="{Binding begin}" Grid.Column="2"/>
<Button Name="End" Content="{Binding end}" Grid.Row="1" Grid.Column="2"/>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<TabControl>
<TabItem Header="Obecne Wypożyczenia" Background="#FFF40AFF" Foreground="Black" BorderBrush="#FF8C8E94" OpacityMask="White">
<Grid Background="#FFE5E5E5">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<ListView Name="obMainListBinding" BorderThickness="0" ItemTemplate="{StaticResource BasicTransactionTemplate}">
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border Background="{TemplateBinding Background}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.Resources>
</ListView>
</Grid>
</TabItem>
<TabItem Header="Baza Klientow">
<Grid Background="#FFE5E5E5">
<ListView BorderThickness="0" >
<ListViewItem Height="66" Background="Red">
<Grid Background="Black" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0*"/>
<ColumnDefinition Width="0*"/>
<ColumnDefinition Width="0*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0*"/>
<RowDefinition Height="0*"/>
<RowDefinition Height="0*"/>
</Grid.RowDefinitions>
</Grid>
</ListViewItem>
</ListView>
</Grid>
</TabItem>
<TabItem Header="TabItem" HorizontalAlignment="Left" Height="35.293" VerticalAlignment="Top" Width="57.32" Margin="-2,-2,0,-13.333">
<Button Content="Button" Height="100" Margin="430,174,430,173"/>
</TabItem>
</TabControl>
You could try to use the ItemTemplateSelector property:
How do I use a ItemTemplateSelector together with a HeaderTemplate in a WPF ListView?
and(or) triggers that change Template:
How to change control template from Style.Triggers
EDIT
To use TemplateSelector you could add some dummy property on your items(or wrap them) that will allow you to discern new item from old.
...
public Int32 Generation
{
get ...
}
public class GenerationTypeSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var transaction = (TransactionItem)item;
if (transaction .Generation == 0)
return Gen0Template;
else
return Gen1Template;
}
}

Categories

Resources