出于某种原因,当在父 CollectionView 中使用 ItemsSource="{Binding Patient}" 和嵌套 CollectionView 与 ItemsSource="{Binding Visits}" 进行数据竞价时,出现错误
在嵌套 CollectionView 的 DataTemplate 中,我具有绑定的 FolderItem 属性,如 IsFolder、Name 和 IsExpanded。当我使用 Visual Studio 2022 并打开此 Maui 8 应用程序和页面:MyLibraryPage.xaml 时,我可以单击这些绑定的属性名称并按 F8,它将带我到访客属性集合项的相应属性:FolderItem 我收到这个消息,这阻止我正确编译代码并运行它。
MyLibraryPage.xaml(47,15):XamlC 错误 XFC0045:绑定:在“Demo.ViewModels.MyLibraryPageViewModel”上找不到属性“名称”。
如果我评论这一行,不同的绑定会出现相同的错误。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewmodels="clr-namespace:Plugin.Maui.Audio.Sample.ViewModels"
xmlns:converters="clr-namespace:Plugin.Maui.Audio.Sample.Converters"
x:Class="Plugin.Maui.Audio.Sample.Pages.MyLibraryPage"
Title="My Library"
x:Name="Page"
x:DataType="viewmodels:MyLibraryPageViewModel">
<ContentPage.Resources>
<Style x:Key="border_gallery_card" TargetType="Border">
<Setter Property="Stroke" Value="{AppThemeBinding Light={StaticResource Gray200}, Dark={StaticResource Gray950}}" />
<Setter Property="BackgroundColor" Value="{AppThemeBinding Light={StaticResource White}, Dark={StaticResource Gray950}}" />
<Setter Property="Padding" Value="16" />
<Setter Property="StrokeThickness" Value="1" />
<Setter Property="StrokeShape" Value="RoundRectangle 8" />
</Style>
<converters:FolderFileIconConverter x:Key="FolderFileIconConverter" />
<converters:FolderFileFontAttributeConverter x:Key="FolderFileFontAttributeConverter" />
<converters:ExpandCollapseConverter x:Key="ExpandCollapseConverter" />
<!-- Font attributes as resources -->
<FontAttributes x:Key="BoldFontAttribute">Bold</FontAttributes>
<FontAttributes x:Key="NoneFontAttribute">None</FontAttributes>
<!-- Icons -->
<FontImageSource x:Key="PersonIcon" Glyph="" FontFamily="FontAwesome" Size="20" />
<FontImageSource x:Key="FolderIcon" Glyph="" FontFamily="FontAwesome" Size="20" />
<FontImageSource x:Key="FileIcon" Glyph="" FontFamily="FontAwesome" Size="20" />
<FontImageSource x:Key="ExpandIcon" Glyph="" FontFamily="FontAwesome" Size="20" />
<FontImageSource x:Key="CollapseIcon" Glyph="" FontFamily="FontAwesome" Size="20" />
</ContentPage.Resources>
<Grid RowDefinitions="60,*,150">
<Grid ColumnDefinitions="*,Auto">
<Entry x:Name="PatientIdEntry" Placeholder="Enter Patient ID" Grid.Column="0" />
<Button Text="Create Recording" Grid.Column="1" Command="{Binding AddRecordingCommand}" />
</Grid>
<CollectionView x:Name="FilesCollectionView" ItemsSource="{Binding Patients}" SelectionMode="Single" Grid.Row="1">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Grid ColumnDefinitions="Auto, *, Auto">
<Image Source="{StaticResource PersonIcon}" VerticalOptions="Center" />
<Label Text="{Binding Name}" FontAttributes="Bold" VerticalOptions="Center" />
<ImageButton Source="{Binding IsExpanded, Converter={StaticResource ExpandCollapseConverter}}" Command="{Binding Path=BindingContext.OpenMusicCommand, Source={x:Reference Page}}" CommandParameter="{Binding .}" />
</Grid>
<CollectionView ItemsSource="{Binding Visits}" IsVisible="{Binding IsExpanded}" SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="20,0,0,0">
<Grid ColumnDefinitions="Auto, *, Auto">
<Image Source="{Binding IsFolder, Converter={StaticResource FolderFileIconConverter}}" VerticalOptions="Center" />
<Label Text="{Binding Name}" FontAttributes="{Binding IsFolder, Converter={StaticResource FolderFileFontAttributeConverter}}" VerticalOptions="Center" />
<ImageButton Source="{Binding IsExpanded, Converter={StaticResource ExpandCollapseConverter}}" Command="{Binding Path=BindingContext.OpenMusicCommand, Source={x:Reference Page}}" CommandParameter="{Binding .}" />
</Grid>
<CollectionView ItemsSource="{Binding Children}" IsVisible="{Binding IsExpanded}" SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="20,0,0,0">
<Border Style="{StaticResource border_gallery_card}">
<Border.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Path=BindingContext.OpenMusicCommand, Source={x:Reference Page}}" CommandParameter="{Binding .}" />
</Border.GestureRecognizers>
<Label Text="{Binding Name}" />
</Border>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<!-- Patient Details Section -->
<StackLayout Grid.Row="2" Padding="10">
<Label Text="Patient Details" FontAttributes="Bold" FontSize="Medium" />
<Image Source="{Binding SelectedPatient.PictureUrl}" HeightRequest="100" WidthRequest="100" />
<Label Text="Name: " />
<Label Text="{Binding SelectedPatient.Name}" />
<Label Text="Health Card Number: " />
<Label Text="{Binding SelectedPatient.HealthCardNumber}" />
<Label Text="Last Visit: " />
<Label Text="{Binding SelectedPatient.LastVisitDateTime}" />
<Label Text="Length of Visit: " />
<Label Text="{Binding SelectedPatient.LengthOfVisit}" />
</StackLayout>
</Grid>
</ContentPage>
Pages\MyLibraryPage.xaml.cs
---------------------------------------
using Plugin.Maui.Audio.Sample.ViewModels;
namespace Plugin.Maui.Audio.Sample.Pages;
public partial class MyLibraryPage : ContentPage
{
public MyLibraryPage(MyLibraryPageViewModel myLibraryPageViewModel)
{
InitializeComponent();
BindingContext = myLibraryPageViewModel;
}
}
ViewModels\Patient.cs
------------------------------------------
using System.Collections.ObjectModel;
namespace Plugin.Maui.Audio.Sample.ViewModels;
public class Patient : BaseViewModel
{
bool isExpanded;
public string PatientId { get; set; }
public string Name { get; set; }
public string PictureUrl { get; set; }
public string HealthCardNumber { get; set; }
public DateTime LastVisitDateTime { get; set; }
public string LengthOfVisit { get; set; }
public ObservableCollection<FolderItem> Visits { get; set; }
public bool IsExpanded
{
get => isExpanded;
set
{
isExpanded = value;
NotifyPropertyChanged();
}
}
public Patient()
{
Visits = new ObservableCollection<FolderItem>();
}
}
ViewModels\FolderItem.cs
-----------------------------------
using System.Collections.ObjectModel;
namespace Plugin.Maui.Audio.Sample.ViewModels;
public class FolderItem : BaseViewModel
{
bool isExpanded;
public string Name { get; set; }
public bool IsFolder { get; set; }
public ObservableCollection<FolderItem> Children { get; set; }
public bool IsExpanded
{
get => isExpanded;
set
{
isExpanded = value;
NotifyPropertyChanged();
}
}
public FolderItem()
{
Children = new ObservableCollection<FolderItem>();
}
}
ViewModels\MyLibraryPageViewModel.cs
--------------------------------------------
using System.Collections.ObjectModel;
namespace Plugin.Maui.Audio.Sample.ViewModels;
public class MyLibraryPageViewModel : BaseViewModel
{
public Command AddRecordingCommand { get; }
public Command<FolderItem> OpenMusicCommand { get; }
ObservableCollection<Patient> patients;
Patient selectedPatient;
public ObservableCollection<Patient> Patients
{
get => patients;
set
{
patients = value;
NotifyPropertyChanged();
}
}
public Patient SelectedPatient
{
get => selectedPatient;
set
{
selectedPatient = value;
NotifyPropertyChanged();
}
}
public MyLibraryPageViewModel()
{
Patients = new ObservableCollection<Patient>
{
new Patient
{
PatientId = "100",
Name = "John Doe",
Visits = new ObservableCollection<FolderItem>
{
new FolderItem
{
Name = "2023-09-22",
IsFolder = true,
Children = new ObservableCollection<FolderItem>
{
new FolderItem
{
Name = "100_2023-09-22_10-30-00.mp3",
IsFolder = false
},
new FolderItem
{
Name = "100_2023-09-22_11-00-00.mp3",
IsFolder = false
}
}
},
new FolderItem
{
Name = "2023-09-21",
IsFolder = true,
Children = new ObservableCollection<FolderItem>
{
new FolderItem
{
Name = "100_2023-09-21_13-30-00.mp3",
IsFolder = false
},
new FolderItem
{
Name = "100_2023-09-22_11-00-00.mp3",
IsFolder = false
}
}
}
}
}
};
AddRecordingCommand = new Command(async () => await AddRecording());
OpenMusicCommand = new Command<FolderItem>(async (item) => await OnMusicItemSelected(item));
}
static async Task AddRecording()
{
await Shell.Current.GoToAsync("AudioRecorderPage");
}
static async Task OnMusicItemSelected(FolderItem item)
{
if (item.IsFolder)
{
item.IsExpanded = !item.IsExpanded;
}
else
{
await Shell.Current.GoToAsync(
"MusicPlayerPage",
new Dictionary<string, object>
{
["Music"] = item
});
}
}
}
当您将 CollectionView 嵌套在另一个 CollectionView 中时,内部 CollectionView 的绑定上下文将成为外部 CollectionView 的当前项。因此,您需要确保嵌套 CollectionView 的 DataTemplate 已正确设置为正确的上下文。
要解决此问题,您应该将嵌套 CollectionView 的绑定上下文设置为适当的数据类型。这是 XAML 的更新版本,重点关注嵌套 CollectionView:
<CollectionView ItemsSource="{Binding Patients}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding Name}" /> <!-- Assuming Patients have a Name property -->
<!-- Nested CollectionView for Visits -->
<CollectionView ItemsSource="{Binding Visits}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding Name}" />
<Label Text="{Binding IsFolder}" />
<Label Text="{Binding IsExpanded}" />
<!-- Other properties of FolderItem -->
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>