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.
Related
Firstscreen with all the notes.
After I deleted the first note!
I have recently started programming with .NET MAUI. The elements are correctly removed in the C# list. However, after deleting the remaining elements are only partially displayed. That means that only e.g. the 4th element is displayed. For the other elements only an empty bar is displayed.
My code so far:
XAML:
<VerticalStackLayout>
<ScrollView>
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image
Grid.Column="0"
Source="logo.png"
WidthRequest="150"
HorizontalOptions="Start"
VerticalOptions="Start"/>
<Label
TextColor="Black"
Grid.Column="1"
Text="TODO"
FontSize="35"
HorizontalOptions="Start"
VerticalOptions="Start"
Margin="23"/>
</Grid>
<Grid BackgroundColor="#24D4A3">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView
Grid.ColumnSpan="2"
Grid.RowSpan="2"
RowHeight="100"
x:Name="listview">
<ListView.ItemTemplate>
<DataTemplate >
<ViewCell >
<Grid BackgroundColor="#24D4A3">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Button BackgroundColor="#DEABF5"
Text="{Binding Title}"
Clicked="onNoteSelected"
BorderWidth="2"
TextColor="Black"
FontSize="28"
Margin="20"
CornerRadius="100"
WidthRequest="350"
HeightRequest="70"
HorizontalOptions="Center"
VerticalOptions="Start"/>
<Button
BindingContext="{Binding Id}"
Clicked="ToDoSolved"
BorderWidth="2"
BorderColor="Black"
BackgroundColor="White"
WidthRequest="45"
HeightRequest="45"
CornerRadius="35"
Margin="0,0,260,0"
/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ImageButton
Clicked="Settings"
Source="settings.png"
Grid.Row="0"
Grid.Column="2"
BorderColor="#2b3c3c"
BorderWidth="0"
BackgroundColor="#34A4EB"
CornerRadius="35"
HorizontalOptions="End"
WidthRequest="70"
HeightRequest="70"
Margin="0,10, 10, 0"
VerticalOptions="Start"/>
<ImageButton
Clicked="CreateNote"
Source="add.png"
Grid.Row="1"
Grid.Column="2"
BorderColor="#2b3c3c"
BorderWidth="0"
BackgroundColor="#34A4EB"
CornerRadius="35"
HorizontalOptions="End"
WidthRequest="70"
HeightRequest="70"
Margin="0,0,10,10"
Padding="2,0,0,0"/>
</Grid>
</StackLayout>
</ScrollView>
</VerticalStackLayout>
C#:
public partial class MainPage : ContentPage
{
private ObservableCollection<Note> notes = new ObservableCollection<Note>();
public ObservableCollection<Note> Notes
{
get { return notes; }
set { notes = value; }
}
public MainPage()
{
InitializeComponent();
notes.Add(new Note(1, "My Note1", "I'm ugly"));
notes.Add(new Note(2, "My Note2", "I'm short"));
notes.Add(new Note(3, "My Note3", "I'm smart"));
notes.Add(new Note(4, "My Note4", "I'm smart"));
//notes.Add(new Note(6, "My Note6", "I'm smart"));
//notes.Add(new Note(7, "My Note7", "I'm smart"));
//notes.Add(new Note(8, "My Note8", "I'm smart"));
//notes.Add(new Note(9, "My Note9", "I'm smart"));
this.BindingContext= Notes;
listview.ItemsSource= Notes;
}
private async void CreateNote(object sender, EventArgs e)
{
await Shell.Current.GoToAsync("//CreateNote");
}
private async void Settings(object sender, EventArgs e)
{
await Shell.Current.GoToAsync("//Settings");
}
private void ToDoSolved(object sender, EventArgs e)
{
Button button= (Button) sender ;
var id = (int)button.BindingContext;
var item = Notes.SingleOrDefault(x => x.Id == id);
if (item != null)
{
Notes.Remove(item);
Console.WriteLine(id);
}
}
async void onNoteSelected(object sender, EventArgs e)
{
Button button= (Button) sender ;
var id = (int)button.BindingContext;
//await Shell.Current.GoToAsync("NotePage" + id);
}
}
I would be grateful for any help :)
To delete the item, since you are using ListView, you can delete the via
Button click. However, you need to delete the item from bottom to top in order.
Code-behind:
public partial class MainPage : ContentPage
{
public ObservableCollection<Note> Notes { get; private set; } = new ObservableCollection<Note>();
public MainPage()
{
InitializeComponent();
AddNotes();
BindingContext = this;
}
private void AddNotes()
{
Notes.Add(new Note("0", "My Note1"));
Notes.Add(new Note("1", "My Note2"));
Notes.Add(new Note("2", "My Note3"));
Notes.Add(new Note("3", "My Note4"));
}
private void Button_Clicked(object sender, EventArgs e)
{
var note = (Button)sender;
Note listnote = (from itm in Notes
where itm.Id == note.CommandParameter.ToString()
select itm).FirstOrDefault<Note>();
Notes.Remove(listnote);
}
}
Xaml:
<VerticalStackLayout>
<ScrollView>
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image
Grid.Column="0"
Source="logo.png"
WidthRequest="150"
HorizontalOptions="Start"
VerticalOptions="Start"
/>
<Label
TextColor="Black"
Grid.Column="1"
Text="TODO"
FontSize="35"
HorizontalOptions="Start"
VerticalOptions="Start"
Margin="23"
/>
</Grid>
<Grid BackgroundColor="#24D4A3">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListView
Grid.ColumnSpan="2"
Grid.RowSpan="2"
RowHeight="100"
x:Name="listview"
ItemsSource="{Binding Notes}" >
<ListView.ItemTemplate>
<DataTemplate >
<ViewCell>
<Grid BackgroundColor="#24D4A3" >
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Button BackgroundColor="#DEABF5"
Text="{Binding Title}"
BorderWidth="2"
TextColor="Black"
FontSize="28"
Margin="20"
CornerRadius="100"
WidthRequest="350"
HeightRequest="70"
HorizontalOptions="Center"
VerticalOptions="Start"/>
<Button
Text="Delete"
Clicked="Button_Clicked"
CommandParameter="{Binding Id}"
BorderWidth="2"
BorderColor="Black"
BackgroundColor="White"
WidthRequest="45"
HeightRequest="45"
CornerRadius="35"
Margin="0,0,260,0"
/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</StackLayout>
</ScrollView>
</VerticalStackLayout>
Note:
public class Note
{
public string Id { get; set; }
public string Title { get; set; }
public Note(string id, string title)
{
Id = id;
Title = title;
}
}
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());
}
In my application I am adding menu items dynamically.
Is it possible to make items clickable so that it can take me to, for example, "Page2" or "Page3"?
Here is my code in AppShell.xaml.cs
public ObservableCollection<dynamic> FlyoutItems { get; set; }
public AppShell()
{
FlyoutItems = new ObservableCollection<dynamic>()
{
new { MenuTitle="MenuTitle1" },
new { MenuTitle="MenuTitle2" },
new { MenuTitle="MenuTitle3" },
new { MenuTitle="MenuTitle4" }
};
InitializeComponent();
BindingContext = this;
}
AppShell.xaml
<Shell.FlyoutContentTemplate>
<DataTemplate>
<StackLayout>
<ListView x:Name="MenuItemsListView"
SeparatorVisibility="None"
HasUnevenRows="true"
ItemsSource="{Binding FlyoutItems}">
<ListView.Header>
<Grid BackgroundColor="CornflowerBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="10"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="80"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
<Label Grid.Row="2" Grid.Column="1"
TextColor="#d7d9b4"
Text="{Binding Title}"
FontSize="24"/>
</Grid>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="15,10"
HorizontalOptions="FillAndExpand">
<Label VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center"
Text="{Binding Type}"
TextColor="Black"
FontSize="20"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</DataTemplate>
</Shell.FlyoutContentTemplate>
I think I need to create a button but I am not quite sure how to do it.
Hope someone can help.
Thanks!
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
I have read that the Editor control doesn't have a placeholder, so I have been trying to do a workaround without success. I know that the Entry control has a Placeholder, but I need multiline field as I am going to use it as a field where users can write a comment, and not just a single line.
This is my approach:
I have tried to put an Editor and a Label into a Grid control, with the Label being on top of the Editor. The Editor's InputTransparent flag is set to true. Then I just toggle the IsVisible property of the label depending on the whether the Editor has text or not. However, the problem is that I am using the MVVM pattern, so I don't know how to control the TextChanged event in the ViewModel. I have also tried to code behind, but the name of the Label can't be found.
This is my XAML code - Have only posted the relevant code:
<Grid Grid.Row="1">
<Editor Text="{Binding UserComment, Mode=TwoWay}" TextChanged="EditorTextChanged" HorizontalOptions="FillAndExpand"/>
<Label x:Name="PlaceholderLabel" Text="Write a comment" InputTransparent="True" HorizontalOptions="StartAndExpand"/>
</Grid>
For now, in the code-behind, I only have the EditorTextChanged event, which works fine, but it can't find PlaceholderLabel. I have binded the whole View to my ViewModel, is that the reason? How would approach it, if you had to follow the MVVM pattern?
It's worth mentioning that I have tried this approach. However, it didn't work as expected. The Placeholder would only appear when I clicked on the Editor and then unclicked it. It should appear in the beginning as on Facebook.
EDIT
This is the whole XAML code:
<ContentPage.Resources>
<ResourceDictionary>
<local:TeamAlignmentConverter x:Key="teamConverter"/>
<local:ImageAlignmentConverter x:Key="imageConverter"/>
<local:BooleanReverser x:Key="booleanReverser"/>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout VerticalOptions="FillAndExpand" Spacing="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="180"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.BindingContext>
<viewModel:MatchPageVM/>
</Grid.BindingContext>
<Grid BackgroundColor="White" RowSpacing="0" Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="0.5*" />
<RowDefinition Height="2*" />
<RowDefinition Height="0.8*" />
</Grid.RowDefinitions>
<Label Text="{Binding Teams}" FontSize="26" HorizontalOptions="CenterAndExpand" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" VerticalOptions="CenterAndExpand" Grid.Row="0"/>
<Image Source="notificationsbell.png" Margin="25,10,0,0" HorizontalOptions="StartAndExpand" VerticalOptions="CenterAndExpand" Grid.Row="1"/>
<Label Text="{Binding Score}" FontSize="80" HorizontalOptions="CenterAndExpand" HorizontalTextAlignment="Center" VerticalOptions="CenterAndExpand" VerticalTextAlignment="Center" Grid.Row="1"/>
<Label Text="Live" FontSize="24" HorizontalOptions="CenterAndExpand" HorizontalTextAlignment="Center" VerticalOptions="CenterAndExpand" VerticalTextAlignment="Center" Grid.Row="2"/>
</Grid>
</Grid>
<Grid RowSpacing="0" VerticalOptions="FillAndExpand">
<Grid.BindingContext>
<viewModel:MatchPageVM/>
</Grid.BindingContext>
<cv:CarouselView ItemsSource="{Binding CollectionList}">
<cv:CarouselView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<flv:FlowListView x:Name="flowListView" FlowColumnCount="1" Grid.Row="0"
SeparatorVisibility="None" HasUnevenRows="True" IsVisible="{Binding ListSwitch}"
FlowItemsSource="{Binding CollectionList}" BackgroundColor="White" >
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<Grid ColumnSpacing="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.005*"/>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding PlayerName}" Grid.Column="{Binding Team}" VerticalOptions="Center"
HorizontalOptions="FillAndExpand"
HorizontalTextAlignment="{Binding Team, Converter={StaticResource teamConverter}}"/>
<Image Source="{Binding ImageURL}" HorizontalOptions="Center" Grid.Column="{Binding Team, Converter={StaticResource imageConverter}}" Aspect="AspectFill" VerticalOptions="Center"/>
<BoxView BackgroundColor="Black" Grid.Column="2" HeightRequest="20" VerticalOptions="Center"/>
</Grid>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>
<Grid Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="4*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<flv:FlowListView x:Name="flowListView2" FlowColumnCount="1" BackgroundColor="White"
HasUnevenRows="True" HeightRequest="180" IsVisible="{Binding ListSwitch, Converter={StaticResource booleanReverser}}" Grid.Row="0"
FlowItemsSource="{Binding CollectionList}" SeparatorVisibility="Default" SeparatorColor="Black">
<flv:FlowListView.FlowColumnTemplate>
<DataTemplate>
<Grid RowSpacing="5">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2.5*"/>
<ColumnDefinition Width="20*"/>
</Grid.ColumnDefinitions>
<Image Source="{Binding ImageURL}" HorizontalOptions="Start"
Grid.Row="0" Grid.Column="0" Aspect="AspectFit" Margin="0,10,0,0" VerticalOptions="Start"/>
<Label Text="{Binding UserName}" Grid.Row="0" Grid.Column="1" VerticalOptions="Start"
HorizontalOptions="Start" FontSize="Medium" FontAttributes="Bold" HorizontalTextAlignment="Start" Margin="0,10,0,5" />
<Label Text="{Binding UserComment}" Grid.Row="1" Grid.Column="0" VerticalOptions="Start"
HorizontalOptions="StartAndExpand" FontSize="Medium" HorizontalTextAlignment="Start" Grid.ColumnSpan="2" Margin="0,0,0,10" />
</Grid>
</DataTemplate>
</flv:FlowListView.FlowColumnTemplate>
</flv:FlowListView>
<Grid Grid.Row="1" IsVisible="{Binding ListSwitch, Converter={StaticResource booleanReverser}}">
<Editor Text="{Binding UserComment, Mode=TwoWay}"
HorizontalOptions="FillAndExpand">
<Editor.BindingContext>
<viewModel:MatchPageVM/>
</Editor.BindingContext>
</Editor>
<Label Text="Skriv en kommentar"
HorizontalOptions="StartAndExpand" IsVisible="{Binding LabelIsVisible}" InputTransparent="True">
<Label.BindingContext>
<viewModel:MatchPageVM/>
</Label.BindingContext>
</Label>
</Grid>
</Grid>
</Grid>
</DataTemplate>
</cv:CarouselView.ItemTemplate>
</cv:CarouselView>
</Grid>
</StackLayout>
</ContentPage.Content>
Here is your own mentioned approach that does work:
<AbsoluteLayout
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Editor
Text="{Binding Address, Mode=TwoWay}"
HorizontalOptions="FillAndExpand"
AbsoluteLayout.LayoutFlags="PositionProportional, WidthProportional"
AbsoluteLayout.LayoutBounds="0,0,1.01,100">
</Editor>
<Label Text="MyPlaceHolder" IsVisible="{Binding IsAddrerssPlaceHolderVisible}" HorizontalTextAlignment="Center"
AbsoluteLayout.LayoutBounds="0.5,0.5, 1, 0.5" VerticalTextAlignment="Center"
AbsoluteLayout.LayoutFlags="All" InputTransparent="True"/>
</AbsoluteLayout>
Here is Viewmodel part:
public bool IsAddrerssPlaceHolderVisible
{
get => _isAddrerssPlaceHolderVisible;
set
{
_isAddrerssPlaceHolderVisible= value;
RaisePropertyChanged();
}
}
public string Address
{
get => _address;
set
{
_address = value;
if (value.Length > 0)
{
IsAddrerssPlaceHolderVisible= false;
}
else
{
IsAddrerssPlaceHolderVisible= true;
}
RaisePropertyChanged();
}
}
It doesn't even need anything else which I previously mentioned by mistake! It works as simple as that :D
What you are looking for is a Custom Renderer, you see since Xamarin.Forms is just another level from the native elements, you can "access" the native elements using a CustomRenderer:
https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/custom-renderer/
You can create the base Custom Editor:
using Xamarin.Forms;
namespace EditorWithPlaceholder
{
public class PlaceholderEditor : Editor
{
public static BindableProperty PlaceholderProperty
= BindableProperty.Create(nameof(Placeholder), typeof(string), typeof(PlaceholderEditor));
public static BindableProperty PlaceholderColorProperty
= BindableProperty.Create(nameof(PlaceholderColor), typeof(Color), typeof(PlaceholderEditor), Color.Gray);
public string Placeholder
{
get { return (string) GetValue(PlaceholderProperty); }
set { SetValue(PlaceholderProperty, value); }
}
public Color PlaceholderColor
{
get { return (Color) GetValue(PlaceholderColorProperty); }
set { SetValue(PlaceholderColorProperty, value); }
}
}
}
And the Renderers on each platform:
Android:
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(PlaceholderEditor), typeof(PlaceholderEditorRenderer))]
namespace EditorWithPlaceholder.Droid.Renderers
{
public class PlacehoderEditorRenderer : EditorRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if (Element == null)
return;
var element = (PlaceholderEditor) Element;
Control.Hint = element.Placeholder;
Control.SetHintTextColor(element.PlaceholderColor.ToAndroid());
}
}
}
iOS:
using System;
using Cirrious.FluentLayouts.Touch;
using Foundation;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(PlaceholderEditor), typeof(PlaceholderEditorRenderer))]
namespace EditorWithPlaceholder.iOS.Renderers
{
public class PlaceholderEditorRenderer : EditorRenderer
{
private UILabel _placeholderLabel;
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
if (Element == null)
return;
CreatePlaceholderLabel((PlaceholderEditor) Element, Control);
Control.Ended += OnEnded;
Control.TextChanged += OnChanged;
}
private void CreatePlaceholderLabel(PlaceholderEditor element, UITextView parent)
{
_placeholderLabel = new UILabel
{
Text = element.Placeholder,
TextColor = element.PlaceholderColor.ToUIColor(),
BackgroundColor = UIColor.Clear,
Font = UIFont.FromName(element.FontFamily, (nfloat)element.FontSize)
};
_placeholderLabel.SizeToFit();
parent.AddSubview(_placeholderLabel);
parent.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
parent.AddConstraints(
_placeholderLabel.AtLeftOf(parent, 7),
_placeholderLabel.WithSameCenterY(parent)
);
parent.LayoutIfNeeded();
_placeholderLabel.Hidden = parent.HasText;
}
private void OnEnded(object sender, EventArgs args)
{
if (!((UITextView) sender).HasText && _placeholderLabel != null)
_placeholderLabel.Hidden = false;
}
private void OnChanged(object sender, EventArgs args)
{
if (_placeholderLabel != null)
_placeholderLabel.Hidden = ((UITextView) sender).HasText;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
Control.Ended -= OnEnded;
Control.Changed -= OnChanged;
_placeholderLabel?.Dispose();
_placeholderLabel = null;
}
base.Dispose(disposing);
}
}
}
I hope this information helps.
For reference:
https://solidbrain.com/2017/07/10/placeholder-text-in-xamarin-forms-editor/