Can`t bind entry and property in two way mode - c#

Try to create simple app that will add items to the list. Have problems with binding entries with properties in ViewModel.
Here is my xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewModels="clr-namespace:MyScoreDemo.ViewModels;assembly=MyScoreDemo"
x:Class="MyScoreDemo.Views.ClubListPage">
<StackLayout
Padding="15"
Spacing="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Text="Name:" Grid.Row="0" Grid.Column="0"/>
<Entry x:Name="EntryName" Text="{Binding Club.Name, Mode=OneWayToSource}" Grid.Row="0" Grid.Column="1"/>
<Label Text="Country:" Grid.Row="1" Grid.Column="0"/>
<Entry x:Name="EntryCountry" Text="{Binding Club.Country, Mode=OneWayToSource}" Grid.Row="1" Grid.Column="1"/>
<Button Text="Add" Command="{Binding AddCommand}" CommandParameter="{x:Reference EntryName}"
Grid.Row="2" Grid.ColumnSpan="2" Grid.Column="0" />
</Grid>
<ListView ItemsSource="{Binding Clubs}"
Margin="5">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding Path=Name}"/>
<Label Text="{Binding Path=Country}" Grid.Column="1"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout.BindingContext>
<viewModels:ClubListViewModel/>
</StackLayout.BindingContext>
</StackLayout>
And ViewModel code:
private Club _club;
public ICommand AddCommand { get; set; }
public ICommand RemoveCommand { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<Club> Clubs { get; set; }
public ClubListViewModel()
{
AddCommand = new Command(AddClub);
RemoveCommand = new Command(RemoveClub);
Clubs = new ObservableCollection<Club>();
}
public Club Club
{
get => _club;
set
{
_club = value;
OnPropertyChanged("Club");
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
//Commands
private void AddClub()
{
}
Set breakpoints in property`s Club set section and try different modes, but it never stops.

All that I need to change is ta add Club = new Club(); in constructor of my ViewModel class.

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

ListView content mixed up when scrolling

I'm trying to List some data from my sql database, but when I scroll (up or down) the list gets mixed up, the data is rigth but in differente position and if I click on the item, it automaticaly changes the value to the rigth one...
This is my Interactions.xaml code
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="OficinaDigitalX.Views.Interactions"
xmlns:local="clr-namespace:OficinaDigitalX">
<ContentPage.BindingContext>
<local:ViewModel.CarInteractions/>
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout>
<ListView ItemsSource="{Binding Path=InteractionsList, Mode=TwoWay}">
<ListView.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Label Text="Fatura" FontSize="Medium" TextColor="Black" FontFamily="Bold" Grid.Column="0" Grid.Row="0" />
<Label Text="Intervenção" FontSize="Medium" TextColor="Black" Grid.Column="1" Grid.Row="0"/>
<Label Text="Total" FontSize="Medium" TextColor="Black" Grid.Column="2" Grid.Row="0"/>
</Grid>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="200"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Grid.Row="0" Text="{Binding Invoice}"
TextColor="#f35e20" FontSize="10"/>
<Label Grid.Column="1" Grid.Row="0" Text="{Binding Article}"
TextColor="#503026" FontSize="10" />
<Label Grid.Column="2" Grid.Row="0" Text="{Binding Total,StringFormat='{0} €'}"
TextColor="#503026" FontSize="10" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
this is my Interactions.xaml.cs code
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Interactions : ContentPage
{
public Interactions (CarInfo car)
{
InitializeComponent();
BindingContext = new CarInteractions(car.VehicleId);
}
public Interactions()
{
}
}
}
CarInteractions(car.VehicleId) returns a list that is shown on the listView
This is my CarInteractions.cs file
public class CarInteractions : ViewModelBase
{
private List<InteractionsInfo> _InteractionsList;
public List<InteractionsInfo> InteractionsList
{
get
{
return _InteractionsList;
}
set
{
_InteractionsList = value;
OnPropertyChanged("InteractionsList");
}
}
public CarInteractions(int id)
{
GetFirstInteractionRow(id);
}
public CarInteractions() { }
public void GetFirstInteractionRow(int id)
{
string command = "(**not important**)";
string requestUriString = $"{MainPage.server}{command}/{id}";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUriString);
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
using (var responseString = new StreamReader(response.GetResponseStream()))
{
InteractionsList = JsonConvert.DeserializeObject<ObservableCollection<InteractionsInfo>>(responseString.ReadToEnd());
}
}
catch (WebException ex)
{
using (StreamReader reader = new StreamReader(ex.Response.GetResponseStream()))
{
}
throw;
}
}
}
I have been facing some issues with XF version 3.5 that was recently released and I would suggest you roll back your XF version to 3.4 for now until these bugs are resolved.
Me as well but just now I updated to the new XF and it worked perfectly.

