我创建了一个名为 SectionTitle 的 .net MAUI 组件,它有两个属性:一个用于背景颜色,一个用于标签字符串。
<?xml version="1.0" encoding="utf-8" ?>
<ContentView
x:Class="mater.Components.SectionTitle"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:c="clr-namespace:mater.Components"
x:DataType="c:SectionTitle">
<Grid ColumnDefinitions="3*,2*">
<Grid ColumnDefinitions="Auto,*">
<Border
x:Name="Bordo"
Grid.Column="0"
Padding="5,10,20,10"
Background="{Binding BGColor}"
StrokeShape="RoundRectangle 0,10,0,10">
<Label
x:Name="Lbl"
Grid.Column="0"
Text="{Binding LabelText}" />
</Border>
</Grid>
</Grid>
</ContentView>
对应的c#代码如下:
namespace mater.Components;
public partial class SectionTitle : ContentView
{
public static readonly BindableProperty BGColorProperty = BindableProperty.Create(
nameof(BGColor), typeof(Brush), typeof(SectionTitle), default(Brush));
public static readonly BindableProperty LabelTextProperty = BindableProperty.Create(
nameof(LabelText), typeof(string), typeof(SectionTitle), "");
public Brush BGColor
{
get { return (Brush)GetValue(BGColorProperty); }
set { SetValue(BGColorProperty, value); }
}
public string LabelText
{
get { return (string)GetValue(LabelTextProperty); }
set { SetValue(LabelTextProperty, value); }
}
public SectionTitle()
{
InitializeComponent();
BindingContext = this;
}
}
在 CollectionView 中使用它时,直接使用模型的 Label 属性时绑定可以工作,但当数据通过我的 SectionTitle 组件传递时它不起作用。为 LabelText 设置静态值是有效的。
<?xml version="1.0" encoding="UTF-8" ?>
<ContentPage
x:Class="mater.Views.HygienePage"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:c="clr-namespace:mater.Components"
xmlns:local="clr-namespace:mater"
xmlns:models="clr-namespace:mater.Models"
xmlns:vm="clr-namespace:mater.ViewModels"
x:DataType="vm:HygieneViewModel">
<ScrollView>
<StackLayout Margin="0,10,0,0">
<CollectionView
Margin="20,10,20,10"
ItemsSource="{Binding Cards}"
SelectionChanged="CollectionView_SelectionChanged"
SelectionMode="Single">
<CollectionView.ItemsLayout>
<GridItemsLayout
HorizontalItemSpacing="20"
Orientation="Vertical"
Span="2"
VerticalItemSpacing="20" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:CardItem">
<StackLayout Margin="0,0,0,10" Background="{StaticResource LightGrey}">
<Grid ColumnDefinitions="Auto,*">
<Border
Grid.Column="0"
Margin="0,10,0,0"
Padding="5,10,20,10"
Background="{StaticResource Coral}"
StrokeShape="RoundRectangle 0,10,0,10">
<Label Text="{Binding Label}" />
</Border>
<Grid Grid.Column="1" />
</Grid>
<!-- Here if I put LabelText="ASD" it works, with the binding it doesn't work, the binding 3 lines before works -->
<c:SectionTitle BGColor="{StaticResource Coral}" LabelText="{Binding Label}" />
<Image HeightRequest="150" Source="{Binding Icon}" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ScrollView>
</ContentPage>
为了完整性,我还添加了相应的 C# 代码
using mater.ViewModels;
using mater.Models;
using mater.Resources.Strings;
namespace mater.Views;
public partial class HygienePage : ContentPage
{
public List<CardItem> Cards = new()
{
new CardItem
{
Icon="rischi_micro.png",
Label=AppStrings.SicRischi
},
new CardItem
{
Icon="da_evitare.png",
Label=AppStrings.SicEvitare
},
new CardItem
{
Icon="acquisto.png",
Label=AppStrings.SicLavaggio
},
new CardItem
{
Icon="cottura.png",
Label=AppStrings.SicCottura
},
new CardItem
{
Icon="contaminazioni.png",
Label=AppStrings.SicContaminazioni
},
};
public HygieneViewModel vm { get; set; }
public HygienePage()
{
InitializeComponent();
vm = new HygieneViewModel();
vm.Cards = Cards;
BindingContext = vm;
}
async void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.CurrentSelection.Count > 0)
{
CardItem selectedCard = (CardItem)e.CurrentSelection[0];
((CollectionView)sender).SelectedItem = null;
switch (selectedCard.Label)
{
case var value when value == AppStrings.SicRischi:
await Shell.Current.GoToAsync("rischimicropage");
break;
case var value when value == AppStrings.SicEvitare:
await Shell.Current.GoToAsync("evitarepage");
break;
case var value when value == AppStrings.SicLavaggio:
await Shell.Current.GoToAsync("lavaggiopage");
break;
case var value when value == AppStrings.SicCottura:
await Shell.Current.GoToAsync("cotturapage");
break;
case var value when value == AppStrings.SicContaminazioni:
await Shell.Current.GoToAsync("contaminazionipage");
break;
default:
break;
}
}
}
}
CardItem 模型:
using System;
namespace mater.Models;
public class CardItem
{
public ImageSource Icon { get; set; }
public string Label { get; set; }
public bool isVisible { get; set; } = true;
}
和视图模型:
using System;
using CommunityToolkit.Mvvm.ComponentModel;
using mater.Models;
namespace mater.ViewModels;
public partial class HygieneViewModel: ObservableObject
{
[ObservableProperty]
private List<CardItem> cards;
}
知道我的绑定做错了什么吗?
正如 @Jason 在评论中强调的那样,问题是在控件中使用 BindingContext=this 。
我从 C# 的构造函数中删除了
BindingContext = this;
向控件添加了 x:Name,并且绑定源更新如下:
<?xml version="1.0" encoding="utf-8" ?>
<ContentView
x:Class="mater.Components.SectionTitle"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:c="clr-namespace:mater.Components"
x:Name="self"
x:DataType="c:SectionTitle">
<Grid ColumnDefinitions="3*,2*">
<Grid ColumnDefinitions="Auto,*">
<Border
x:Name="Bordo"
Grid.Column="0"
Padding="5,10,20,10"
Background="{Binding Source={x:Reference self}, Path=BGColor}"
StrokeShape="RoundRectangle 0,10,0,10">
<Label
x:Name="Lbl"
Grid.Column="0"
Text="{Binding Source={x:Reference self}, Path=LabelText}" />
</Border>
</Grid>
</Grid>
</ContentView>
现在一切正常