我目前正在我的 Xamarin 应用程序中使用数据绑定构建视图。但是,我遇到了一个问题,即当我修改列表的值时,列表(特别是“ChecklistSections”)不会更新。奇怪的是,当我尝试更新按钮的文本时,数据绑定工作得很好。但由于某种原因,它没有按列表的预期工作。
我正在寻找一种解决方案,以确保“ChecklistSections”列表通过数据绑定正确更新,就像按钮的文本一样。任何有关如何解决列表数据绑定问题的见解或建议将不胜感激!
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewModels="clr-namespace:xxx.xxx.ExternalDisplay.App.ViewModels"
xmlns:converters="clr-namespace:xxx.xxx.ExternalDisplay.App.Converters"
xmlns:model="clr-namespace:xxx.xxx.ExternalDisplay.Core.Models;assembly=xxx.xxx.ExternalDisplay.Core"
x:Class="xxx.xxx.ExternalDisplay.App.Views.Checklist"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
x:DataType="viewModels:ChecklistViewModel"
NavigationPage.HasNavigationBar="False"
BackgroundColor="Black">
<ContentPage.Resources>
<ResourceDictionary>
<xct:InvertedBoolConverter x:Key="InvertedBoolConverter" />
<converters:CheckedColorConverter x:Key="CheckedColorConverter" />
<converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout Padding="10">
<Label Text="Checklist Items" FontSize="Large" TextColor="White" HorizontalOptions="Center" VerticalOptions="StartAndExpand" Margin="0,20,0,0" />
<Grid>
<ListView ItemsSource="{Binding ChecklistSections}" HasUnevenRows="True"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Margin="0,10,0,0">
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:ChecklistSection">
<ViewCell>
<StackLayout Padding="10">
<!-- Add padding to the StackLayout to create free space on all sides -->
<Label Text="{Binding ChecklistCategory.Name}" FontAttributes="Bold" Padding="5,0,0,0" FontSize="Header" TextColor="White" />
<StackLayout BindableLayout.ItemsSource="{Binding ChecklistItems}">
<BindableLayout.ItemTemplate>
<DataTemplate x:DataType="model:ChecklistItem">
<StackLayout Padding="15" Orientation="Vertical" BackgroundColor="Purple">
<StackLayout Orientation="Horizontal">
<Label Text="{Binding ItemText}" FontSize="Large" TextColor="White" VerticalOptions="Center"/>
<StackLayout HorizontalOptions="End" Orientation="Horizontal" VerticalOptions="End" >
<CheckBox IsChecked="{Binding Value}" Color="Green" WidthRequest="40" HeightRequest="40"
CheckedChanged="GreenCheckBox_CheckedChanged" />
<CheckBox IsChecked="{Binding Value, Converter={StaticResource InverseBooleanConverter}}" Color="Red" WidthRequest="40" HeightRequest="80" MinimumHeightRequest="50"
CheckedChanged="RedCheckBox_CheckedChanged" />
<BoxView Color="{Binding Value, Converter={StaticResource CheckedColorConverter}}"
HeightRequest="20"
WidthRequest="20"
VerticalOptions="Center"
HorizontalOptions="CenterAndExpand"
Margin="5,0,0,0">
<BoxView.GestureRecognizers>
<TapGestureRecognizer Tapped="BoxView_Tapped" />
</BoxView.GestureRecognizers>
</BoxView>
</StackLayout>
</StackLayout>
<Editor HorizontalOptions="FillAndExpand" TextColor="White"/>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
<Button Text="{Binding ButtonText}" Command="{Binding SubmitCommand}" BackgroundColor="{StaticResource PrimaryAccentColor}" BorderRadius="10" FontAttributes="Bold" TextColor="White" HorizontalOptions="Center" VerticalOptions="EndAndExpand" Margin="0,20" />
</StackLayout>
这就是我更新清单部分的方式:
var a = ChecklistSections;
foreach (var section in a)
{
var itemToUpdate = section.ChecklistItems.FirstOrDefault(item => item.Id == checklistItem.Id);
if (itemToUpdate != null)
{
itemToUpdate.Value = value;
// next two lines just for testing databinding
ButtonText = itemToUpdate.ItemText;
a[0].ChecklistCategory.Name = "hi hi hi";
break; // Exit the loop after updating the item
}
}
ChecklistSections = a;
清单部分:
private ObservableCollection<ChecklistSection> _checklistSections;
public ObservableCollection<ChecklistSection> ChecklistSections
{
get => _checklistSections;
set
{
{
_checklistSections = value;
OnPropertyChanged(nameof(ChecklistSections));
}
}
如果您希望 UI 在更改绑定属性的值后自动刷新(例如
ItemText
),请重新检查您是否为您的模型实现了接口 INotifyPropertyChanged
。
例如:
public class YourItemModel: INotifyPropertyChanged
{
private string _itemText ;
public string ItemText
{
get => _itemText;
set
{
SetProperty(ref _itemText, value);
}
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
注:
从文档ObservableCollection Class,我们可以发现:
表示动态数据集合 当添加或删除项目时,或者当 整个列表已刷新。ObservableCollection<T>
所以,如果你想让UI在改变item model的值后自动刷新,使用代码是没有用的
ObservableCollection<ChecklistSection> ChecklistSections
。
此外,建议您直接在变量
ChecklistSections
上修改子元素属性的值,而不是使用中间变量a
。
//var a = ChecklistSections;
foreach (var section in ChecklistSections)
{
//....
}
//ChecklistSections = a;