Home > Back-end >  MVVM ListView not updating despite Itemsource modification | XAMARIN FORMS, ANDROID
MVVM ListView not updating despite Itemsource modification | XAMARIN FORMS, ANDROID

Time:02-10

I would like to create an android Bluetooth scanner. But I can't manage to display anything using a listview. I've tried debugging it for an extended amount of time without success. It seems like the problem doesn't come from the Bluetooth segments. But rather comes from a refreshing/binding issue.

I'm debugging on a physical Android device, the permissions stuff should be ok since the devices list is updating but the linked list view isn't.

It might be worth mentioning that I've started from the visual studio 2019 Xamarin flyout template. Which, uses an app shell to navigate between the pages. I feel like the problem could also come from this since the app shell might mess with the view models links.

P.S: I am relatively new to MVVM.

Any help would be appreciated !!

I have the following code :

ItemPage (.XAML)

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="clavier.Views.ItemsPage"
                 Title="Devices"
                 x:Name="BrowseItemsPage">
    
        <ContentPage.Content>
            <StackLayout>
                <Button Text="Search" Command="{Binding SearchDeviceCommand}"/>
                <ListView x:Name="DevicesList"
                          ItemsSource="{Binding list, Mode=OneWay}"
                          IsPullToRefreshEnabled="True"
                          CachingStrategy="RecycleElement">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
                                <StackLayout>
                                    <Label Text="{Binding NativeDevice.Name}"></Label>
                                    <Label Text="{Binding NativeDevice.Address}" ></Label>
                                </StackLayout>
                            </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
                <Button Text="End"/>
            </StackLayout>
        </ContentPage.Content>
    </ContentPage>

ItemPage code (.XAML.CS)

namespace clavier.Views
    {
        public partial class ItemsPage : ContentPage
        {
            public ItemsPage()
            {
                BindingContext = new ItemsViewModel();
                InitializeComponent();
            }
        }
    }

ViewModel (.CS)

    ```
    namespace clavier.ViewModels
    {
        public class ItemsViewModel : BaseViewModel
        {
            public IAdapter adapter;
            public IBluetoothLE bluetoothBLE;
            public IDevice SelectedDevice { get; set; }
            public string Title { get; set; }
            public ObservableCollection<IDevice> list { get; set; }
            public Command SearchDeviceCommand { get; }
    
            public ItemsViewModel()
            {
                bluetoothBLE = CrossBluetoothLE.Current;
                adapter = CrossBluetoothLE.Current.Adapter;
                SearchDeviceCommand = new Command(SearchDevice);
                list = new ObservableCollection<IDevice>();
            }
    
            public async void SearchDevice()
            {
                if (bluetoothBLE.State == BluetoothState.Off)
                {
                    await Shell.Current.DisplayAlert("Attention", "le bluetooth n'est pas activé.", "OK");
                } 
                else 
                {
                    list.Clear();
                    adapter.ScanTimeout = 10000;
                    adapter.ScanMode = ScanMode.Balanced;
                    adapter.DeviceDiscovered  = (obj, a) =>
                    {
                        if (!list.Contains(a.Device))
                        {
                            list.Add(a.Device);
                        }
                    };
                    await adapter.StartScanningForDevicesAsync();
                }
            }
    
            public async void DevicesList_OnItemSelected()
            {
                var resullt = await Shell.Current.DisplayAlert("Alerte", "Vous êtes sur le point de vous connecter à cet appareil. Etes vosu sur de vouloir vous connecter ?","Se connecter", "Annuler");
    
                if (!resullt)
                {
                    return;
                }
                await adapter.StopScanningForDevicesAsync();
    
                try
                {
                    await adapter.ConnectToDeviceAsync(SelectedDevice);
                    await Shell.Current.DisplayAlert("Connection ...", "Status : "   SelectedDevice.State, "Ok");
                }
                catch (DeviceConnectionException ex)
                {
                    await Shell.Current.DisplayAlert("Erreur !", ex.Message, "Ok");
                }
            }
        }
    }
```

My app shell (.XAML)

