.netmvvmmauipicker

I need a picker in .NET MAUI to initialize to the current value of a term


I have a page that displays a list of terms. Each term has a status. See models:

public class Term : INotifyPropertyChanged
{
    [PrimaryKey, AutoIncrement]
    public int Term_ID { get; set; }
    public string Name { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }

    // Foreign Key
    private int _termStatus_ID;
    public int TermStatus_ID { get; set; }

    private TermStatus _status;
    [Ignore]
    public TermStatus Status
    {
        get => _status;
        set
        {
            if (_status != value)
            {
                _status = value;
                OnPropertyChanged();
            }
        }
    }

    [Ignore]
    public ObservableCollection<Course> Courses { get; set; }
    [Ignore]
    public int CourseCount
    {
        get
        {
            return Courses.Count;
        }
    }

    public event PropertyChangedEventHandler? PropertyChanged;
    // Raises the event when the property has changed
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

TermStatus:

public class TermStatus
{
    [PrimaryKey, AutoIncrement]
    public int TermStatus_ID { get; set; }
    public string StatusName { get; set; }
}

From my term list view, I can successfully pass the selected term object to my detailed view—the label for SelectedTerm.Name works, but the picker does not display the current status. It is blank when I navigate to the page.

    <Grid RowDefinitions="Auto, 70, Auto, 50"
          ColumnDefinitions="Auto, Auto"
          RowSpacing="10"
          ColumnSpacing="10"
          BackgroundColor="{StaticResource Light Grey}">

        <Image
            Source="dark_wgu_logo.png"
            Grid.ColumnSpan="2"
            WidthRequest="412"
            SemanticProperties.Description="WGU logo" />

        <Label
            Grid.ColumnSpan="2"
            Grid.Row="1"
            Text="{Binding SelectedTerm.Name}"
            Style="{StaticResource Headline}"
            SemanticProperties.HeadingLevel="Level1" />

        <Picker Grid.Row="2" Grid.ColumnSpan="2"
                ItemsSource="{Binding TermStatuses}"
                ItemDisplayBinding="{Binding StatusName}"
                SelectedItem="{Binding SelectedTerm.Status}"/>
    </Grid>

Here is the ViewModel that controls the TermDetail page.

[QueryProperty(nameof(SelectedTerm), nameof(SelectedTerm))]
public class DetailedTermViewModel : BaseViewModel
{
    private ITermService _termService;
    private ICourseService _courseService;
    public ObservableCollection<TermStatus> TermStatuses { get; set; }

    private Term _selectedTerm;
    public Term SelectedTerm
    {
        get => _selectedTerm;
        set
        {
            if (_selectedTerm != value)
            {
                _selectedTerm = value;
                OnPropertyChanged(nameof(SelectedTerm));
                OnPropertyChanged(nameof(SelectedTerm.Status));
            }
        }
    }

    public DetailedTermViewModel(ITermService termService, ICourseService courseService) 
    {
        _termService = termService;
        _courseService = courseService;
        _ = LoadDetailsAsync();
    }

    private async Task LoadDetailsAsync()
    {
        TermStatuses = new ObservableCollection<TermStatus>(await 
        _termService.GetAllStatuses());
        OnPropertyChanged(nameof(TermStatuses));
    }

How can I get the picker to display the term's current status? For example, if I select a term on the terms list page that has a status of "In progress," how can I get the picker to also display "In Progress" when the DetailTerm page is loaded?


Solution

  • Even though the SelectedTerm object is passed correctly and SelectedTerm.TermStatus_ID is available, the actual Status property (which the Picker binds to) is not being set to an object from the TermStatuses list. Since SelectedItem uses object reference comparison, it needs a reference from the ItemsSource, not just an object with matching properties.The Picker remains blank because the SelectedItem (i.e., SelectedTerm.Status) is never explicitly set to a matching item from the TermStatuses collection after loading.

       private async Task LoadDetailsAsync()
        {
            TermStatuses = new ObservableCollection<TermStatus>(await 
            _termService.GetAllStatuses());
            OnPropertyChanged(nameof(TermStatuses));
    
    // Match the selected term's status after loading statuses
      if (SelectedTerm != null)
        {
            SelectedTerm.Status = TermStatuses
           .FirstOrDefault(s => s.TermStatus_ID == SelectedTerm.TermStatus_ID);
    
            OnPropertyChanged(nameof(SelectedTerm));
        }
      }