dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.27k stars 1.76k forks source link

Picker ItemDisplayBinding doesn't support MVVM properly #25634

Open stephenquan opened 3 weeks ago

stephenquan commented 3 weeks ago

Description

(Moved from https://github.com/dotnet/maui/discussions/25565)

The binding reference by Picker.ItemDisplayBinding appears to cache results from the MVVM and doesn't react to subsequent changes. To reproduce this, I created a small test application with a CollectionView and a Picker where the CollectionView does react to the MVVM changes but the Picker does not.

Steps to Reproduce

  1. Create a new .NET MAUI application
  2. Create a view model, e.g. Person
  3. Create sample data, e.g. People
  4. Update the view model in a loop, e.g. a 1 second timer
  5. Hook up the view model to both a CollectionView and a Picker
  6. The CollectionView reacts to the property changes whilst the Picker is stuck on the initial value
<!-- MainPage.xaml -->
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="MauiPickerMVVM.MainPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MauiPickerMVVM"
    x:Name="this"
    x:DataType="local:MainPage"
    BindingContext="{Reference this}">
    <ScrollView>
        <VerticalStackLayout Padding="30,0" Spacing="25">
            <Label Text="Picker (bug)" />
            <Picker x:Name="picker" ItemDisplayBinding="{Binding DisplayName}" ItemsSource="{Binding People}" />
            <Label Text="CollectionView (Ok)" />
            <CollectionView ItemsSource="{Binding People}">
                <CollectionView.ItemTemplate>
                    <DataTemplate x:DataType="local:Person">
                        <Label Text="{Binding DisplayName}" />
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>
using CommunityToolkit.Mvvm.ComponentModel;
using System.Collections.ObjectModel;
namespace MauiPickerMVVM;
public partial class Person : ObservableObject
{
    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(DisplayName))]
    string firstName = "FirstName";
    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(DisplayName))]
    string lastName = "LastName";
    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(DisplayName))]
    string timeStamp = "HH:mm:ss";
    public string DisplayName => $"[{TimeStamp}] {FirstName} {LastName}";
}
public partial class MainPage : ContentPage
{
    public ObservableCollection<Person> People { get; } = new()
    {
        new Person { FirstName = "John", LastName = "Doe" },
        new Person { FirstName = "Jane", LastName = "Smith" },
        new Person { FirstName = "Sam", LastName = "Johnson" }
    };
    IDispatcherTimer timer;
    public MainPage()
    {
        InitializeComponent();
        timer = Dispatcher.CreateTimer();
        timer.Interval = TimeSpan.FromSeconds(1);
        timer.Tick += (s, e) =>
        {
            foreach (var person in People)
            {
                person.TimeStamp = DateTime.Now.ToString("HH:mm:ss");
                // picker.ItemDisplayBinding = new Binding("DisplayName"); // Uncomment: Workaround
            }
        };
        timer.Start();
    }
}

The screen recording shows the CollectionView values changing but the Picker values are stuck on their initial value.

PickerBug

Link to public reproduction project repository

https://github.com/stephenquan/MauiPickerMVVM

Version with bug

8.0.92 SR9.2

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

Windows, Android, iOS

Affected platform versions

No response

Did you find any workaround?

As a workaround, when the view model updates, you have to reset picker.ItemDisplayBinding, e.g.

picker.ItemDisplayBinding = new Binding("DisplayName"); // Uncomment: Workaround

PickerWorkaround

Relevant log output

No response

similar-issues-ai[bot] commented 3 weeks ago

We've found some similar issues:

If any of the above are duplicates, please consider closing this issue out and adding additional context in the original issue.

Note: You can give me feedback by 👍 or 👎 this comment.

jaosnz-rep commented 3 weeks ago

I can repro this issue at Windows platform on the latest 17.12.0 preview 5(9.0.10-ci.net9.24553.1 & 9.0.0-rc.2.24503.2 & 8.0.92 & 8.0.91).

W4lm4s commented 1 week ago

Hi, I faced the same issue ; The workaround is working.

Thank you @stephenquan