I get data from another page with
var check = new check
{
Age = (int)Convert.ToInt64(Ageg)
};
var secondPage = new Sdeduction ();
secondPage.BindingContext = check;
await Navigation.PushAsync(secondPage);
and received on
public class check
{
public int Age { get; set; }
}
public Sdeduction()
{
InitializeComponent();
}
but I am unable to access Age for some calculation directly. lile tta.Text = Age.ToString();
So I use binding. Which work well.
<Label x:Name="Ages" Text="{Binding Age}"></Label>
but i want to check for Age which data get passed between page but I'm unable to figure it out I try
public Sdeduction()
{
InitializeComponent();
int aged = (int)Convert.ToInt64(Ages.Text);
if (aged == 0)
{
TTA.IsVisible = true;
}
if(aged > 0)
{
TTB.IsVisible = true;
//Ds.IsVisible = true;
}
}
But it is Ages.Text is null.
Main issue is how to get data from public class check
public class check
{
public int Age { get; set; }
}
How can able to get this public int in other part of c#. where get passed data by
I can able to bind but https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/ is all about the binding property and context on the xaml level. I like to get data from other page but only can able to bind with the x:names Ages but nothing much as when page load/InitializeComponent it don't have names of ages.
You set the BindingContext of the Sdeduction instance to the check instance, and then navigates to the Sdeduction. It's the right way to pass data when navigating.
But when you check for Age as page load in Sdeduction() method, it always get 0 before the Sdeduction page set the BindingContext. You nned to load in OnAppearing() method.
MainPage:
xaml:
<StackLayout>
<Label x:Name="label" Text="10" />
<Button Clicked="Button_Clicked" Text="Navigate" />
</StackLayout>
Code behind:
public partial class MainPage : ContentPage
{
string Ageg;
public MainPage()
{
InitializeComponent();
Ageg = label.Text;
}
async void Button_Clicked(object sender, EventArgs e)
{
var check = new check
{
Age = (int)Convert.ToInt64(Ageg)
};
var secondPage = new Sdeduction();
secondPage.BindingContext = check;
await Navigation.PushAsync(secondPage);
}
}
Sdeduction:
Xaml:
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="Welcome to Sdeduction!"
VerticalOptions="CenterAndExpand" />
<Label x:Name="Ages" Text="{Binding Age}" />
<StackLayout Orientation="Horizontal">
<Button
x:Name="TTA"
IsVisible="false"
Text="TTA" />
<Button
x:Name="TTB"
IsVisible="false"
Text="TTB" />
</StackLayout>
</StackLayout>
Code behind:
protected override void OnAppearing()
{
base.OnAppearing();
int aged = (int)Convert.ToInt64(Ages.Text);
if (aged == 0)
{
TTA.IsVisible = true;
}
if (aged > 0)
{
TTB.IsVisible = true;
//Ds.IsVisible = true;
}
}
Please check the screenshot:
https://imgur.com/vx6GZFw
Related
I would like to slightly modify the code generated when creating a maui project to implement the following
add an object to Meetings in MainPage.xaml.cs when the button is clicked
display the contents of that Meetings
I wrote the following code for this purpose, but there is no change in the output content. One possible reason for this is that adding data to the object does not re-render the screen. How can I solve this problem?
Views/MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App.Views"
x:Class="App.Views.MainPage">
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Image
Source="dotnet_bot.png"
SemanticProperties.Description="Cute dot net bot waving hi to you!"
HeightRequest="200"
HorizontalOptions="Center" />
<Label
Text="Hello, World!"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" />
<Label
Text="Welcome to .NET Multi-platform App UI"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App U I"
FontSize="18"
HorizontalOptions="Center" />
<Button
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
<ListView ItemsSource="{Binding Meetings}" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
Views/MainPage.xaml.cs
namespace App.Views;
using App.Models;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
BindingContext = new Models.AllMeetings();
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
((Models.AllMeetings)BindingContext).Meetings.Add(new Models.Meeting() { Name = "foo" });
}
}
Modes/AllMeetings
namespace App.Models;
internal class AllMeetings
{
public List<Meeting> Meetings { get; set; }
}
Models/Meetings.cs
namespace App.Models;
internal class Meeting
{
public string Name { get; set; }
}
Updates
Models/AllMeetings.cs
using System.Collections.ObjectModel;
namespace ailia_speech_gui.Models;
internal class AllMeetings
{
public ObservableCollection<Meeting> Meetings { get; set; }
public void Add_Meeting(Meeting meeting)
{
this.Meetings.Add(meeting);
}
}
I made a demo on my side. You can refer to my demo to change your project.
Here is the code in my Model named Products.cs:
namespace ListViewDelete.Models
{
public class Products
{
public string Name
{
get; set;
}
public double Price
{
get; set;
}
}
}
Then you need to create a viewmodel to realize the delete and add method and create the ObservableCollection to load the data.
Here is the code in my ViewModel:
namespace ListViewDelete.ViewModels
{
internal class ProductsViewModels
{
public ObservableCollection<Products> Products
{
get; set;
}
public Command<Products> RemoveCommand
{
get
{
return new Command<Products>((Product) => {
Products.Remove(Product);
});
}
}
public Command<Products> AddCommand
{
get
{
return new Command<Products>((Product) => {
Products.Add(Product);
});
}
}
public ProductsViewModels()
{
Products = new ObservableCollection<Products> {
new Products {
Name = "name1",
Price = 100
},
new Products {
Name = "name2",
Price = 100
},
new Products {
Name = "name3",
Price = 100
}
};
}
}
}
Last, you need to create the ListView or the CollectionView in the MainPage.xaml. Here is the code in the MainPage.xaml:
<StackLayout>
<Button Text="add" Clicked="Button_Clicked"></Button>
<CollectionView ItemsSource="{Binding Products}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding Name}" />
<Label Text="{Binding Price}" />
<Button Text="Remove" Clicked="Remove_Clicked" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
Here is the code in MainPage.xaml.cs:
namespace ListViewDelete
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
// bind the viewmodel to the Mainpage
BindingContext = new ProductsViewModels();
}
//delete the item from the observablecollection
public void Remove_Clicked(object sender, EventArgs e)
{
var button = sender as Button;
var product = button.BindingContext as Products;
var vm = BindingContext as ProductsViewModels;
vm.RemoveCommand.Execute(product);
}
//add the new item to the observablecollection
private void Button_Clicked(object sender, EventArgs e)
{
var product = new Products()
{
Name =" new name",
Price = 100
};
var vm = BindingContext as ProductsViewModels;
vm.AddCommand.Execute(product);
}
}
}
Meeting collection must be somewhere initialized before calling any operation on collestion (be it on property level or in constructor):
public class AllMeetings
{
public ObservableCollection<Meeting> Meetings { get; } = new ObservableCollection<Meeting>();
public void Add_Meeting(Meeting meeting)
{
this.Meetings.Add(meeting);
}
}
And ListView must have some data template to tell UI how data should be presented:
<ListView ItemsSource="{Binding Meetings}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Name}"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I'm trying to search how to create a custom picker on Xamarin but I have no idea how to do it.
Here is what I want to do
I don't even know if I need to install a nuget package. Please help and thanks.
As mentioned by #Skalpel02, you need to sub-class the Picker class and implement the corresponding Renderers in each platform. There, you have the ability to interact with native APIs of the platform.
This could be implemented by custom renderer.
First,a custom Picker control can be created by subclassing the Picker control, as shown in the following code:
public class BorderlessPicker : Picker
{
public BorderlessPicker() : base()
{
}
}
Second:Create the Custom Renderer on each Platform,Override the OnElementChanged method and write logic to customize the control,then Add an ExportRenderer attribute to the custom renderer class to specify that it will be used.
In Android:
[assembly: ExportRenderer(typeof(BorderlessPicker), typeof(BordlessPickerRenderer))]
namespace AppPicker01.Droid
{
public class BordlessPickerRenderer : PickerRenderer
{
public BordlessPickerRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
Control.Background = null;
}
}
}
}
In iOS:
[assembly: ExportRenderer(typeof(BorderlessPicker), typeof(BorderlessPickerRenderer))]
namespace AppPicker01.iOS
{
public class BorderlessPickerRenderer : PickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (Control == null)
{
return;
}
Control.Layer.BorderWidth = 0;
Control.BorderStyle = UITextBorderStyle.None;
}
}
}
Last but not least, consume the custom picker control in Xaml:
<apppicker01:BorderlessPicker Title="Select a color" ItemsSource="{Binding ColorNames}" SelectedItem="{Binding SelectedColorName, Mode=TwoWay}" />
Screenshot:
MS official docs link:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/
You can easily create your own control that doesn't need a renderer and works on iOS, Android, and UWP. Here my solution.
You have to create a View "PickerCustom" for the control
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="___YOURCLASS"
xmlns:xmleditor="clr-namespace:XmlEditor" HorizontalOptions="FillAndExpand" BackgroundColor="#ddd">
<StackLayout x:Name="stack" Orientation="Horizontal" HorizontalOptions="FillAndExpand" Margin="1" BackgroundColor="#fff" Padding="5">
<Label Text="{Binding TextValue}" Margin="0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"/>
<ImageButton BackgroundColor="#ffffff" Source="dropdown.png" x:Name="img" WidthRequest="20"></ImageButton>
<Entry WidthRequest="0"></Entry>
</StackLayout>
</ContentView>
with this code behind
public partial class PickerCustom : ContentView
{
public PickerCustom()
{
InitializeComponent();
Items = new ObservableCollection<CustomItem>();
SelectedIndex = -1;
BindingContext = this;
TapGestureRecognizer tap0 = new TapGestureRecognizer();
tap0.Tapped += (sender, e) =>
{
img.Focus();
PickerCustomList pcl = new PickerCustomList();
pcl.Items = this.Items;
App.Current.MainPage.Navigation.PushModalAsync(pcl);
MessagingCenter.Subscribe<PickerCustomList>(this, "finish", (sender1) =>
{
MessagingCenter.Unsubscribe<PickerCustomList>(this, "finish");
img.Focus();
if(((PickerCustomList)sender1).SelectedIndex != -1)
{
SelectedIndex = ((PickerCustomList)sender1).SelectedIndex;
}
});
};
GestureManager.AddGesture(stack, tap0);
}
string _textvalue = "";
public string TextValue
{
get
{
return _textvalue;
}
set
{
_textvalue = value;
OnPropertyChanged();
}
}
public ObservableCollection<CustomItem> Items { get; set; }
int _selectedIndex = 0;
public int SelectedIndex
{
get
{
return _selectedIndex;
}
set
{
_selectedIndex = value;
if(_selectedIndex>= Items.Count)
{
_selectedIndex = -1;
} else if (_selectedIndex != -1)
{
TextValue = Items[SelectedIndex].Name;
}
else
{
TextValue = "";
}
OnPropertyChanged();
}
}
}
public class CustomItem
{
public CustomItem(string _name)
{
name = _name;
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
And a View "PickerCustomList" for the choice
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="___YOURCLASS" BackgroundColor="#66aaaaaa"
x:Name="ContentPage1" Padding="30,100,30,100" >
<ListView x:Name="ContactsList" ItemsSource="{Binding Items}" IsVisible="True"
VerticalOptions="Start" HorizontalOptions="Center"
BackgroundColor="Transparent" HasUnevenRows="True">
<ListView.Header HorizontalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" BackgroundColor="#f0f0f0" >
<ImageButton Source="close.png" WidthRequest="20" Clicked="Button_Clicked" Margin="10,5,10,5" BackgroundColor="Transparent"></ImageButton>
</StackLayout>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Tapped="ViewCell_Tapped" >
<StackLayout BackgroundColor="#ffffff">
<Label Text="{Binding Name}" Padding="10"></Label>
<ContentView HeightRequest="1" BackgroundColor="#666"></ContentView>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
with this code behind
public partial class PickerCustomList : ContentPage
{
public int SelectedIndex = -1;
ObservableCollection<CustomItem> myItems= new ObservableCollection<CustomItem>();
public ObservableCollection<CustomItem> Items
{
get { return myItems; }
set {
myItems = value;
OnPropertyChanged();
}
}
public PickerCustomList()
{
InitializeComponent();
BindingContext = this;
}
private void Button_Clicked(object sender, EventArgs e)
{
SelectedIndex = -1;
App.Current.MainPage.Navigation.PopModalAsync();
MessagingCenter.Send<PickerCustomList>(this, "finish");
}
private void ViewCell_Tapped(object sender, EventArgs e)
{
SelectedIndex = Items.IndexOf(((CustomItem)((ViewCell)sender).BindingContext));
App.Current.MainPage.Navigation.PopModalAsync();
MessagingCenter.Send<PickerCustomList>(this, "finish");
}
}
Here is a sample app that illustrates my problem (full source at: https://github.com/cmpalmer66/CollectionViewSample)
It works fine on UWP and Android, but on iOS, if you click the Add Label or Add Entry buttons, the preloaded list of 20 items disappears (or shrinks to 0 height). Adding more controls still just displays the last one, moving down the page. Occasionally, one of the previously added controls will show up at random.
Basically just wondering if I'm doing something wrong or if this is a bug.
MainPage.xaml
<StackLayout>
<Button Text="Add Label" Clicked="Button1_OnClicked" />
<Button Text="Add Entry" Clicked="Button2_OnClicked" />
<CollectionView x:Name="MyCollectionView">
<CollectionView.ItemTemplate>
<DataTemplate>
<ContentView Content="{Binding .}"></ContentView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
MainPage.xaml.cs:
using System.Collections.ObjectModel;
using System.ComponentModel;
using Xamarin.Forms;
namespace CollectionViewSample
{
[DesignTimeVisible(false)]
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
MyCollectionView.BindingContext = this;
MyCollectionView.SetBinding(ItemsView.ItemsSourceProperty, nameof(ControlList));
// Adding these 20 items all at once works fine
for (var x = 0; x < 20; x++)
{
ControlList.Add(new Label {Text = $"Added at {ControlList.Count}"});
}
}
public ObservableCollection<View> ControlList { get; set; } = new ObservableCollection<View>();
private void Button1_OnClicked(object sender, EventArgs e)
{
// Adding a single control to the ControlList will mess up the display of the previously
// added items on iOS
ControlList.Add(new Label {Text = $"Added at {ControlList.Count}"});
}
private void Button2_OnClicked(object sender, EventArgs e)
{
// Adding a single control to the ControlList will mess up the display of the previously
// added items on iOS
ControlList.Add(new Entry {Text = $"Added at {ControlList.Count}"});
}
}
}
Below is a simple sample:
Create a ViewTemplateSelector :
public class ViewTemplateSelector : DataTemplateSelector
{
public DataTemplate LebelTemplate { get; set; }
public DataTemplate EntryTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
return ((CollectionData)item).Type == 1 ? LebelTemplate : EntryTemplate;
}
}
then use in your page xaml:
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="labelTemplate">
<Label Text="{Binding Name}"/>
</DataTemplate>
<DataTemplate x:Key="entryTemplate">
<Entry Text="{Binding Name}"/>
</DataTemplate>
<local:ViewTemplateSelector x:Key="viewTemplateSelector"
LebelTemplate="{StaticResource labelTemplate}"
EntryTemplate="{StaticResource entryTemplate}" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<Button Text="Add Label" Clicked="Button1_Clicked" />
<Button Text="Add Entry" Clicked="Button2_Clicked" />
<CollectionView x:Name="MyCollectionView" ItemTemplate="{StaticResource viewTemplateSelector}" >
</CollectionView>
</StackLayout>
</ContentPage.Content>
create a data mode ,add a Type to determine which template to use (here 1 means add Label,2 means add Entry):
public class CollectionData
{
public string Name { get; set; }
public int Type { get; set; }
}
in your page.xaml.cs:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
MyCollectionView.BindingContext = this;
MyCollectionView.SetBinding(ItemsView.ItemsSourceProperty, nameof(ControlList));
// Adding these 20 items all at once works fine
for (var x = 0; x < 20; x++)
{
ControlList.Add(new CollectionData { Name = $"Added at {ControlList.Count}",Type = 1 });
}
}
public ObservableCollection<CollectionData> ControlList { get; set; } = new ObservableCollection<CollectionData>();
private void Button1_OnClicked(object sender, EventArgs e)
{
// Adding a single control to the ControlList will mess up the display of the previously
// added items on iOS
ControlList.Add(new CollectionData { Name = $"Added at {ControlList.Count}",Type = 1 });
}
private void Button2_OnClicked(object sender, EventArgs e)
{
// Adding a single control to the ControlList will mess up the display of the previously
// added items on iOS
ControlList.Add(new CollectionData { Name = $"Added at {ControlList.Count}",Type = 2 });
}
}
I am learning Xamaring forms , I want to do 4 content pages. One will display my to do listand images.
I would like to know if there is a way to charge my todo list before going to the last page from any of my 3 pages.
Knowing that I am going through pages like this :
var page = new LastPage();
MainView.Content = page.Content;
Thanks for your help
Do you want to achieve the result like following GIF?
If so, you need achieve it by MVVM and INotifyPropertyChanged
First of all, you should create a model to achieve the INotifyPropertyChanged.
public class MyModel: INotifyPropertyChanged
{
string name;
public string Name
{
set
{
if (name != value)
{
name = value;
OnPropertyChanged("Image");
}
}
get
{
return name;
}
}
string count;
public string Count
{
set
{
if (count != value)
{
count = value;
OnPropertyChanged("Count");
}
}
get
{
return count;
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Then you need the ViewModel to push the data.
public class MyViewModel
{
public ObservableCollection<MyModel> myModels { get; set; }
public MyViewModel() {
myModels = new ObservableCollection<MyModel>();
myModels.Add(new MyModel() { Count = "0", Name = "test1" });
myModels.Add(new MyModel() { Count = "1", Name = "test2" });
myModels.Add(new MyModel() { Count = "2", Name = "test3" });
}
}
In the First page and end page, you should binding same viewmodel that use bindingcontext like following code format.
MainPage.xaml
<StackLayout>
<!-- Place new controls here -->
<Button Text="Next" Clicked="Button_Clicked"></Button>
<ListView x:Name="mylistview" ItemsSource="{Binding myModels}" HasUnevenRows="True" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<StackLayout>
<Label Text="{Binding Name}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center" />
<Label Text="{Binding Count}"
LineBreakMode="WordWrap"
HorizontalOptions="Center" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
MyViewModel viewModel;
public MainPage()
{
InitializeComponent();
viewModel = new MyViewModel();
BindingContext = viewModel;
}
private void Button_Clicked(object sender, EventArgs e)
{
Navigation.PushAsync(new Page1(viewModel));
}
}
Here is my demo, you can download it.
https://github.com/851265601/XFormsMvvmChange
Here is a helpful article about it, you can refer to it.
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/data-bindings-to-mvvm
public class Zicker : INotifyPropertyChanged
{
public class MyClass
{
public string HeyName { get; set; }
public string HeySurname { get; set; }
public int HeyAge { get; set; }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string name = null)
{
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(name));
}
}
private ObservableCollection<MyClass> _yourList = new ObservableCollection<MyClass>();
public ObservableCollection<MyClass> YourList
{
get
{
return _yourList;
}
set
{
_yourList = value;
RaisePropertyChanged("YourList");
RaisePropertyChanged("BindMeLabel");
}
}
public int BindMeLabel
{
get { return _yourList.Sum(a => a.HeyAge); }
}
public void WonCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
RaisePropertyChanged("BindMeLabel");
}
public List<string> heresamplenames = new List<string> { "Mohamed", "Zaran", "Ivan" };
public List<string> heresamplesurnames = new List<string> { "Pakou", "Simmone", "Zagoev" };
public List<int> heresampleages = new List<int> { 17,33,50 };
public Zicker()
{
ObservableCollection<MyClass> vs = new ObservableCollection<MyClass>();
for (int i = 0; i < 3; i++)
{ vs.Add(new MyClass { HeyName = heresamplenames[i], HeySurname = heresamplesurnames[i], HeyAge = heresampleages[i] }); }
YourList = vs; YourList.CollectionChanged += WonCollectionChanged;
}
}
<ContentPage.Content>
<StackLayout Orientation="Vertical" HorizontalOptions="Center" VerticalOptions="Center">
<ContentView HorizontalOptions="Fill" VerticalOptions="Fill">
<ListView HorizontalOptions="Center" VerticalOptions="Center" HasUnevenRows="True" ItemsSource="{Binding YourList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label HorizontalTextAlignment="Center" VerticalTextAlignment="Center" Text="{Binding Path=HeyName}" Grid.Column="0" FontSize="12" TextColor="Black"></Label>
<Label HorizontalTextAlignment="Center" VerticalTextAlignment="Center" Text="{Binding Path=HeySurname}" FontSize="12" TextColor="Black" Grid.Column="1"/>
<Entry HorizontalTextAlignment="Center" VerticalOptions="Center" Text="{Binding Path=HeyAge}" FontSize="12" Keyboard="Numeric" TextColor="Black" Grid.Column="2"/>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentView>
<Label Text="{Binding BindMeLabel}" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" FontSize="40" TextColor="Black"></Label>
</StackLayout>
</ContentPage.Content>
public MainPage()
{
InitializeComponent();
BindingContext = new Zicker();
}
My Problem: In this List, there are three names, surnames, and ages. At the bottom, there is also a label which should be shown as the sum of Ages collection.
When the UI is starting, Label is working well. But, if I try to change any Ages entries, there is a big problem with the binding label.
I want to use MVVM structure but due to this problem, label binding is working just start up.
If you are updating the HeyName property, binding is not updating because the class MyClass does not implement INotifyPropertyChanged.
Try to replace the MyClass class with this code:
public class MyClass : INotifyPropertyChanged
{
private string name;
private string surname;
private int age;
public string HeyName
{
get => name;
set
{
name = value;
RaisePropertyChanged("HeyName");
}
}
public string HeySurname
{
get => surname;
set
{
surname = value;
RaisePropertyChanged("HeySurname");
}
}
public int HeyAge
{
get => age;
set
{
age = value;
RaisePropertyChanged("HeyAge");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string name = null)
{
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(name));
}
}
}
EDIT:
Sorry, the CollectionChanged is not called when you update the HeyAge property, because it is called only if the collection is changed, but not when a property of an item in the collection changes.
Try to add the OnAgeChanged event into the class MyClass and call it when the HeyAge property change:
public class MyClass : INotifyPropertyChanged
{
public event EventHandler OnAgeChanged;
public int HeyAge
{
get => age;
set
{
age = value;
RaisePropertyChanged("HeyAge");
OnAgeChanged?.Invoke(this, EventArgs.Empty);
}
}
...
...
Then, when you add a new MyClass object into the collection, register the event in the ViewModel like this:
public Zicker()
{
ObservableCollection<MyClass> vs = new ObservableCollection<MyClass>();
for (int i = 0; i < 3; i++)
{
var test = new MyClass()
{
HeyName = heresamplenames[i],
HeySurname = heresamplesurnames[i],
HeyAge = heresampleages[i],
};
test.OnAgeChanged += Test_OnAgeChanged;
vs.Add(test);
}
YourList = vs;
YourList.CollectionChanged += WonCollectionChanged;
}
private void Test_OnAgeChanged(object sender, EventArgs e)
{
RaisePropertyChanged("BindMeLabel");
}
Note that the WonCollectionChanged it's not necessary any more.
Note also that the variable vs is not needed, you can work directly into the YourList object instead.