For Binding Property in Xamarin Forms - c#

enter image description here This is the data that is stored in listview
I am trying to show ChampName and ChampImage on the page
Therefore, I used Binding in this code but nothing show up...
Please help me Thank you.
public class UserChamp
{
[JsonProperty("championId")]
public int champID { get; set; }
[JsonProperty("championPoints")]
public int points { get; set; }
public string ChampName { get; set; }
public string ChampImage { get; set; }
}
List<UserChamp> champList;
for (int i = 0; i < userChamps.Length; i++)
{
if (userChamps[i].champID == Convert.ToInt32(championDTO.data.Aatrox.key))
{
UserChamp user = new UserChamp {
ChampName = championDTO.data.Aatrox.name,
ChampImage = "http://ddragon.leagueoflegends.com/cdn/12.23.1/img/champion/Atrox.png"
};
champList.Add(user);
}
if (userChamps[i].champID == Convert.ToInt32(championDTO.data.Ahri.key))
{
UserChamp user = new UserChamp
{
ChampName = championDTO.data.Ahri.name,
ChampImage = "http://ddragon.leagueoflegends.com/cdn/12.23.1/img/champion/Ahri.png"
};
champList.Add(user);
} ....
champLv.ItemsSource = champList; // champLv is listview
// this is xml for showing champion Image and Names.
<?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="FinalProject.Champions">
<ContentPage.Content>
<StackLayout>
<ListView x:Name="champLv">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Image Source="{Binding ChampImage}" HeightRequest="100" WidthRequest="100" />
<Label Text="{Binding ChampName}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
private async void Clicked(object sender, ItemTappedEventArgs e)
{
champ = new Champions();
await Navigation.PushAsync(champ, true);
}
I expect to see champion Images and Names.
The listview is saved correctly.
The page I want to show up is champ page so I am using await Navigation.PushAsync(champ, true); in my mainpage so I can go over to it when I click summoner icon

Related

Re-render the screen when an object changes

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>

Shell CollectionView is not updating Xamarin Forms

I'm trying to make CollectionView in Shell but it's not updating.
I have one view model connected to Page and AppShell but when I update Collection view only page is updationg.
`public class AppShellViewModel : INotifyPropertyChanged
{
public Command Load { get; }
public ObservableCollection<ListData> _lists { get; set; }
public ObservableCollection<ListData> Lists
{
get { return _lists; }
set
{
_lists = value;
OnPropertyChanged();
}
}
public AppShellViewModel()
{
Lists = new ObservableCollection<ListData>()
{
new ListData(){id=0,name="test",UserId=0},
new ListData(){id=1,name="test1",UserId=1},
new ListData(){id=2,name="test2",UserId=2},
new ListData(){id=3,name="test3",UserId=3},
new ListData(){id=4,name="test4",UserId=4}
};
Load = new Command(async () => await GetUserLists());
}
async Task GetUserLists()
{
for (int i = 5; i < 15; i++)
{
Lists.Add(new ListData {id=i, name=$"test{ i }", UserId=i });
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}`
Then i have App Shell Collection View
`<Shell.FlyoutContent>
<StackLayout BackgroundColor="#34495e">
<Label Text="YOUR LISTS" FontSize="50" />
<CollectionView ItemsSource="{Binding Lists}" >
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10" x:DataType="model:ListData">
<Label Text="{Binding name}"
LineBreakMode="NoWrap"
FontSize="13" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</Shell.FlyoutContent>`
And There is Page CollectionView
`<?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="ToDoApp.Views.AboutPage"
xmlns:model="clr-namespace:ToDoApp.Models">
<StackLayout>
<Button Text="Load" Command="{Binding Load}"/>
<Label Text="{Binding error}"/>
<CollectionView ItemsSource="{Binding Lists}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10" x:DataType="model:ListData">
<Label Text="{Binding name}"
LineBreakMode="NoWrap"
FontSize="13" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage>`
before update it looks like this
Page before update
Shell before update
And after update the only what changed is content page and shell is the same as before
Page after update
Shell after update
Related to Jason's comment.
WON'T CHANGE TOGETHER
NOT the same instance - BindingContexts similar to these:
// In AppShell.xaml.cs.
public AppShell()
{
InitializeComponent();
BindingContext = new AppShellViewModel();
}
// In AboutPage.xaml.cs.
public AboutPage()
{
InitializeComponent();
BindingContext = new AppShellViewModel();
}
GOOD (SHARED BETWEEN TWO PLACES)
BindingContexts are SAME instance:
// In AppShellViewModel.cs.
public class AppShellViewModel ...
{
private static AppShellViewModel _it;
public static AppShellViewModel It
{
get {
if (_it == null)
_it = new AppShellViewModel();
return _it;
}
}
}
// In AppShell.xaml.cs.
public AppShell()
{
InitializeComponent();
BindingContext = AppShellViewModel.It;
}
// In AboutPage.xaml.cs.
public AboutPage()
{
InitializeComponent();
BindingContext = AppShellViewModel.It;
}

Dynamically add UserControls to a Custom Xamarin ListView using a bindable property

I have already created all of the controls, and have tested that the controls are added as needed without using the binding.
The issue is as soon as I add the binding which is supposed to determine which control to add, the controls stop working as needed.
The list view control will be populated from a collection of a class, which will have an indicator field to determine which control needs to be loaded. The list view contains a 2nd user control which basically acts as a placeholder for the correct control, it has a bindable property of type text which is set to determine the correct control to be loaded.
Here is the XAML Code for the list view control
<ContentView.Content>
<StackLayout>
<Label Text="Binding Control Type"/>
<Entry x:Name="cntName"/>
<ListView x:Name="GroupedView" GroupDisplayBinding="{Binding Title}" HasUnevenRows="True" GroupShortNameBinding="{Binding ShortName}" IsGroupingEnabled="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Text="Add Comment"/>
<MenuItem Text="Add Attachment"/>
</ViewCell.ContextActions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="7*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="3*"/>
<RowDefinition Height="7*"/>
</Grid.RowDefinitions>
<Label Text="{Binding QUESTION_ID}" Grid.Row="0" Grid.Column="0" VerticalTextAlignment="Center" FontSize="Medium"/>
<Label Text="{Binding QUESTION_DETAILS}" Grid.Row="1" Grid.Column="0" VerticalTextAlignment="Center" FontSize="Medium"/>
<con:ucListViewControls ControlType="{Binding QUESTION_ANSWERCONTROL}" Grid.Row="1" Grid.Column="1"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Text="Add Comment"/>
<MenuItem Text="Add Attachment"/>
</ViewCell.ContextActions>
<StackLayout Orientation="Horizontal" Padding="5,5,5,5" BackgroundColor="#E2F5F9">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference this}, Path=Tapped}" CommandParameter="{Binding .}"/>
</StackLayout.GestureRecognizers>
<Button Image="{Binding StateIcon}" BackgroundColor="Transparent" BorderColor="Transparent" BorderWidth="0"/>
<Label Text="{Binding Title}" TextColor="#005569" FontSize="15" VerticalOptions="Center"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
</ListView>
</StackLayout>
</ContentView.Content>
And the code behind for the control
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ucExpandibleListView : ContentView
{
private ObservableCollection<dbQuestionGroup> _allGroups;
private ObservableCollection<dbQuestionGroup> _expandedGroups;
public ucExpandibleListView()
{
InitializeComponent();
Tapped = new Command(x => HeaderTapped(x));
_allGroups = new ObservableCollection<dbQuestionGroup>()
{
new dbQuestionGroup("Category 1", "C1", false)
{
new dbQuestionModel() { QUESTION_ID = 1, QUESTION_DETAILS = "Testing Question 1", QUESTION_ANSWERCONTROL = "RBL" },
new dbQuestionModel() { QUESTION_ID = 2, QUESTION_DETAILS = "Testing Question 2", QUESTION_ANSWERCONTROL = "" }
}
};
UpdateListContent();
}
private void UpdateListContent()
{
_expandedGroups = new ObservableCollection<dbQuestionGroup>();
foreach (dbQuestionGroup group in _allGroups)
{
dbQuestionGroup newGroup = new dbQuestionGroup(group.Title, group.ShortName, group.Expanded);
newGroup.QuestionCount = group.Count;
if (group.Expanded)
{
foreach (dbQuestionModel question in group)
{
newGroup.Add(question);
}
}
_expandedGroups.Add(newGroup);
}
GroupedView.ItemsSource = _expandedGroups;
}
public Command Tapped { get; set; }
private void HeaderTapped(object group)
{
var groupCat = (dbQuestionGroup)group;
int selectedIndex = _expandedGroups.IndexOf(groupCat);
if (groupCat.Expanded)
{
_allGroups[selectedIndex].Expanded = false;
}
else
{
_allGroups.ToList().ForEach(x => x.Expanded = false);
_allGroups[selectedIndex].Expanded = !_allGroups[selectedIndex].Expanded;
}
UpdateListContent();
}
}
Here is the XAML Code for the placeholder control
<ContentView.Content>
<StackLayout x:Name="stkPlaceholder">
</StackLayout>
</ContentView.Content>
And the code behind for the placeholder control
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ucListViewControls : ContentView, INotifyPropertyChanged
{
public ucListViewControls()
{
InitializeComponent();
}
#region Control Attributes
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string info)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
}
#endregion
#region Bindable Properties
public static readonly BindableProperty ControlTypeProperty = BindableProperty.Create(nameof(ControlType), typeof(string), typeof(ucListViewControls));
public string ControlType
{
get
{
return (string)GetValue(ControlTypeProperty);
}
set
{
SetValue(ControlTypeProperty, value);
AddControl();
NotifyPropertyChanged("ControlType");
}
}
#endregion
public void AddControl()
{
switch (ControlType)
{
case "RBL":
ucRadiobuttons radiobuttons = new ucRadiobuttons();
radiobuttons.lblTitle1 = "Yes";
radiobuttons.lblTitle2 = "No";
radiobuttons.lblTitle3 = "N/A";
radiobuttons.OnColor1 = Color.Green;
radiobuttons.OnColor2 = Color.Red;
radiobuttons.OnColor3 = Color.Transparent;
stkPlaceholder.Children.Add(radiobuttons);
break;
default:
Entry placeholder = new Entry();
stkPlaceholder.Children.Add(placeholder);
break;
}
}
}
I have tested that the controls are added without the binding, which works perfectly.
I have tried to rewrite the bindable property multiple times in case I missed something, I also could not find any post relating to something similar which wouldve helped me.
Any clues?
The first screenshot shows the expected output, and the seconds screenshots shows what happens when the binding is applied.
dbQuestionModel:
using System.Collections.Generic;
namespace PivotMobile_BusinessLayer.Models
{
public class dbQuestionModel
{
public int QUESTION_PK { get; set; }
public int QUESTION_ID { get; set; }
public string QUESTION_CATEGORY { get; set; }
public string QUESTION_DETAILS { get; set; }
public string QUESTION_TYPE { get; set; }
public string QUESTION_ANSWERCONTROL { get; set; }
public string QUESTION_COMMENT { get; set; }
public List<string> QUESTION_ATTACHMENTS { get; set; }
}
}
dbQuestionGroup:
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace PivotMobile_BusinessLayer.Models
{
public class dbQuestionGroup : ObservableCollection<dbQuestionModel>, INotifyPropertyChanged
{
public static ObservableCollection<dbQuestionGroup> All { private set; get; }
private bool _expanded;
public string Title { get; set; }
public string ShortName { get; set; }
public bool Expanded
{
get
{
return _expanded;
}
set
{
if (_expanded != value)
{
_expanded = value;
OnPropertyChanged("Expanded");
OnPropertyChanged("StateIcon");
}
}
}
public string StateIcon
{
get
{
return Expanded ? "expanded_blue.png" : "collapsed_blue.png";
}
}
public int QuestionCount { get; set; }
public dbQuestionGroup(string title, string shortName, bool expanded = true)
{
Title = title;
ShortName = shortName;
Expanded = expanded;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
ListView Page XAML:
<?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="PivotMobile.Views.ObservationsView"
xmlns:con="clr-namespace:PivotMobile.Controls">
<ContentPage.Content>
<StackLayout Margin="5">
<con:ucExpandibleListView/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
ListView Page Code Behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace PivotMobile.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ObservationsView : ContentPage
{
public ObservationsView ()
{
InitializeComponent ();
}
}
}

Databinding is not working between two tabbedpage children

I'm new to Xamarin.Forms development and I'm trying to build a tiny Xamarin app to start.
My app currently has one main TabbedPage that has two ContentPages children. On the ListePage, I have a ListView with an ObservableCollection with OlonaModel is an object with an int Numero and a Text string. I would like the Details page to show details of the selected OlonaModel from the listview of ListePage, but the Details page doesn't seem to update to changes when I select an item from the listview.
Both of the content pages are bound to the same ListPageViewModel. The view model updates when I select an item from the listview, but the changes aren't reflected on the Details page and I'm really confused.
How can I make the Details refresh itself when the SelectedItem of the view model gets set ?
The MainPage :
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:App.Views"
xmlns:viewmodels="clr-namespace:App.ViewModels"
mc:Ignorable="d"
x:Class="App.MainPage">
<TabbedPage.Children>
<local:ListePage/>
<local:Details/>
</TabbedPage.Children>
</TabbedPage>
The ListePage.xaml (ContentPage1 in the post) :
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="App.Views.ListePage"
Title="Liste">
<ContentPage.Content>
<StackLayout>
<ListView x:Name="ListeMipoitra" ItemSelected="ListeMipoitra_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Text="{Binding Numero}" Grid.Column="0" FontSize="Medium" FontAttributes="Bold"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
The ListePage.xaml.cs :
namespace App.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ListePage : ContentPage
{
public static ListePageViewModel viewModel;
public ListePage()
{
InitializeComponent();
viewModel = new ListePageViewModel();
this.BindingContext = viewModel;
ListeMipoitra.ItemsSource = viewModel.listeOlonaVM;
}
private void ListeMipoitra_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
viewModel.setSelected((OlonaModel)e.SelectedItem);
}
}
}
The Details.xaml (ContentPage2 in the post) :
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="App.Views.Details"
Title="Détails">
<ContentPage.Content>
<StackLayout>
<Label Text="{Binding Text}"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
The Details.xaml.cs :
namespace App.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Details : ContentPage
{
public Details()
{
InitializeComponent();
this.BindingContext = ListePage.viewModel.selected;
}
}
}
The ListePageViewModel.cs :
Note: I'm using Fody and PropertyChanged.Fody weaver, so the RaisePropertyChanged() event (should be) is called automatically when a property changes
namespace App.ViewModels
{
public class ListePageViewModel : INotifyPropertyChanged
{
public ObservableCollection<OlonaModel> listeOlonaVM;
public OlonaModel selected { get; set; }
public ListePageViewModel()
{
listeOlonaVM = new ObservableCollection<OlonaModel>();
listeOlonaVM = ListeOlona.liste;
}
public event PropertyChangedEventHandler PropertyChanged;
public void setSelected(OlonaModel olona)
{
selected = olona;
}
}
}
The model of the Olona object :
namespace App.Models
{
public class OlonaModel
{
public int Numero { get; set; }
public string Text { get; set; }
public OlonaModel(int num, string text)
{
this.Numero = num;
this.Text= text;
}
}
}
The ListeOlona.cs where the model of the list is stored:
The InitializeList() method is called at App Startup.
namespace App.ViewModels
{
public static class ListeOlona
{
public static ObservableCollection<OlonaModel> liste = new ObservableCollection<OlonaModel>();
public static void InitializeList()
{
liste.Add(new OlonaModel(1,
"FirstItem"));
liste.Add(new OlonaModel(2,
"Second Item"));
}
}
}
According to your description, there is tabbedpage, two pages, one is Listpage, another is detailpage, you want to select listview item in listpage, then other detail info will display detailpage, am I right?
If yes, I suggest you can do this like this:
TabbedPage:
<TabbedPage
x:Class="App4.TabbedPage2"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App4"
x:Name="tabbedpage2">
<!-- Pages can be added as references or inline -->
<TabbedPage.Children>
<local:ListPage Title="Mian page" BindingContext="{Binding}" />
<local:DetailPage Title="Detail page" BindingContext="{Binding select}" />
</TabbedPage.Children>
public partial class TabbedPage2 : TabbedPage
{
public TabbedPage2 ()
{
InitializeComponent();
this.BindingContext = new ListePageViewModel();
}
}
public class OlonaModel
{
public int Numero { get; set; }
public string Text { get; set; }
}
public class ListePageViewModel : ViewModelBase
{
public ObservableCollection<OlonaModel> listeOlonaVM { get; set; }
private OlonaModel _select;
public OlonaModel select
{
get { return _select; }
set
{
_select = value;
RaisePropertyChanged("select");
}
}
public ListePageViewModel()
{
listeOlonaVM = new ObservableCollection<OlonaModel>()
{
new OlonaModel(){Numero=1,Text="first item"},
new OlonaModel(){Numero=2,Text="second item"},
new OlonaModel(){Numero=3,Text="third item"},
new OlonaModel(){Numero=4,Text="fouth item"}
};
select = listeOlonaVM[0];
}
}
ListPage:
<StackLayout>
<ListView ItemsSource="{Binding listeOlonaVM}" SelectedItem="{Binding select}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Numero}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
DetailPage:
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="{Binding Text}"
VerticalOptions="CenterAndExpand" />
</StackLayout>
ViewModelBase implement INotifyPropertyChanged interface.
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Xamarin Cross Platform Picker not binding correctly

