c# - 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);
}
}
}
解决方案
当连接状态发生变化时,您需要更新 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;
}
}
}
推荐阅读
- android - Android ViewModel 正在泄漏
- xamarin.forms - Xamarin.Forms 中的设置列表
- sql - Sql需要对列进行多次求和并将结果水平拆分为一行
- python-3.x - Django 单元测试句柄 PermissionDenied
- r - 尝试在 Ubuntu 18.04 上安装 tidycensus 包时出错
- angular - 如何在 Angular Reactive Forms 中正确呈现动态表单?
- c++ - 仅当将(IF)循环合并到while循环中时才过早地强制结束while循环?
- python - 安装 Pillow 后出现 ModuleNotFoundError
- bash - 如何从 .gitconfig 别名调用外部脚本?
- python - 如何让我的不和谐机器人发送 mp3 文件?(discord.py)