.NET MAUI绑定属性的StringFormat无法显示附加文本问题
.NET MAUI自定义控件中StringFormat无法添加百分号后缀的问题
在.NET MAUI的XAML自定义控件里,我给Entry绑定了带Bindable Property的属性,想给文本加%后缀,但设置的StringFormat完全不生效——数值能正常显示,可格式里前后的文本都出不来。试了各种方法都没用,现在只能在后台硬编码加百分号。下面是完整的代码:
初始视图元素
<Entry x:Name="PercentEntry" Margin="10,0,10,0" HorizontalOptions="Start" IsReadOnly="True" Text="{Binding Percent, Mode=OneWay, StringFormat='{0} %'}" VerticalOptions="Center" />
初始绑定属性代码
public static readonly BindableProperty PercentProperty = BindableProperty.Create(nameof(Percent), typeof(string), typeof(StatsControl), propertyChanged: (bindable, oldValue, newValue) => { var control = (StatsControl)bindable; control.PercentEntry.Text = newValue as string; }); public string Percent { get => GetValue(PercentProperty) as string; set => SetValue(PercentProperty, value); }
完整自定义控件XAML代码
<ContentView x:Class="MathsForFlorence.Controls.StatsControl" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:MathsForFlorence.Controls"> <Border BackgroundColor="AliceBlue" HorizontalOptions="Center" Stroke="Black" StrokeShape="RoundRectangle 10" StrokeThickness="0" WidthRequest="360"> <VerticalStackLayout HorizontalOptions="Center"> <Label x:Name="TitleLabel" Margin="5,5,0,0" FontAttributes="Bold" FontSize="14" Text="{Binding Title, FallbackValue='Title'}" /> <FlexLayout AlignContent="Stretch" AlignItems="Stretch" Direction="Row" HorizontalOptions="CenterAndExpand" JustifyContent="SpaceEvenly" Wrap="Wrap"> <HorizontalStackLayout HorizontalOptions="Center"> <Label Margin="10,0,10,0" HorizontalOptions="Start" Text="Correct:" VerticalOptions="Center" /> <Entry x:Name="CorrectEntry" Margin="10,0,10,0" HorizontalOptions="Start" IsReadOnly="True" Text="{Binding Correct, Source={RelativeSource AncestorType={x:Type local:StatsControl}}}" VerticalOptions="Center" /> </HorizontalStackLayout> <HorizontalStackLayout HorizontalOptions="Center"> <Label Margin="10,0,10,0" HorizontalOptions="Start" Text="Wrong:" VerticalOptions="Center" /> <Entry x:Name="WrongEntry" Margin="10,0,10,0" HorizontalOptions="Start" IsReadOnly="True" Text="{Binding Wrong, FallbackValue='0'}" VerticalOptions="Center" /> </HorizontalStackLayout> <HorizontalStackLayout HorizontalOptions="Center"> <Label Margin="10,0,10,0" HorizontalOptions="Start" Text="Percentage correct:" VerticalOptions="Center" /> <Entry x:Name="PercentEntry" Margin="10,0,10,0" HorizontalOptions="Start" IsReadOnly="True" Text="{Binding Percent, Source={x:Reference this}, FallbackValue='0%'}" VerticalOptions="Center" /> </HorizontalStackLayout> </FlexLayout> </VerticalStackLayout> </Border> </ContentView>
控件后台代码
public partial class StatsControl : ContentView { public static readonly BindableProperty CorrectProperty = BindableProperty.Create(nameof(Correct), typeof(int), typeof(StatsControl), propertyChanged: (bindable, oldValue, newValue) => { var control = (StatsControl)bindable; control.CorrectEntry.Text = newValue.ToString(); }); public int Correct { get => (int)GetValue(CorrectProperty); set { SetValue(CorrectProperty, value); } } public static readonly BindableProperty WrongProperty = BindableProperty.Create(nameof(Wrong), typeof(int), typeof(StatsControl), propertyChanged: (bindable, oldValue, newValue) => { var control = (StatsControl)bindable; control.WrongEntry.Text = newValue.ToString(); }); public int Wrong { get => (int)GetValue(WrongProperty); set => SetValue(WrongProperty, value); } public static readonly BindableProperty PercentProperty = BindableProperty.Create(nameof(Percent), typeof(int), typeof(StatsControl), propertyChanged: (bindable, oldValue, newValue) => { var control = (StatsControl)bindable; control.PercentEntry.Text = String.Format("{0}%", newValue); }); public int Percent { get => (int)GetValue(PercentProperty); set => SetValue(PercentProperty, value); } public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(StatsControl), propertyChanged: (bindable, oldValue, newValue) => { var control = (StatsControl)bindable; control.TitleLabel.Text = newValue as string; }); public string Title { get => GetValue(TitleProperty) as string; set { SetValue(TitleProperty, value); } } public StatsControl() { InitializeComponent(); } }
控件使用方式
<controls:StatsControl x:Name="AdditionStatsControl" Title="Addition" Margin="0,5,0,0" Correct="{Binding AdditionCorrect}" Percent="{Binding AdditionPercentage}" Wrong="{Binding AdditionWrong}" />
ViewModel赋值代码
#region Properties - Addition [ObservableProperty] int additionCorrect; [ObservableProperty] int additionWrong; [ObservableProperty] int additionPercentage; #endregion //... AdditionCorrect = await SumCorrect(MathOperator.Add); AdditionWrong = await SumWrong(MathOperator.Add); AdditionPercentage = Helpers.CalculatePercent(AdditionCorrect, AdditionWrong); OnPropertyChanged(nameof(AdditionCorrect)); OnPropertyChanged(nameof(AdditionWrong)); OnPropertyChanged(nameof(AdditionPercentage));
问题原因及解决方法
问题核心是绑定属性的propertyChanged回调直接覆盖了Entry的Text值,导致XAML里设置的StringFormat完全被忽略——不管你在XAML里怎么写格式,回调里的直接赋值都会把它覆盖掉。
两种正确实现方式:
方式1:移除回调,让XAML绑定自动处理格式
修改PercentProperty的定义,去掉propertyChanged回调,同时在XAML里给Entry的Text绑定加上StringFormat:
后台代码修改:
public static readonly BindableProperty PercentProperty = BindableProperty.Create(nameof(Percent), typeof(int), typeof(StatsControl), defaultValue:0); public int Percent { get => (int)GetValue(PercentProperty); set => SetValue(PercentProperty, value); }
XAML里的PercentEntry修改:
<Entry x:Name="PercentEntry" Margin="10,0,10,0" HorizontalOptions="Start" IsReadOnly="True" Text="{Binding Percent, Source={x:Reference this}, FallbackValue='0%', StringFormat='{0}%'}" VerticalOptions="Center" />
方式2:在回调里处理格式(保留现有逻辑)
如果一定要保留propertyChanged回调,直接在回调里拼接百分号即可(你当前已经这么做了),但要注意XAML里的绑定不需要再加StringFormat,避免重复:
XAML里的PercentEntry保持现有代码,后台的PercentProperty回调逻辑不变。这种方式适合需要更复杂格式处理的场景。
另外,你的其他绑定属性(Correct、Wrong、Title)也存在同样的问题——用回调直接赋值会绕过XAML的绑定系统,建议统一改成移除回调,让绑定自动更新UI,更符合MAUI的绑定规范。
内容的提问来源于stack exchange,提问作者jason.kaisersmith
相关产品推荐
相关产品推荐