I am new to Xamarin Cross Platform apps
I am trying to bind a Picker ItemSource to a List and display one property, with out success! My reference has been from here
Please can some one advise where my error is, my View or Xmal please (or probably both)
The List is a List of StdGrades defined as
namespace FitRestults_Dev1
{
class StdGrade
{
public string Gradelbl
{ get; set; }
public string Grade
{ get; set; }
public static List<StdGrade> Grades()
{
List<StdGrade> GradesList = new List<StdGrade>(){
new StdGrade(){ Gradelbl="10th Gup (White belt)", Grade="G10"},
new StdGrade(){ Gradelbl="9th Gup (Organge belt)", Grade="G9"},
new StdGrade(){ Gradelbl="8th Gup (Organge belt 1 tag)", Grade="G8"},
... };
return GradesList;
}
public List<StdGrade> GradesList => Grades();
public static string GetGrade(string Input)
{
List<StdGrade> GradesList = Grades();
var result = (from r in GradesList where r.Gradelbl == Input select r).First();
return result.Grade;
}
}
For the Content page I have defined a simple view as
namespace FitRestults_Dev1
{
class AddStudentView
{
List<StdGrade> _GradeList;
public List<StdGrade> GradeList
{ get => _GradeList;
set
{
_GradeList = StdGrade.Grades();
}
}
}
}
My content page xmal is
<?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="FitRestults_Dev1.AddStudent"
xmlns:src="clr-namespace:FitRestults_Dev1"
>
<ContentPage.BindingContext>
<src:AddStudentView/>
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout Padding="10" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Grid>
…
<Picker x:Name="GradePicker" Title="Select a Grade" Grid.Row="2" Grid.Column="1" MinimumWidthRequest="100" FontSize="12"
ItemsSource="GradeList" SelectedIndex="0" ItemDisplayBinding="{Binding Gradelbl}">
</Picker>
</StackLayout>
</ContentPage.Content>
</ContentPage>
You are providing the itemsSource the incorrect way it should be a binding
ItemsSource={Binding GradeList}
Also Stop using Generic.List for binding, MVVM with Xamarin Forms should have ObservableCollections as it inherits from INotifyPropertyChanged and INotifyCollectionChanged

Categories