Listview 不会根据 ObservableCollection 属性进行更新
Posted
技术标签:
【中文标题】Listview 不会根据 ObservableCollection 属性进行更新【英文标题】:Listview is not updating based on ObservableCollection properties 【发布时间】:2021-07-31 23:31:51 【问题描述】:我有一个 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);
【问题讨论】:
我不清楚问题是什么。您是说添加新设备时它不会显示正确的状态吗?或者在添加它之后,当状态改变时它不会更新?此外,您同时初始化devicesFound
和 DevicesFound
,您应该只更新公共属性,而不是同时更新。
当我连接时,状态应该从已断开连接更改为正在连接并已连接,但它仍处于断开连接状态,因此它不会更新属性。首次添加设备时初始状态正确
我在您的代码中看不到任何会在初始连接后更新状态的内容
我有一个连接设备的方法。一旦它连接状态应该改变,它的连接正确但状态没有改变,我以为我将它正确绑定到属性
但是您没有发布该代码
【参考方案1】:
当连接状态改变时,你需要更新你的 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;
【讨论】:
以上是关于Listview 不会根据 ObservableCollection 属性进行更新的主要内容,如果未能解决你的问题,请参考以下文章