I'm writing a page in Xamarin, and I'm having issue binding to ItemDisplayBinding in the Picker. The code that I have is showing the main components of what I am trying to do to bind it. I am able to set ItemsSource="{Binding terms}" but if I try to set ItemDisplayBinding="{Binding Name}", Visual Studio says "Member not found in data context 'SearchViewModel' and the Picker is not being populated. All of the solutions I looked at haven't helped me to solve this.
My Term model (in the models folder):
namespace ClassSearch.Models
{
public class Term
{
public string Code { get; set; }
public string Name { get; set; }
public Term(string code, string name)
{
Code = code;
Name = name;
}
}
}
My ViewPage:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ClassSearch.Views.SearchPage"
xmlns:viewmodel="clr-namespace:ClassSearch.ViewModels"
x:DataType="viewmodel:SearchViewModel"
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Page.UseSafeArea="True">
<ContentPage.BindingContext>
<viewmodel:SearchViewModel/>
</ContentPage.BindingContext>
<ContentPage.Content>
<Grid>
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
...
</Grid.RowDefinitions>
<Frame Style="{StaticResource FrameStyle}" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="0">
<Picker Title="Select"
ItemsSource="{Binding Terms}"
IsEnabled="{Binding IsNotBusy}"
/>
</Frame>
</Grid>
</ContentPage.Content>
</ContentPage>
My view Model:
public class SearchViewModel : ViewModelBase
{
public ObservableRangeCollection<Term> Terms { get; set; }
public SearchViewModel()
{
Terms = new ObservableRangeCollection<Term>();
}
public async Task GetCurrentTerms()
{
IsBusy = true;
Terms = Terms ?? await CurrentTerm.GetTerms();
IsBusy = false;
}
}
SearchPage.xaml.cs has the OnAppearing() overridden with
protected override async void OnAppearing()
{
base.OnAppearing();
if (BindingContext is SearchViewModel vm)
{
await vm.GetCurrentTerms();
}
}
It appears this is the code causing the problem, but I don't see what the issue is.
public static class CurrentTerm
{
public static async Task<ObservableRangeCollection<Term>> GetTerms()
{
ObservableRangeCollection<Term> terms = new ObservableRangeCollection<Term>();
// YYYY/MM/DD
DateTime currentDay = DateTime.Now.Date;
DateTime SummerCheck = new DateTime(currentDay.Year, 11, 01);
DateTime SpringCheck = new DateTime(currentDay.Year, 10, 01);
DateTime FallCheck = new DateTime(currentDay.Year, 03, 01);
if ((currentDay - SummerCheck).Days > 0)
{
var s = $"2{currentDay.Year % 100 1}4";
var sp = $"2{currentDay.Year % 100 1}1";
terms.Add(new Term(s, $"Summer {currentDay.Year 1}"));
terms.Add(new Term(sp, $"Spring {currentDay.Year 1}"));
}
else if ((currentDay - SpringCheck).Days > 0)
{
var sp = $"2{currentDay.Year % 100 1}1";
var f = $"2{currentDay.Year % 100}7";
terms.Add(new Term(sp, $"Spring {currentDay.Year 1}"));
terms.Add(new Term(f, $"Fall {currentDay.Year}"));
}
else if ((currentDay - FallCheck).Days > 0)
{
var f = $"2{currentDay.Year % 100}7";
var s = $"2{currentDay.Year % 100}4";
terms.Add(new Term(f, $"Fall {currentDay.Year}"));
terms.Add(new Term(s, $"Summer {currentDay.Year}"));
}
return terms;
}
}
CodePudding user response:
Due to i do not have the CurrentTerm.GetTerms()
, i make a sample with adding data directly in GetCurrentTerms
method for your reference.
Xaml:
<ContentPage.BindingContext>
<viewmodel:SearchViewModel/>
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout>
<Picker Title="Select"
ItemsSource="{Binding Terms}"
ItemDisplayBinding="{Binding Name}"
/> <!--IsEnabled="{Binding IsNotBusy}"-->
</StackLayout>
</ContentPage.Content>
ViewModel:
public class SearchViewModel : ViewModelBase
{
public ObservableRangeCollection<Term> Terms { get; set; }
public SearchViewModel()
{
Terms = new ObservableRangeCollection<Term>();
}
public async Task GetCurrentTerms()
{
//IsBusy = true;
//Terms = Terms ?? await CurrentTerm.GetTerms();
//IsBusy = false;
Term term1 = new Term("1", "a");
Term term2 = new Term("2", "b");
Term term3 = new Term("3", "c");
Terms.Add(term1);
Terms.Add(term2);
Terms.Add(term3);
}
}
Update:
Remove the code in OnAppearing
. Set the data in ViewModel like below.
public static class CurrentTerm
{
public static ObservableRangeCollection<Term> terms { get; set; }
static CurrentTerm()
{
terms = new ObservableRangeCollection<Term>();
// YYYY/MM/DD
DateTime currentDay = DateTime.Now.Date;
DateTime SummerCheck = new DateTime(currentDay.Year, 11, 01);
DateTime SpringCheck = new DateTime(currentDay.Year, 10, 01);
DateTime FallCheck = new DateTime(currentDay.Year, 03, 01);
if ((currentDay - SummerCheck).Days > 0)
{
var s = $"2{currentDay.Year % 100 1}4";
var sp = $"2{currentDay.Year % 100 1}1";
terms.Add(new Term(s, $"Summer {currentDay.Year 1}"));
terms.Add(new Term(sp, $"Spring {currentDay.Year 1}"));
}
else if ((currentDay - SpringCheck).Days > 0)
{
var sp = $"2{currentDay.Year % 100 1}1";
var f = $"2{currentDay.Year % 100}7";
terms.Add(new Term(sp, $"Spring {currentDay.Year 1}"));
terms.Add(new Term(f, $"Fall {currentDay.Year}"));
}
else if ((currentDay - FallCheck).Days > 0)
{
var f = $"2{currentDay.Year % 100}7";
var s = $"2{currentDay.Year % 100}4";
terms.Add(new Term(f, $"Fall {currentDay.Year}"));
terms.Add(new Term(s, $"Summer {currentDay.Year}"));
}
}
}
ViewModel:
public class SearchViewModel : ViewModelBase
{
public ObservableRangeCollection<Term> Terms { get { return CurrentTerm.terms; } }
public SearchViewModel()
{
}
//public async Task GetCurrentTerms()
//{
// //IsBusy = true;
// //Terms = Terms ?? await CurrentTerm.GetTerms();
// //IsBusy = false;
// //Term term1 = new Term("1", "a");
// //Term term2 = new Term("2", "b");
// //Term term3 = new Term("3", "c");
// //Terms.Add(term1);
// //Terms.Add(term2);
// //Terms.Add(term3);
//}
}