Hi,
I'm having real trouble with the Picker binding in a Listview that it would be great to get some assistance with. I'll be retrieving ListView Items via an API and also adding Items to the ListView (and then saving via API).
Basically I have an List() as Picker ItemsSource as follows:
public class RFIOptionDto
{
public int RFIOptionId { get; set; }
public string Value { get; set; }
}
and so far I've ended up with the following as my ListView items:
public class TextCategoryDto : BindableBase
{
public IEnumerable<RFIOptionDto> RFIOptions { get; set; }
public int TextCategoryId { get; set; }
public int? RFIOptionId { get; set; }
private RFIOptionDto _selectedRFIOption;
public RFIOptionDto SelectedRFIOption
{
get { return _selectedRFIOption; }
set { SetProperty(ref _selectedRFIOption, (RFIOptions != null && RFIOptionId != null) ? RFIOptions.SingleOrDefault(c => c.RFIOptionId == RFIOptionId) : value); }
}
private string response;
public string Response
{
get { return response; }
set { SetProperty(ref response, value); }
}
}
Here's my ViewModel:
private DelegateCommand<TextCategoryDto> _entryUnfocusedCommand;
public DelegateCommand<TextCategoryDto> EntryUnfocusedCommand => _entryUnfocusedCommand ?? (_entryUnfocusedCommand = new DelegateCommand<TextCategoryDto>(EntryUnfocused));
private DelegateCommand<TextCategoryDto> _pickerUnfocusedCommand;
public DelegateCommand<TextCategoryDto> PickerUnfocusedCommand => _pickerUnfocusedCommand ?? (_pickerUnfocusedCommand = new DelegateCommand<TextCategoryDto>(PickerUnfocused));
public IEnumerable<RFIOptionDto> RFIOptions { get; set; }
private ObservableCollection<TextCategoryDto> textCategories;
public ObservableCollection<TextCategoryDto> TextCategories
{
get { return textCategories; }
set { SetProperty(ref textCategories, value); }
}
public async override void OnNavigatingTo(INavigationParameters parameters)
{
RFIOptions = parameters.GetValue<IEnumerable<RFIOptionDto>>("RFIOptions");
try
{
var apiResponse = RestService.For<IRFIRepository>(Settings.BaseURL, new RefitSettings()
{
AuthorizationHeaderValueGetter = () => Task.FromResult(Settings.AccessToken)
});
var rfiDto = await apiResponse.GetTextCategoriesForRFI(RFIId);
TextCategories = new ObservableCollection<TextCategoryDto>(rfiDto.TextCategories);
base.OnNavigatingTo(parameters);
}
catch (Exception ex)
{
}
}
private async void PickerUnfocused(TextCategoryDto textCategoryDto)
{
//Save TextCategory via API
}
private async void EntryUnfocused(TextCategoryDto textCategoryDto)
{
//Save TextCategory via API
}
And the ListView;
<ListView x:Name="textCategoriesListView" ItemsSource="{Binding TextCategories}"
HasUnevenRows="True"
VerticalOptions="FillAndExpand"
Margin="0,0,0,0"
SelectionMode="None"
CachingStrategy="RecycleElement"
Grid.Column="0"
Grid.Row="0">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell x:Name="textCategoryViewCell">
<ViewCell.View>
<StackLayout Margin="10,20,10,20">
<Picker Title="Select Category" TitleColor="#999999"
HorizontalOptions="FillAndExpand"
TextColor="#FFFFFF"
BackgroundColor="#4c5a63"
FontSize="14"
ItemsSource="{Binding RFIOptions}"
ItemDisplayBinding="{Binding Value}"
SelectedItem="{Binding SelectedRFIOption}">
<Picker.Behaviors>
<behaviors:EventHandlerBehavior EventName="Unfocused">
<behaviors:InvokeCommandAction Command="{Binding BindingContext.PickerUnfocusedCommand, Source={x:Reference Name=textCategoriesListView}}"
CommandParameter="{Binding .}"/>
</behaviors:EventHandlerBehavior>
</Picker.Behaviors>
</Picker>
<Label Text="Enter Value"
TextColor="#ea5c2d"
HorizontalOptions="Start" />
<Entry Placeholder="Enter Value"
PlaceholderColor="#999999"
FontSize="14"
Text="{Binding Response}"
TextColor="#FFFFFF"
BackgroundColor="#4c5a63">
<Entry.Behaviors>
<b:EventToCommandBehavior EventName="Unfocused"
Command="{Binding BindingContext.EntryUnfocusedCommand, Source={x:Reference Name=textCategoriesListView}}"
CommandParameter="{Binding .}"/>
</Entry.Behaviors>
</Entry>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
On the PickerUnfocused Command the the SelectedRFIOption doesn't show the changed Picker TextCategoryDto item:
textCategoryDto.RFIOptionId = textCategoryDto.SelectedRFIOption.RFIOptionId;
And it can't be right that I'm having to do the following on the setter of the SelectedRFIOption property in the TextCategoryDto:
private RFIOptionDto _selectedRFIOption;
public RFIOptionDto SelectedRFIOption
{
get { return _selectedRFIOption; }
set { SetProperty(ref _selectedRFIOption, (RFIOptions != null && RFIOptionId != null) ? RFIOptions.SingleOrDefault(c => c.RFIOptionId == RFIOptionId) : value); }
}
However if the SelectedRFIOption property is as follows:
public RFIOptionDto SelectedRFIOption
{
get { return _selectedRFIOption; }
set { SetProperty(ref _selectedRFIOption, value); }
}
The SelectedItem is not visible in the Picker for existing TextCategories from the API despite being set in the retrieved data. I saw this post by @DarkSummon which looks like it explains why:
But adding the override ToString() property made no difference.
Can anyone see anything obvious I'm missing? Any help much appreciated.