```
<?xml version="1.0" encoding="UTF-8"?>
<Shell xmlns="http://xamarin.com/schemas/2014/forms" 
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:local="clr-namespace:clavier.Views"
       Title="clavier"
       x:Class="clavier.AppShell">

    <Shell.Resources>
        <ResourceDictionary>
            <Style x:Key="BaseStyle" TargetType="Element">
                <Setter Property="Shell.BackgroundColor" Value="{StaticResource Primary}" />
                <Setter Property="Shell.ForegroundColor" Value="White" />
                <Setter Property="Shell.TitleColor" Value="White" />
                <Setter Property="Shell.DisabledColor" Value="#B4FFFFFF" />
                <Setter Property="Shell.UnselectedColor" Value="#95FFFFFF" />
                <Setter Property="Shell.TabBarBackgroundColor" Value="{StaticResource Primary}" />
                <Setter Property="Shell.TabBarForegroundColor" Value="White"/>
                <Setter Property="Shell.TabBarUnselectedColor" Value="#95FFFFFF"/>
                <Setter Property="Shell.TabBarTitleColor" Value="White"/>
            </Style>
            <Style TargetType="TabBar" BasedOn="{StaticResource BaseStyle}" />
            <Style TargetType="FlyoutItem" BasedOn="{StaticResource BaseStyle}" />

            <Style Class="FlyoutItemLabelStyle" TargetType="Label">
                <Setter Property="TextColor" Value="White"></Setter>
            </Style>
            <Style Class="FlyoutItemLayoutStyle" TargetType="Layout" ApplyToDerivedTypes="True">
                <Setter Property="VisualStateManager.VisualStateGroups">
                    <VisualStateGroupList>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="{x:OnPlatform UWP=Transparent, iOS=White}" />
                                    <Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="{StaticResource Primary}" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="Selected">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="{StaticResource Primary}" />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateGroupList>
                </Setter>
            </Style>

            <Style Class="MenuItemLayoutStyle" TargetType="Layout" ApplyToDerivedTypes="True">
                <Setter Property="VisualStateManager.VisualStateGroups">
                    <VisualStateGroupList>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal">
                                <VisualState.Setters>
                                    <Setter TargetName="FlyoutItemLabel" Property="Label.TextColor" Value="{StaticResource Primary}" />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateGroupList>
                </Setter>
            </Style>
        </ResourceDictionary>
    </Shell.Resources>

    <FlyoutItem Title="Clavier bluetooth" Icon="icon_about.png">
        <ShellContent Route="AboutPage" ContentTemplate="{DataTemplate local:AboutPage}" />
    </FlyoutItem>
    <FlyoutItem Title="Information" Icon="icon_feed.png">
        <ShellContent Route="ItemsPage" ContentTemplate="{DataTemplate local:ItemsPage}" />
    </FlyoutItem>

    <MenuItem Text="Logout" StyleClass="MenuItemLayoutStyle" Clicked="OnMenuItemClicked">
    </MenuItem>

    <TabBar>
        <ShellContent Route="LoginPage" ContentTemplate="{DataTemplate local:LoginPage}" />
    </TabBar> 
</Shell>
```

During debugging, I've checked the XAML linker errors but I don't have anything. I've also tried step-by-step debugging and the list is correctly updating with the devices.

I've also tried to add the INotifyProprietyChanged as it was suggested in other answers but nothing changed. (I might have incorrectly used it)

Note: I'm using the plugin BLE nuget, and I've followed the instructions from the Git and from tutorials I've found on the web (this one, and this one).

CodePudding user response:

Thanks for your help @ColeX and @Jason! I've figured out what was happening. I don't know how could I've not thought about this earlier.

It appears that the default text color for my ListView was white which explains why I could not see anything.

I don't know why by default the text and the background colors were the same but yeah that was the problem...

CodePudding user response:

From source code I see IDevice.NativeDevice is just an object, so maybe it can't recognize NativeDevice.Name in the binding with the Label.Text.

Can you try this code first ?

<ViewCell>
   <StackLayout>
      <Label Text="{Binding Name}"></Label>
      <Label Text="{Binding NativeDevice}" ></Label>
   </StackLayout>
</ViewCell>
  • Related