首页 > 解决方案 > Listview 不会根据 ObservableCollection 属性进行更新

问题描述

我有一个 BLE 应用程序,它连接到设备并旨在在列表视图中动态接收设备状态。我已将本机设备类实现为模型,并且我的视图模型在 MainViewModel 类中是单独的。我已经在这两个类上实现了 INotifyPropretyChanged,但是在我连接到它之后设备的状态没有改变。它应该是 Disconnected、Connecting、Connected、Disconnected 并且我有一个来自这个 BLE 插件的 Name DeviceState 属性,它保存了这个值 + 我已经为它实现了一个 INotifyPropretyChanged。我已经尝试过没有 TwoWay 和 NotifyCollectionChanged 等。我成功地获得了设备名称和状态(断开连接),但是当我连接到它时,状态应该改变并且它没有。它成功连接,我在另一个没有 MVVM 方法的应用程序上尝试过它,它在连接后获取状态,但我必须循环遍历它们并将它们添加到单独的集合中,这不是很有效。任何帮助将不胜感激,在此先感谢您!

class NativeDevice : INotifyPropertyChanged
    {
        private string deviceNameValue = String.Empty;
        public event PropertyChangedEventHandler PropertyChanged;
        private DeviceState states;


        public NativeDevice(string name, DeviceState stated)
        {
            deviceNameValue = name;
            states = stated;
        }
        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public string Name
        {
            get
            {
                return this.deviceNameValue;
            }

            set
            {
                if (value != this.deviceNameValue)
                {
                    this.deviceNameValue = value;
                    OnPropertyChanged();
                }
            }
        }
        
        public DeviceState States
        {
            get
            {
                return states;
            }

            set
            {
                this.states = value;
                OnPropertyChanged();
            }
        }
       


    }
class MainViewModel : INotifyPropertyChanged
    {
        public ObservableCollection<IDevice> BluetoothDevices { get; set; }
        public ObservableCollection<NativeDevice> devicesFound;
        public ObservableCollection<NativeDevice> DevicesFound { get { return devicesFound; } 
                                                              set { devicesFound = value; OnPropertyChanged(); } }
        public event PropertyChangedEventHandler PropertyChanged;

        private readonly IAdapter _bluetoothAdapter;
        public AsyncCommand ScanForDevices { get; }
        public AsyncCommand ConnectToDevices { get; }

        CancellationTokenSource source = new CancellationTokenSource();
        public MainViewModel()
        {
            ScanForDevices = new AsyncCommand(PerformScanAsync);
            DevicesFound = new ObservableCollection<NativeDevice>();
            BluetoothDevices = new ObservableCollection<IDevice>();
            _bluetoothAdapter = CrossBluetoothLE.Current.Adapter;
            _bluetoothAdapter.DeviceDiscovered += (s, a) =>
            {
                BluetoothDevices.Add(a.Device);
            };
            ConnectToDevices = new AsyncCommand(ConnectAsync);
            CancellationToken token = source.Token;
            devicesFound = new ObservableCollection<NativeDevice>();
        }



        public void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        
        async Task PerformScan{
         await _bluetoothAdapter.StartScanningForDevicesAsync();

            foreach (var item in BluetoothDevices)
            {
                if (item.Name == "GP")
                {
                    DevicesFound.Add(new NativeDevice(item.Name, item.State));
                }
            }
            await _bluetoothAdapter.StopScanningForDevicesAsync();
        }
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:bleappmodelview="clr-namespace:BleAppModelView.ViewModels" xmlns:bleappmodelview1="clr-namespace:BleAppModelView.Model" x:DataType="bleappmodelview:MainViewModel"
             x:Class="BleAppModelView.MainPage">

    <ContentPage.BindingContext>
        <bleappmodelview:MainViewModel/>
    </ContentPage.BindingContext>

    <StackLayout>
       
        <Button x:DataType="bleappmodelview:MainViewModel"
                Text="Scan"
                Command="{Binding ScanForDevices}"
                Margin="10" />
        <ListView  ItemsSource="{Binding DevicesFound}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout>
                            <Label x:DataType="bleappmodelview1:NativeDevice" Text="{Binding Name, Mode=TwoWay}"/>
                            <Label x:DataType="bleappmodelview1:NativeDevice" Text="{Binding States, Mode=TwoWay}" TextColor="Red"/>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        <Button x:DataType="bleappmodelview:MainViewModel"
                Text="Connect" 
                Command="{Binding ConnectToDevices}"
                Margin="10"/>
    </StackLayout>


</ContentPage>
 public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            BindingContext = new MainViewModel();
        }
    }
namespace Plugin.BLE.Abstractions
{
    public enum DeviceState
    {
        Disconnected = 0,
        Connecting = 1,
        Connected = 2,
        Limited = 3
    }
}
 async Task ConnectAsync()
        {
            foreach (var device in BluetoothDevices)
            {
                if (device.Name == "GP")
                {
                    var parameters = new ConnectParameters(forceBleTransport: true);
                    await _bluetoothAdapter.ConnectToDeviceAsync(device, parameters, source.Token);
                }
            }
        }

标签: c#listviewxamarinmvvmbinding

解决方案


当连接状态发生变化时,您需要更新 UI 绑定的对象

有很多不同的方法可以解决这个问题,一种简单的方法是

  async Task ConnectAsync()
    {
        foreach (var device in BluetoothDevices)
        {
            if (device.Name == "GP")
            {
                var parameters = new ConnectParameters(forceBleTransport: true);
                await _bluetoothAdapter.ConnectToDeviceAsync(device, parameters, source.Token);

                // find the matching device in DevicesFound
                var d = DevicesFound.Where(x => x.Name == device.Name).FirstOrDefault();
                d.States = DeviceState.Connected;
            }
        }
    }

推荐阅读