Here is my code.
List<DriverStatusViewModel> driverStatus = PopulateDriverStatus();
var selectedStatus = driverStatus.FirstOrDefault();
var picker = new Picker { Title = "Select a status" };
picker.SetBinding(Picker.ItemsSourceProperty, "driverStatus");
picker.SetBinding(Picker.SelectedItemProperty, "selectedStatus");
picker.ItemDisplayBinding = new Binding("Status");
Populate the List
private List<DriverStatusViewModel> PopulateDriverStatus()
{
var driverStatus = new List<DriverStatusViewModel>();
var stat1 = new DriverStatusViewModel();
stat1.EnumId = 1;
stat1.Status = "At Lunch";
driverStatus.Add(stat1);
var stat2 = new DriverStatusViewModel();
stat2.EnumId = 2;
stat2.Status = "Break";
driverStatus.Add(stat2);
var stat3 = new DriverStatusViewModel();
stat3.EnumId = 3;
stat3.Status = "Delivering";
driverStatus.Add(stat3);
return driverStatus;
}
Xaml codes for display
<Picker Title="Select a status"
ItemsSource="{Binding driverStatus}"
TextColor="Black"
BackgroundColor="Red"
ItemDisplayBinding="{Binding Name}"
SelectedItem="{Binding selectedStatus}" />
Below image is how it looks like when running in emulator
Im very new to Xamarin, Please help me and Thank you in advance.
In Xaml, add x:Name="pic":
<Picker Title="Select a monkey"
TextColor="Black"
x:Name="pic"
BackgroundColor="Red"
ItemDisplayBinding="{Binding Name}"
SelectedItem="{Binding selectedStatus}"/>
In your page add:
pic.ItemsSource = driverStatus;
The problem is that when you set a Binding in code, the string cannot "point" to a local variable. The binding is evaluated at runtime, so there would have to be a property with the name driverStatus and selectedDriver in the view model.
So instead of setting it as a local variable, create two properties DriverStatus and SelectedDriver and bind to them. Also you probably want to use INotifyPropertyChanged so that the UI is notified when the property values change.
This is what I did to solve the Picker.
//ViewModel
public class DriverStatusViewModel : INotifyPropertyChanged
{
List<DriverStatus> statusList;
public List<DriverStatus> StatusList
{
get { return statusList; }
set
{
if (statusList != value)
{
statusList = value;
OnPropertyChanged();
}
}
}
public string Title { get; set; }
DriverStatus selectedStatus;
public DriverStatus SelectedStatus
{
get { return selectedStatus; }
set
{
if (selectedStatus != value)
{
selectedStatus = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
//Model
public class DriverStatus
{
public int E_Id { get; set; }
public string E_Name { get; set; }
}
//cs file
BindingContext = new DriverStatusViewModel
{
StatusList = PopulateDriverStatus()
};
//adding Static data for DriverStatus
private List<DriverStatus> PopulateDriverStatus()
{
var driverStatus = new List<DriverStatus>();
var stat1 = new DriverStatus();
stat1.E_Id = 1;
stat1.E_Name = "At Lunch";
driverStatus.Add(stat1);
var stat2 = new DriverStatus();
stat2.E_Id = 2;
stat2.E_Name = "Break";
driverStatus.Add(stat2);
var stat3 = new DriverStatus();
stat3.E_Id = 3;
stat3.E_Name = "Delivering";
driverStatus.Add(stat3);
return driverStatus;
}
//XAML file
<Picker x:Name="picker"
Title="Select new status"
TextColor="Black"
HorizontalOptions="Start"
ItemsSource="{Binding StatusList}"
ItemDisplayBinding="{Binding E_Name}"
SelectedItem="{Binding SelectedStatus}"/>
<Label Text="{Binding SelectedStatus.E_Id}" IsVisible="False" x:Name="E_Id"/>
Special thanks to this answer Xamarin Forms Picker Binding I followed what he did.
Related
My picker stays empty. I already created a test list to test it in particular but it doesn't work either.
this is my XAML
<Picker x:Name="picker1" Grid.Row="1" Grid.Column="1" ItemsSource="{Binding TestList}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding AdditionSort}"/>
this is my code behind
List<AdditionSort> TestList
{
get => testList;
set => SetValue(ref testList, value);
}
List<AdditionSort> testList = new List<AdditionSort>();
void LoadList()
{
TestList.Add(new AdditionSort { Name = "test1" });
TestList.Add(new AdditionSort { Name = "test2" });
}
when I'm debugging I can see that my list is correct.
1)Use System.Generics.ObjectModel.ObservableCollection instead of List.
ObservableCollection notifies View on CollectionChanges where as List doesnot do that.
(Or)
2) Add items to List at initialization of List
List<AdditionSort> testList = new List<AdditionSort>()
{
new AdditionSort(),
new AdditionSort(),
new AdditionSort(),
new AdditionSort(),
}
I wrote a demo to make the binding work and you can check the code:
In code behind:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
myModel m = new myModel();
BindingContext = m;
}
}
public class myModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
List<AdditionSort> testList = new List<AdditionSort>();
public List<AdditionSort> TestList
{
get { return testList; }
set
{
testList = value;
OnPropertyChanged();
}
}
public myModel() {
LoadList();
}
void LoadList()
{
TestList.Add(new AdditionSort { Name = "test1" });
TestList.Add(new AdditionSort { Name = "test2" });
}
}
public class AdditionSort
{
public string Name { get; set; }
}
And in Xaml:
<StackLayout>
<!-- Place new controls here -->
<Picker x:Name="picker1" ItemsSource="{Binding TestList}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding AdditionSort}"/>
</StackLayout>
I uploaded my sample project here.
Also, here is the document: Setting a Picker's ItemsSource Property
I am relatively new to MVVM and I want to bind my view to the view model. I have a lot of code to move from the CodeBehind into the ViewModel class.
What I would like to do is binding the ComboBox Events to the corresponding ViewModel ICommand methods. I want the ComboBox to show "CompanyB" when the view loads and when I make a selection, the ComboBox should give me "CompanyA", "CompanyB" and "CompanyC" as options to select from.
After a company was selected, the values of the 2 textboxes below
Nachbest.Empf_Ansprechpartner
Nachbest.Empfaenger_Mail
must change accordingly.
The problem is with my code both the ComboBox and the textboxes remain empty and there is also nothing to choose from inside the combobox.
Could you please help me find what I am missing here? Thanks in advance for any help!
XAML (neueNachbestellung.xaml):
<Window xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<Grid>
<StackPanel Grid.Column="0" Margin="25,25,0,0" x:Name="leftStPnl">
<ComboBox x:Name="cboxEmpfaenger"
ItemsSource="{Binding Empf}"
Text="{Binding Empfaenger}"
FontSize="12" Width="150" Margin="118,0,0,0"
SelectedItem="{Binding SelValue}">
</ComboBox>
<TextBox x:Name="txtEmpfAnsprechpartner" Text="{Binding Empf_Ansprechpartner}" FontSize="12" IsEnabled="False" Width="150" Margin="50,0,0,0"/>
<TextBox x:Name="txtEmpfMail" Text="{Binding Empfaenger_Mail}" FontSize="12" IsEnabled="False" Width="150" Margin="73,0,0,0"/>
</StackPanel>
</Grid>
</Window>
Code Behind (neueNachbestellung.xaml.cs):
public neueNachbestellung(string someId)
{
InitializeComponent();
this.DataContext = new neueNachbestellungViewModel(someId);
}
View Model(neueNachbestellungViewModel.cs):
public class neueNachbestellungViewModel: INotifyPropertyChanged
{
public ICommand LoadCombobox => new DelegateCommand<object>(ExecuteLoadCombobox);
public ICommand ComboboxSelectionChanged => new DelegateCommand<object>(ExecuteComboboxSelectionChanged);
public Nachbestellung Nachbest { get; set; }
private object someObject;
private ObservableCollection<string> _empf;
public ObservableCollection<string> Empf
{
get { return _empf; }
set
{
_empf = value;
OnPropertyChanged("Empf");
}
}
private string _selValue = "12";
public string SelValue
{
get { return _selValue; }
set
{
_selValue = value;
OnPropertyChanged("SelValue");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public neueNachbestellungViewModel(string id)
{
this.Artikel = new ArtikelViewModel();
this.ArtikelList = new ObservableCollection<Artikel>();
InitializeReorderModel(id);
ExecuteComboboxSelectionChanged(someObject);
}
public void InitializeReorderModel(string id)
{
//set the MODEL
this.Nachbest = new Nachbestellung();
//Retrieve and set some values on *VIEW LOAD*!
var dbOracle = new Datenbank();
this.Nachbest.Bv = dbOracle.GetBauvorhaben(hv);
this.Nachbest.Hv = hv;
this.Nachbest.Bauleiter = dbOracle.GetBauleiter(hv);
this.Nachbest.Projektleiter = dbOracle.GetProjektleiter(hv);
}
private void ExecuteLoadCombobox(object param)
{
Empf = new ObservableCollection<string>()
{
"CompanyA",
"CompanyB",
"CompanyC"
};
//Company B is the standard selection on combobox load
Nachbest.Empf_Ansprechpartner = "CompanyB";
Nachbest.Empfaenger_Mail = "orders#companyB.com";
}
private void ExecuteComboboxSelectionChanged(object param)
{
Empf = new ObservableCollection<string>()
{
"CompanyA",
"CompanyB",
"CompanyC"
};
switch (SelValue)
{
case "CompanyA":
{
Nachbest.Empf_Ansprechpartner = "CompanyA";
Nachbest.Empfaenger_Mail = "service#companyA.com";
}
break;
case "CompanyB":
{
Nachbest.Empf_Ansprechpartner = "CompanyB";
Nachbest.Empfaenger_Mail = "orders#companyB.com";
}
break;
case "CompanyC":
{
Nachbest.Empf_Ansprechpartner = "CompanyC";
Nachbest.Empfaenger_Mail = "info#companyC.com";
}
break;
default:
MessageBox.Show("Something went wrong with the company selection!");
break;
}
}
}
View Fragment:
This is my quick & dirty solution. It does what it needs to and I don't have these click_button, selection_changed events inside my code behind anymore but inside my view model. That is all I need for now. Obviously not an elegant solution but it is working. I hope I can help some developers with it in the future who run into similar problems. Just a side note: The ICommand properties inside the view model are not necessary in this scenario but I am using them to handle button click events in the view. You can replace them with your own properties if you don't need the DelegateCommand class in your application.
XAML (neueNachbestellung.xaml):
<Window>
<Grid>
<StackPanel Grid.Column="0" Margin="25,25,0,0" x:Name="leftStPnl">
<ComboBox x:Name="cboxEmpfaenger"
ItemsSource="{Binding Empf}"
Text="{Binding Empfaenger}"
FontSize="12" Width="150" Margin="118,0,0,0"
SelectedItem="{Binding SelValue}">
</ComboBox>
<TextBox x:Name="txtEmpfAnsprechpartner" DataContext="{Binding Nachbest}" Text="{Binding Empf_Ansprechpartner}" FontSize="12" IsEnabled="False" Width="150" Margin="50,0,0,0"/>
<TextBox x:Name="txtEmpfMail" DataContext="{Binding Nachbest}" Text="{Binding Empfaenger_Mail}" FontSize="12" IsEnabled="False" Width="150" Margin="73,0,0,0"/>
</StackPanel>
</Grid>
</Window>
Code Behind (neueNachbestellung.xaml.cs):
public neueNachbestellung(string someId)
{
InitializeComponent();
this.DataContext = new neueNachbestellungViewModel(someId);
}
neueNachbestellungViewModel.cs:
public class neueNachbestellungViewModel: INotifyPropertyChanged
{
//public ICommand LoadCombobox => new DelegateCommand<object>(ExecuteLoadCombobox);
public ICommand ComboboxSelectionChanged => new DelegateCommand<object>(ExecuteComboboxSelectionChanged);
public Nachbestellung Nachbest { get; set; }
private object someObject; //DelegateCommand.cs requires an argument
private ObservableCollection<string> _empf;
public ObservableCollection<string> Empf
{
get { return _empf; }
set
{
_empf = value;
OnPropertyChanged("Empf");
}
}
private string _selValue = "CompanyB"; //default value
public string SelValue
{
get { return _selValue; }
set
{
_selValue = value;
OnPropertyChanged("SelValue");
switch (SelValue)
{
case "CompanyA":
{
Nachbest.Empf_Ansprechpartner = "CompanyA";
Nachbest.Empfaenger_Mail = "service#companyA.com";
}
break;
case "CompanyB":
{
Nachbest.Empf_Ansprechpartner = "CompanyB";
Nachbest.Empfaenger_Mail = "orders#companyB.com";
}
break;
case "CompanyC":
{
Nachbest.Empf_Ansprechpartner = "CompanyC";
Nachbest.Empfaenger_Mail = "info#companyC.com";
}
break;
default:
MessageBox.Show("Something went wrong with the company selection!");
break;
}
//setting the Empfaenger property here with the current selected value is necessary for the database insert later on!
Nachbest.Empfaenger = SelValue;
}
}
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public neueNachbestellungViewModel(string id)
{
this.Artikel = new ArtikelViewModel();
this.ArtikelList = new ObservableCollection<Artikel>();
InitializeReorderModel(id);
ExecuteComboboxSelectionChanged(someObject);
}
public void InitializeReorderModel(string id)
{
//set the MODEL
this.Nachbest = new Nachbestellung();
//Retrieve and set some values on *VIEW LOAD*!
var dbOracle = new Datenbank();
this.Nachbest.Bv = dbOracle.GetBauvorhaben(hv);
this.Nachbest.Hv = hv;
this.Nachbest.Bauleiter = dbOracle.GetBauleiter(hv);
this.Nachbest.Projektleiter = dbOracle.GetProjektleiter(hv);
}
private void ExecuteComboboxSelectionChanged(object param)
{
Empf = new ObservableCollection<string>()
{
"CompanyA",
"CompanyB",
"CompanyC"
};
Nachbest.Empf_Ansprechpartner = "CompanyB";
Nachbest.Empfaenger_Mail = "orders#companyB.com";
Nachbest.Empfaenger = SelValue; //if this is left out and there is no selection (just the default remaining unchanged!), Nachbest.Empfaenger will be null!
}
}
In our edit page, we have an issue to populate the value into Selected Item in picker and it won't select for some reason from the LoadCourses() or LoadRoundCategories() either.
Any ideas?
Here's the code:
ViewModel
public class EditGolfRoundViewModel : INotifyPropertyChanged
{
ApiServices _apiServices = new ApiServices();
private string _message;
private ObservableCollection<GolfCourse> _courses;
private ObservableCollection<GolfRoundCategory> _roundCategories;
private object_selectedGolfCourse;
private GolfRoundCategory _selectedGolfRoundCategory;
private GolfRound _golfRound;
public EditGolfRoundViewModel()
{
_selectedGolfCourse = new GolfCourse();
_selectedGolfRoundCategory = new GolfRoundCategory();
LoadCourses();
LoadRoundCategories();
}
public GolfRound GolfRound
{
get { return _golfRound; }
set
{
_golfRound = value;
OnPropertyChanged();
}
}
public string Message
{
get { return _message; }
set
{
_message = value;
OnPropertyChanged();
}
}
public ObservableCollection<GolfCourse> GolfCourses
{
get { return _courses; }
set
{
if (_courses != value)
{
_courses = value;
OnPropertyChanged();
}
}
}
public ObservableCollection<GolfRoundCategory> GolfRoundCategories
{
get { return _roundCategories; }
set
{
_roundCategories = value;
OnPropertyChanged();
}
}
public object SelectedGolfCourse
{
get { return _selectedGolfCourse; }
set
{
_selectedGolfCourse = value;
var golfCourse = _selectedGolfCourse as GolfCourse;
Guid tempGolfCourseID = golfCourse.GolfCourseID;
OnPropertyChanged("SelectedGolfCourse");
}
}
public GolfRoundCategory SelectedGolfRoundCategory
{
get { return _selectedGolfRoundCategory; }
set
{
_selectedGolfRoundCategory = value;
OnPropertyChanged();
}
}
public ICommand EditCommand
{
get
{
return new Command(async() =>
{
GolfRound.GolfCourseID = SelectedGolfCourse.GolfCourseID;
GolfRound.GolfCourse = SelectedGolfCourse;
GolfRound.GolfRoundCategoryID = SelectedGolfRoundCategory.GolfRoundCategoryID;
GolfRound.GolfRoundCategory = SelectedGolfRoundCategory;
GolfRound.LastModifiedUTC = System.DateTime.Now;
await _apiServices.PutGolfRoundAsync(GolfRound, Settings.AccessToken);
});
}
}
public ICommand DeleteCommand
{
get
{
return new Command(async () =>
{
await _apiServices.DeleteGolfRoundAsync(GolfRound.GolfRoundID, Settings.AccessToken);
});
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private async void LoadCourses()
{
GolfCourses = new ObservableCollection<GolfCourse>(await _apiServices.GetGolfCoursesAsync(Settings.AccessToken));
}
private async void LoadRoundCategories()
{
GolfRoundCategories = new ObservableCollection<GolfRoundCategory>(await _apiServices.GetGolfRoundCategoriesAsync(Settings.AccessToken));
}
}
View - XAML
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewModels="clr-namespace:AthlosifyMobile.ViewModels.Golf"
x:Class="AthlosifyMobile.Views.EditGolfRoundPage">
<StackLayout Orientation="Vertical" VerticalOptions="Center" Spacing="30" Padding="30">
<Entry Text="{Binding GolfRound.Name}" Placeholder="name" FontSize="Default" />
<Entry Text="{Binding GolfRound.Notes}" Placeholder="notes" FontSize="Default" />
<Entry Text="{Binding GolfRound.DailyHandicap}" Placeholder="daily handicap" FontSize="Default" />
<Label Text="Date" />
<DatePicker Date="{Binding GolfRound.TeeOffUTC}"
Format="D"
Margin="30, 0, 0, 30" />
<Picker x:Name="pCourse" Title="Course" ItemsSource="{Binding GolfCourses}"
SelectedItem="{Binding SelectedGolfCourse, Mode=TwoWay}"
ItemDisplayBinding="{Binding Name}"></Picker>
<Entry Text="{Binding GolfRound.GolfCourse.Name}" Placeholder="selected golf course" FontSize="Default" />
<Picker x:Name="pCategory" Title="Category" ItemsSource="{Binding GolfRoundCategories}"
SelectedItem="{Binding SelectedGolfRoundCategory, Mode=TwoWay}"
ItemDisplayBinding="{Binding Name}"></Picker>
<Entry Text="{Binding SelectedGolfRoundCategory.Name}" Placeholder="selected round category" FontSize="Default" />
<Button Command="{Binding EditCommand}" Text="Edit Round" />
<Button Command="{Binding DeleteCommand}" Text="Delete Round" />
<Label Text="{Binding Message}" ></Label>
</StackLayout>
View - code behind
public partial class EditGolfRoundPage : ContentPage
{
public EditGolfRoundPage (GolfRound round)
{
var editGolfRoundViewModel = new EditGolfRoundViewModel();
editGolfRoundViewModel.GolfRound = round;
BindingContext = editGolfRoundViewModel;
InitializeComponent ();
//var editGolfRoundViewModel = new EditGolfRoundViewModel();
//editGolfRoundViewModel.GolfRound = round;
//editGolfRoundViewModel.SelectedGolfCourse = round.GolfCourse;
//BindingContext = editGolfRoundViewModel;
}
}
Implement IEquatable for class of property used in SelectedItem:
public class GolfCourse : IEquatable<GolfCourse>
{
...
public bool Equals(GolfCourse other)
{
if (other == null) return false;
return (this.Name.Equals(other.Name));
}
}
Usage, assuming ItemsSource contains an object with value of Name as shown below:
SelectedGolfCourse = new GolfCourse { Name = "Course 2" };
The following is true as of Xamarin Forms v4.7.
See if you are doing this:
<Picker x:Name="DefaultEntitlement" Title="Entitlement"
SelectedItem="{Binding SelectedOwnerEntitlement, Mode=TwoWay}"
ItemsSource="{Binding OwnerEntitlements, Mode=TwoWay}">
</Picker>
Instead of this:
<Picker x:Name="DefaultEntitlement" Title="Entitlement"
ItemsSource="{Binding OwnerEntitlements, Mode=TwoWay}"
SelectedItem="{Binding SelectedOwnerEntitlement, Mode=TwoWay}">
</Picker>
you are binding view model before Initialise page so that is wrong thing we can not bind data without Initialise page fro that you need to change code of xaml.cs like below
public EditGolfRoundPage (GolfRound round)
{
InitializeComponent ();
BindingContext = editGolfRoundViewModel;
BindingContext.GolfRound = round;
}
that will work for you
Happy Coding :)
Xaml
<Picker x:Name="ProductPicker" WidthRequest="220" HeightRequest="35" Title="Select" ItemsSource="{Binding ProductList}" SelectedItem="{Binding ProductSelected}" ItemDisplayBinding="{Binding ProductName}"> </Picker>
ViewModel
public List<ProductModel> ProductList { get; set; }
Populating Data in Datasource in Viewmodel
ProductList = Products.Result.ToList();
Getting Selected Data
private object _ProductSelected;
public object ProductSelected
{
get { return _ProductSelected; }
set
{
_ProductSelected = value;
ProductSelected_SelectedIndex.Execute(value);
OnPropertyChanged("ProductSelected"); //in case you are using MVVM Light
}
}
private Command ProductSelected_SelectedIndex
{
get
{
return new Command((e) =>
{
}}}
private object _CitySelectedFromList;
public object CitySelectedFromList
{
get { return _CitySelectedFromList; }
set
{
_CitySelectedFromList = value;
var cityid = _CitySelectedFromList as CityMasterModel;
tempcityids = Convert.ToInt32(cityid.Id);
}
}
Can you try once replacing your Viewmodel. I have changed the type from Object to actual type. Set the Default item while loading the items from endpoint.
public class EditGolfRoundViewModel : INotifyPropertyChanged
{
ApiServices _apiServices = new ApiServices();
private string _message;
private ObservableCollection<GolfCourse> _courses;
private ObservableCollection<GolfRoundCategory> _roundCategories;
private GolfCourse _selectedGolfCourse;
private GolfRoundCategory _selectedGolfRoundCategory;
private GolfRound _golfRound;
public EditGolfRoundViewModel()
{
LoadCourses();
LoadRoundCategories();
}
public GolfRound GolfRound
{
get { return _golfRound; }
set
{
_golfRound = value;
OnPropertyChanged();
}
}
public string Message
{
get { return _message; }
set
{
_message = value;
OnPropertyChanged();
}
}
public ObservableCollection<GolfCourse> GolfCourses
{
get { return _courses; }
set
{
if (_courses != value)
{
_courses = value;
OnPropertyChanged();
}
}
}
public ObservableCollection<GolfRoundCategory> GolfRoundCategories
{
get { return _roundCategories; }
set
{
_roundCategories = value;
OnPropertyChanged();
}
}
public GolfCourse SelectedGolfCourse
{
get { return _selectedGolfCourse; }
set
{
_selectedGolfCourse = value;
OnPropertyChanged("SelectedGolfCourse");
}
}
public GolfRoundCategory SelectedGolfRoundCategory
{
get { return _selectedGolfRoundCategory; }
set
{
_selectedGolfRoundCategory = value;
OnPropertyChanged();
}
}
public ICommand EditCommand
{
get
{
return new Command(async () =>
{
GolfRound.GolfCourseID = SelectedGolfCourse.GolfCourseID;
GolfRound.GolfCourse = SelectedGolfCourse;
GolfRound.GolfRoundCategoryID = SelectedGolfRoundCategory.GolfRoundCategoryID;
GolfRound.GolfRoundCategory = SelectedGolfRoundCategory;
GolfRound.LastModifiedUTC = System.DateTime.Now;
await _apiServices.PutGolfRoundAsync(GolfRound, Settings.AccessToken);
});
}
}
public ICommand DeleteCommand
{
get
{
return new Command(async () =>
{
await _apiServices.DeleteGolfRoundAsync(GolfRound.GolfRoundID, Settings.AccessToken);
});
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private async void LoadCourses()
{
GolfCourses = new ObservableCollection<GolfCourse>(await _apiServices.GetGolfCoursesAsync(Settings.AccessToken));
if (GolfCourses != null && GolfCourses.Count() > 0)
SelectedGolfCourse = GolfCourses[0];
}
private async void LoadRoundCategories()
{
GolfRoundCategories = new ObservableCollection<GolfRoundCategory>(await _apiServices.GetGolfRoundCategoriesAsync(Settings.AccessToken));
if (GolfRoundCategories != null && GolfRoundCategories.Count() > 0)
SelectedGolfRoundCategory = GolfRoundCategories[0];
}
}
You can try:
make sure your prop support INotifyPropertyChanged
make sure Selected Item variable has initial value
try debug your selected item variable, make sure has value
1. Initials
Take a look your code:
public EditGolfRoundViewModel()
{
_selectedGolfCourse = new GolfCourse();
_selectedGolfRoundCategory = new GolfRoundCategory();
LoadCourses();
LoadRoundCategories();
}
If you try to initial value Selected Item, don't do this:
_selectedGolfCourse = new GolfCourse();
_selectedGolfRoundCategory = new GolfRoundCategory();
let it null, is fine. You can do like this:
SelectedGolfRoundCategory = new GolfRoundCategory();
//or
SelectedGolfRoundCategory = dataFromAPI;
2. Assign
Take a look your code:
public ICommand EditCommand
{
get
{
return new Command(async() =>
{
GolfRound.GolfCourseID = SelectedGolfCourse.GolfCourseID;
GolfRound.GolfCourse = SelectedGolfCourse;
GolfRound.GolfRoundCategoryID = SelectedGolfRoundCategory.GolfRoundCategoryID;
GolfRound.GolfRoundCategory = SelectedGolfRoundCategory;
GolfRound.LastModifiedUTC = System.DateTime.Now;
await _apiServices.PutGolfRoundAsync(GolfRound, Settings.AccessToken);
});
}
}
You trying selected item variable insert into to object GolfRound, like this part:
GolfRound.GolfRoundCategoryID = SelectedGolfRoundCategory.GolfRoundCategoryID;
GolfRound.GolfRoundCategory = SelectedGolfRoundCategory;
Make sure you have INotifyPropertyChanged implement this model GolfRound for prop GolfRoundCategoryID and GolfRoundCategory. If not, it would not work. I have experience for this.
Hope this helpful.
I have a listview with data from a list called actualmeterreading. In each row, there are a label and entry, both display data from the list. User can edit the data displayed in entry. How can I loop through the listview and get the data that user input in the entry?
Code for populating the listview.
list = new ListView
{
ItemsSource = actualmeterreading,
RowHeight = 50,
ItemTemplate = new DataTemplate(() =>
{
printDesc = new Label();
string desc = actualmeterreading[x].MachineMeterReadingList.Meterreadingdescription.Description;
printDesc.Text = desc;
meterreading = new Entry();
string reading = actualmeterreading[x].ActualReading.ToString();
meterreading.Text = reading;
meterreading.FontSize = 14;
x = x + 1;
//nameLabel2.WidthRequest = 300;
//nameLabel2.SetBinding(Entry.TextProperty, "");
// Return an assembled ViewCell.
return new ViewCell
{
View = new StackLayout
{
Padding = new Thickness(0, 5),
Orientation = StackOrientation.Horizontal,
Children =
{
new StackLayout
{
VerticalOptions = LayoutOptions.Center,
Spacing = 0,
Children =
{
printDesc,
meterreading
//nameLabel2
}
}
}
}
};
})
};
Loop through the listview on submit button click.
private void submitbtn_Clicked(object sender, EventArgs e)
{
int x = 0;
foreach (var c in list.ItemsSource)
{
int r = c.?
myactualreading = new actualmeterreading
{
ActualReading = r
};
x = x + 1;
dataservice.UpdateActualReading(myactualreading);
}
}
When I did some search, there was someone who mention to View models and two ways bindings. Does anyone have some solution regarding that one or any other solutions? Thank you
Refer the below code to achieve your requirement. Whenever the entry is edited, then it will be stored in model and label also will get reflected.
<ListView ItemsSource="{Binding Elements}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Entry Grid.Column="0" Text="{Binding Name,Mode=TwoWay}" />
<Label Grid.Column="1" Text="{Binding Name,Mode=TwoWay}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public partial class MainPage : ContentPage
{
ObservableCollection<Model> elements;
public ObservableCollection<Model> Elements
{
get { return elements;}
set { elements = value;}
}
public MainPage()
{
Elements = new ObservableCollection<Model>() { new Model() { Name = "One" }, new Model() { Name = "Two" } };
BindingContext = this;
InitializeComponent();
}
}
public class Model : INotifyPropertyChanged
{
string name;
public string Name
{
get { return name; }
set {
name = value;
NotifyPropertyChanged("Name");
}
}
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
I am trying to bind SelectedIndex of ListBox inside Pivot. Headers, Items are bind correctly, however, the ListBox SelectedIndex is somehow not working.
XAML
<Page.DataContext>
<local:ChapterMenuViewModel/>
</Page.DataContext>
<Pivot x:Name="pvMain" TitleTemplate="{StaticResource PivotTitleTemplate}"
HeaderTemplate="{StaticResource PivotHeaderTemplate}"
ItemsSource="{Binding ChapterMenuHeader}" SelectionChanged="pvMain_SelectionChanged">
<Pivot.ItemTemplate>
<DataTemplate>
<Grid Grid.Row="1" Grid.Column="0">
<ListBox FlowDirection="RightToLeft" FontFamily="./Fonts/ScheherazadeRegOT.ttf#Scheherazade"
x:Name="lsbChapter" ItemTemplate="{StaticResource ChapterItemTemplate}"
SelectedIndex="{Binding SelectedChapterIndex}"
ItemsSource="{Binding Chapters}">
</ListBox>
</Grid>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
MVVM
public class ChapterMenuViewModel : INotifyPropertyChanged
{
ObservableCollection<ChapterMenusHeader> _chapterMenuHeader;
DataSource ds = null;
public ChapterMenuViewModel()
{
ChapterMenuHeader = new ObservableCollection<ChapterMenusHeader>();
ds = new DataSource();
List<JuzDetail> allJuz = DataSource.GetAllJuz;
ChapterMenuHeader.Add(new ChapterMenusHeader() { Header = "chapter", Chapters = DataSource.GetAllChapter, Juzs = allJuz });
ChapterMenuHeader.Add(new ChapterMenusHeader() { Header = "location", Chapters = DataSource.GetAllChapterSortedByChapterType, Juzs = allJuz });
ChapterMenuHeader.Add(new ChapterMenusHeader() { Header = "order", Chapters = DataSource.GetAllChapterSortedByOrder, Juzs = allJuz });
ChapterMenuHeader.Add(new ChapterMenusHeader() { Header = "size", Chapters = DataSource.GetAllChapterSortedBySize, Juzs = allJuz });
ChapterMenuHeader.Add(new ChapterMenusHeader() { Header = "arabic name", Chapters = DataSource.GetAllChapterSortedByArabicAlphabet, Juzs = allJuz });
ChapterMenuHeader.Add(new ChapterMenusHeader() { Header = "english name", Chapters = DataSource.GetAllChapterSortedByEnglishAlphabet, Juzs = allJuz });
}
public ObservableCollection<ChapterMenusHeader> ChapterMenuHeader
{
get { return _chapterMenuHeader; }
set
{
if (_chapterMenuHeader != value)
{
_chapterMenuHeader = value;
OnPropertyChanged("ChapterMenuHeader");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ChapterMenusHeader : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public ChapterMenusHeader()
{
SelectedChapterIndex = App.Recent.ChapterID;
}
string _header;
public string Header
{
get { return _header; }
set
{
if (_header != value)
{
_header = value;
OnPropertyChanged("Header");
}
}
}
List<Chapter> _allChapters;
public List<Chapter> Chapters
{
get { return _allChapters; }
set
{
if (_allChapters != value)
{
_allChapters = value;
OnPropertyChanged("Chapters");
}
}
}
int _selectedChapterIndex;
public int SelectedChapterIndex
{
get { return _selectedChapterIndex; }
set
{
_selectedChapterIndex = value;
OnPropertyChanged("SelectedChapterIndex");
}
}
List<JuzDetail> allJuz;
public List<JuzDetail> Juzs
{
get { return allJuz; }
set
{
if (allJuz != value)
{
allJuz = value;
OnPropertyChanged("Juzs");
}
}
}
}
Scrolling Section
private void lsbChapter_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox lsb = sender as ListBox;
if (lsb.SelectedIndex != -1)
scrollIntoSelectedItem(lsb, lsb.SelectedIndex);
}
void scrollIntoSelectedItem(ListBox lsb, int index)
{
lsb.SelectionChanged -= lsbChapter_SelectionChanged;
lsb.SelectedIndex = lsb.Items.Count - 1;
lsb.UpdateLayout();
lsb.ScrollIntoView(lsb.SelectedIndex);
lsb.SelectedIndex = index;
lsb.UpdateLayout();
lsb.ScrollIntoView(index);
lsb.SelectionChanged += lsbChapter_SelectionChanged;
}
This is only portion of the ViewModel class where I am binding the SelectedIndex of ListBox.
The ListBox items are bind correctly, however, the SelectedIndex is not working.
How to set and scroll the SelectedIndex of ListBox in Pivot?
Thanks!
So turns out the issue is at this line -
SelectedIndex="{Binding SelectedChapterIndex}" ItemsSource="{Binding Chapters}"
You need to move the ItemsSource binding in front of the SelectedIndex one -
ItemsSource="{Binding Chapters}" SelectedIndex="{Binding SelectedChapterIndex}"
The reason? I suspect that it's because of the instantiation sequence of the two values. When the SelectedIndex is placed in front of the ItemsSource in xaml and assigned with a value in the constructor, the ItemsSource is still null, so nothing will be selected.
Now, to scroll to a particular item, you need to call the ScrollIntoView method on the ListBox. In your case, it should be
lsbChapter.ScrollIntoView(Chapters[SelectedChapterIndex]);