Binding a list of object to grid

Trying to render a ListView with a grid into it. The grid contains two columns. The first one, with a button. The second one, with a Label.
Model contains two attributes. First one, a List of specific object. Second one, a string.
Finally, the label of the grid inside of listview will be binded to the one random attribute of list of object of the Model.
My best approach is:
<ListView x:Name="intervectionList"
ItemsSource="{Binding .}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="5">
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="1"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="3*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Text="Play" Grid.Row="0" Grid.Column="0" Clicked="OnLogginClicked"/>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding random_attribute}"/>
<BoxView Color="Navy" HeightRequest="1" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
CODE-BEHIND:
public Intervection()
{
InitializeComponent();
var obj= new Model();
this.BindingContext = prueba.List_of_object;
}
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaiseOnPropertyChange([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public ViewModel()
{
_viewmodel = new ViewModel();
}
private ViewModel _viewmodel;
private string _attribute1;
public string Attribute1
{
get { return _attribute1; }
set { _attribute1= value; RaiseOnPropertyChange(); }
}
.............
}
public class Model
{
public List<obj> Intervencion;
public string attribute2;
// Helpers...
}
That is not rendering anything.
I tried successive approaches. Coming from Basic ListView with string, ListView of object,... and so on. The problem is coming from when I insert the grid.
After check Stackoverflow. I found this link Create Grid from Code-Behind, but this is not serving to my purpose because I can´t re-write the view model. (I, even, tried to coded it).
As usual, thanks mates.
I have added the VerticalOptions to the Listview and Grid.
I have created a viewmodel in which I have one property, the list of items.
The viewmodel also implements INotifyPropertyChanged.
You can read about INotifyPropertyChanged here.
The INotifyPropertyChanged interface is used to notify clients,
typically binding clients, that a property value has changed.
XAML :
<ListView ItemsSource="{Binding MyObservableCollection}" VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="5" VerticalOptions="Fill">
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="1"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="3*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Text="Play" Grid.Row="0" Grid.Column="0"/>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding .}"/>
<BoxView Color="Navy" HeightRequest="1" Grid.Row="1"
Grid.Column="0" Grid.ColumnSpan="2"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
ViewModel :
public class ListViewWithGridViewModel : INotifyPropertyChanged
{
private ObservableCollection<string> _myObservableCollection;
public ListViewWithGridViewModel()
{
MyObservableCollection = new ObservableCollection<string>(new List<string> { "abc", "xyz", "pqr", "aaa", "abc", "xyz", "pqr", "aaa", "abc", "xyz", "pqr", "aaa" });
}
public ObservableCollection<string> MyObservableCollection
{
get { return _myObservableCollection; }
set
{
_myObservableCollection = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
XAML.cs :
public partial class ListViewWithGrid : ContentPage
{
public ListViewWithGrid()
{
InitializeComponent();
BindingContext = new ListViewWithGridViewModel();
}
}
Finally I got it. The xaml needed for it is the next one (you can complet all code coming from the code´s question). Posted just in case you all want to use another approach. Proper answer (more elegant) is #Rohit´s answer.
<ContentPage.Resources>
<ResourceDictionary>
<Color x:FactoryMethod="FromHex" x:Key="fondoBlancoPalido">
<x:Arguments>
<x:String>#F2F2F2</x:String>
</x:Arguments>
</Color>
</ResourceDictionary>
</ContentPage.Resources>
<ListView x:Name="listView" ItemsSource="{Binding .}" BackgroundColor="{StaticResource fondoBlancoPalido}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid Padding="5">
<Grid.RowDefinitions>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="60"></RowDefinition>
<RowDefinition Height="10"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="2*"></ColumnDefinition>
<ColumnDefinition Width="3*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Clicked="OnStartClicked" Image="play.png" BackgroundColor="Transparent" HorizontalOptions="Center" Grid.RowSpan="2"/>
<Label Grid.Row="0" Grid.Column="1" Text="Hora de Inicio: " XAlign="Center" YAlign="Center" TextColor="Black" FontAttributes="Bold"/>
<Label Grid.Row="0" Grid.Column="2" Text="{ Binding attribute3 }" XAlign="Center" YAlign="Center" TextColor="Black"/>
<Label Grid.Row="1" Grid.Column="1" Text="Encargado de la Tarea: " XAlign="Center" YAlign="Center" TextColor="Black" FontAttributes="Bold"/>
<Label Grid.Row="1" Grid.Column="2" Text="{ Binding attribute4 }" XAlign="Center" YAlign="Center" TextColor="Black"/>
<BoxView Color="Navy" HeightRequest="2" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3"/>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Categories

Resources