need to ask you a hand with this one.
I'm currently developing a Xamarin Forms solution using MVVM and i'm in a new situation right now.
I've got a listView with items made by this class
public class City
{
public int Key { get; set; }
public string Value { get; set; }
public List<string> Words{ get; } = new List<string> { "One", "Two", "Three" };
}
What I want to achieve is to display a label text created using the Words list elements indicized by Key. Something like
Words[Key]
Example
<ListView
ItemsSource="{Binding Cities}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout
HorizontalOptions="FillAndExpand"
VerticalOptions="StartAndExpand">
<Label Text="{Binding Words[Key]}"
FontSize="18"
TextColor="Black"
VerticalOptions="StartAndExpand" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The label text binding doesn't work, but tecnically is what i need to achieve. For example, if i use Words[0] it will work and returns 'One'
My ViewModel is pretty simple.
public class TestViewModel : INotifyPropertyChanged
{
public ObservableCollection<City> Cities { get; set; }
public TestViewModel()
{
Cities = GetCities();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public ObservableCollection<City> GetCities()
{
return new ObservableCollection<City>
{
new City {Key = 1, Value = "Mumbai"},
new City {Key = 2, Value = "New York"},
new City {Key = 3, Value = "Milan"},
new City {Key = 4, Value = "Rome"}
};
}
}
Do i need to create a property for indexing? In my opinion the problem is that i'm inside a list and already have an index to use.
Thanks for help guys
You can modify your model :
public class City
{
public int Key { get; set; }
public string Value { get; set; }
public List<string> Words { get; } = new List<string> { "One", "Two", "Three" };
public string myValue
{
get
{
return Words[Key];
}
set {}
}
}
And in your .xmal, just set Text="{Binding myValue}" and it will display a list element value of Words.
Related
I have ListView with Button showing status A(Absent), P(Present) and L(Late) for each item. On Button click status Text getting changed P to A, A to L.
When changing status of any item, I have to change AttendanceId, AttendanceTypeStatusCD, AttendanceTypeStatusId fields for for the same record. This I have to do for multiple records. I need to update my ListView's source StudentList according to action performed and post modified data to db.
<ListView x:Name="list1" ItemsSource="{Binding StudentList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Image Source="other.png" />
<Label Text="{Binding StudentName}" />
<Button x:Name="mybtn"
BindingContext="{Binding Source={x:Reference list1}, Path=BindingContext}"
Command="{Binding BtnTextCommand}"
CommandParameter="{Binding Source={x:Reference mybtn}}"
Text="{Binding AttendanceTypeStatusId, Converter={x:StaticResource IDToStringConverter}}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is my model class
public class Student
{
public int? StudentId { get; set; }
public string StudentName { get; set; }
public int? AttendanceTypeStatusId { get; set; }
public string ClassLevelCd { get; set; }
public int? StudentDailyAttendanceId { get; set; }
public int? AbsentReasonId { get; set; }
public string AttendanceTypeStatusCD { get; set; }
public string Name { get; set; }
public string LoggedInUser { get; set; }
public string ImageValue { get; set; }
public string FirstName { get; set; }
}
This is the method in ViewModel in to change specific item text
public void SetBtnText(object sender)
{
var view = sender as Xamarin.Forms.Button;
if (view.Text == "P")
{
view.Text = "A";
AbsentReasonId = "3001";
AttendanceTypeStatusCD= "Absent";
AttendanceTypeStatusId = "3002";
}
else if (view.Text == "A")
{
view.Text = "L";
AbsentReasonId= "2001";
AttendanceTypeStatusCD = "Late";
AttendanceTypeStatusId = "2002";
}
else
{
view.Text = "P";
AbsentReasonId = "4001";
AttendanceTypeStatusCD = "Present";
AttendanceTypeStatusId = "4002";
}
}
//Above used properties
private string _absentReasonId;
public string AbsentReasonId
{
get { return _absentReasonId; }
set { SetProperty(ref _absentReasonId, value); }
}
private string _attendanceTypeStatusCD;
public string AttendanceTypeStatusCD
{
get { return _attendanceTypeStatusCD; }
set { SetProperty(ref _attendanceTypeStatusCD, value); }
}
private int _attendanceTypeStatusId;
public int AttendanceTypeStatusId
{
get{return _attendanceTypeStatusId;}
set { SetProperty(ref _attendanceTypeStatusId, value); }
}
The above process is not working, SutdentList source not getting changed, How can I do that using MVVM?
Student list screenshot
Need some direction/help here guys. Similar to a basic contacts app - I'm building a customer entry screen and need a drop down for contact types (phone, email, etc). I figured out how to populate the picker(s) by explicitly defining the path and source but I can't seem to get SelectedItem to do anything. My expectation is set the default value of the picker with whats in the record and also be able to change that value.
<ListView x:Name="ContactListView" ItemsSource="{Binding Customer.ContactList}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout>
<Picker
ItemsSource="{Binding Path=BindingContext.ContactTypes, Source={x:Reference ContactListView} }"
ItemDisplayBinding="{Binding TypeName}"
SelectedItem="{Binding TypeName, Mode=TwoWay}"
/>
<Entry Text="{Binding Value}" />
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The ViewModel attached to this page is a Customer object which has a nested contact list in it (defined at the list view). Below is a basic version of the Customer Class that I'm using on the page with its relationship to ContactTypes.
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string AddressLine { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
public List<Contact> ContactList { get; set; }
}
public class ContactType
{
public string TypeName { get; set; }
public int SortOrderId { get; set; }
}
public class Contact : ContactType
{
public int Id { get; set; }
public string Value { get; set; }
}
When the Page ViewModel loads, I store a list of possible ContactTypes (one time) that the user can choose from and it's shared in each picker as the item source. The list of possible ContactTypes from the database are stored in a local variable - here's the static representation of it:
public IList<ContactType> ContactTypes { get; } = new List<ContactType>
{
new ContactType(){ TypeName = "Home Phone", SortOrderId = 1 },
new ContactType(){ TypeName = "Cell Phone", SortOrderId = 2 },
new ContactType(){ TypeName = "Work Phone", SortOrderId = 3 },
new ContactType(){ TypeName = "Email", SortOrderId = 4 },
new ContactType(){ TypeName = "Fax", SortOrderId = 5 }
};
I need the picker to show the options from ContactTypes, and when an Item is Selected, it updates the TypeName property of the current record iteration in ContactList.
I am having some difficulty in getting the selected item binded to a picker. I have been through various answers, but none of it working for me. Here is my code
My XAML
`<Picker x:Name="mobListPicker"
Style="{StaticResource PickerOrangeStyle}" Title="Select Mob"
HeightRequest="50" ItemsSource="{Binding ProductList, Mode=TwoWay}"
ItemDisplayBinding="{Binding ProductNo}"
SelectedItem="{Binding SelectedProduct,Mode=TwoWay}">
</Picker>`
Property for the selected item
private Product _selectedProduct;
public Product SelectedProduct
{
get { return _selectedProduct; }
set { SetProperty(ref _selectedProduct, value); }
}
It will be awesome if someone can help me identify the error.
I made this simple demo-project about using Picker and MVVM binding. As Item source I use one ObservableCollection of type Person.
When user select one of the items from Picker, value/content of labels bellow is changed. Please take a look at it I think this project is what you need to resolve your issue.
You are not providing us your whole code so it can be hard to see your possible erros. Maybe this can be helpful for you.
Demo:
Code snippets:
My Person class looks like this:
public class Person {
public int PersonId { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public string FullName { get { return $"{FName} {LName}"; } }
public string Biography { get; set; }
}
My ViewModel:
public class AllPersonsViewModel : INotifyPropertyChanged{
public ObservableCollection<Person> AllPersons { get; set; }
private Person selectedPerson;
public Person SelectedPerson {
get { return selectedPerson; }
set { selectedPerson = value;
OnPropertyChanged();
}
}
public AllPersonsViewModel() {
AllPersons = new ObservableCollection<Person>() {
new Person() {
Biography = "Lorem ipsum person 1",
FName = "Person",
LName = "One",
PersonId = 1,
},
new Person() {
Biography = "Lorem ipsum person 2",
FName = "Person",
LName = "Two",
PersonId = 2,
},
new Person() {
Biography = "Lorem ipsum person 3",
FName = "Person",
LName = "Three",
PersonId = 3,
},
};
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName]string propertyName = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
I have one view which use this view-model as BindingContext
... and XAML of my page with Picker control is here:
<?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="XF.Picker.Demo.Views.PersonsPage">
<ContentPage.Content>
<StackLayout Orientation="Vertical">
<Picker Title="All person"
ItemDisplayBinding="{Binding FullName}"
ItemsSource="{Binding AllPersons}"
SelectedItem="{Binding SelectedPerson}"/>
<!-- Margin just to see picker dropdown and labels at the same time-->
<Label Text="{Binding SelectedPerson.FullName}" Margin="0,80,0,0"/>
<Label Text="{Binding SelectedPerson.Biography}"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
I published this code project on github you can find it here
I am trying to bind the values for a picker from a model in view model, there I am getting path of the model instead of the values.
<Picker x:Name="LocationPicker"
Title="Location" HeightRequest="40"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
SelectedItem="{Binding Location}"
ItemsSource="{Binding MaintainRoomTypes}"/>
Here is my view model code:
if (jobDetailsForFitter != null)
{
WindowDetails = new WindowDetailsModel
{
Windows = jobDetailsForFitter.Windows,
Locations = jobDetailsForFitter.Locations,
RoomTypes = jobDetailsForFitter.RoomTypes,
AddFiles = jobDetailsForFitter.AddFiles
};
Locations = jobDetailsForFitter.Locations;
MaintainRoomTypes = jobDetailsForFitter.RoomTypes;
await FitterService.Instance.LoadJobDetailsToLocalStore(jobDetailsForFitter, SelectedJob?.Id ?? 0);
}
how to bind itemsource to get list.
public List<Room> Locations { get; set; }
public List<RoomTypeModel> RoomTypes { get; set; }
You have to define ItemDisplayBinding property to Picker.
For eg:
public class Room
{
public string RoomNumber { private set; get; }
public string RoomName { private set; get; }
}
And you want to display RoomName in Picker
<Picker ItemsSource="{Binding Room}" ItemDisplayBinding="{Binding RoomName}"/>
Hope this will solve your problem.
Binding in the collection Items works perfectly, but when I try to Binding the variable Count does not work, could anyone help me with this?
<Label Text="{Binding Count}" TextColor="#4F4F4F" FontSize="10" FontAttributes="Bold"/>
I did a test, moving the Label out of the ListView and it worked perfect, but I need it to work from within the Listview.
ViewModel:
class ListViewModel : INotifyPropertyChanged
{
public ObservableCollection<Item> Items { get; }
public ListViewModel()
{
Items = new ObservableCollection<Item>(new[]
{
new Item { Text = "Test 1", Detail = "Detail 1", Foto = "computer2.png" },
new Item { Text = "Test 2", Detail = "Detail 2", Foto = "computer4.png" },
});
private int count = 1;
public int Count
{
get { return count; }
set
{
count = value;
OnPropertyChanged();
}
}
XAML:
<ListView
ItemsSource="{Binding Items}"
<ListView.Header>
<StackLayout>
<Label Text="{Binding Count}"
TextColor="#4F4F4F" FontSize="10"
FontAttributes="Bold"/>
</StackLayout>
</ListView.Header>
</ListView>
try something like the following. Also i'm assuming what you've posted isn't your full code, as we can't see your implementation of OnPropertyChanged or how you are setting the count.
<ContentPage
//BlahBlah Headings
x:Name="PageName">
<ListView ItemsSource="{Binding Items}">
<ListView.Header>
<StackLayout>
<Label Text="{Binding Source={x:Reference PageName}, Path=BindingContext.Count}"
TextColor="#4F4F4F" FontSize="10"
FontAttributes="Bold"/>
</StackLayout>
</ListView.Header>
</ListView>
</ContentPage>
I have done this little repo and it works without particular bindings
ViewModel + Model
namespace TestRelativeLayout.ViewModels
{
[ImplementPropertyChanged]
public class MyPage4ViewModel
{
public ObservableCollection<Item> Items { get; set; }
public int Counter { get; set; } = 111;
public string MyCounterFooter { get; set; } = "888";
public MyPage4ViewModel() {
Items = new ObservableCollection<Item>(new[]
{
new Item { Text = "Test 1", Detail = "Detail 1", Foto = "computer2.png" },
new Item { Text = "Test 2", Detail = "Detail 2", Foto = "computer4.png" },
});
}
public class Item
{
public string Detail { get; set; }
public string Foto { get; set; }
public string Text { get; set; }
}
}
}
Xaml
namespace TestRelativeLayout.ViewModels
{
[ImplementPropertyChanged]
public class MyPage4ViewModel
{
public ObservableCollection<Item> Items { get; set; }
public int Counter { get; set; } = 111;
public string MyCounterFooter { get; set; } = "888";
public MyPage4ViewModel() {
Items = new ObservableCollection<Item>(new[]
{
new Item { Text = "Test 1", Detail = "Detail 1", Foto = "computer2.png" },
new Item { Text = "Test 2", Detail = "Detail 2", Foto = "computer4.png" },
});
}
public class Item
{
public string Detail { get; set; }
public string Foto { get; set; }
public string Text { get; set; }
}
}
}