.NET MAUI ContentView属性值及绑定更新异常修复咨询
.NET MAUI ProgressCardView 控件修复方案
问题根源分析
你的控件出现显示异常的核心原因有以下几点:
- 所有
BindableProperty定义错误使用了ProgressCardView2作为所有者类型,实际控件类是ProgressCardView,导致绑定完全失效 Score和Percentage是普通属性,未实现属性变化通知,且依赖的私有字段未与Attempted/Possible同步ProgressBar未绑定进度值,无法展示分数对应的进度- 未处理分母为0的异常情况
修正后的代码
1. ProgressCardView.xaml(仅修改ProgressBar绑定)
<?xml version="1.0" encoding="utf-8" ?> <ContentView x:Name="this" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="ExampleApp.Controls.ProgressCardView"> <Frame BindingContext="{x:Reference this}" BackgroundColor="{Binding BackgroundColor}" CornerRadius="5" HasShadow="True"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="3*" /> <RowDefinition Height="Auto" /> <RowDefinition Height="2*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="10*" /> <ColumnDefinition Width="4*" /> <ColumnDefinition Width="4*" /> </Grid.ColumnDefinitions> <Button x:Name="InternalButton" Grid.RowSpan="3" Grid.ColumnSpan="2" Opacity="0.0" Clicked="buttonEvent" /> <Label Text="{Binding Title}" HorizontalOptions="Start" VerticalOptions="Center" FontSize="17" TextColor="{Binding HeaderColor}" /> <Label Text="{Binding Score}" Grid.Column="1" Grid.ColumnSpan="2" HorizontalOptions="End" VerticalOptions="Center" FontSize="12" TextColor="{Binding TextColor}" /> <BoxView Grid.Row="1" Grid.ColumnSpan="3" HeightRequest="1" Color="{Binding TextColor}"/> <!-- 新增Progress属性绑定 --> <ProgressBar x:Name="CardProgressBar" Grid.Row="2" Grid.ColumnSpan="2" Progress="{Binding ProgressValue}" /> <Label Text="{Binding Percentage}" Grid.Row="2" Grid.Column="2" HorizontalOptions="End" VerticalOptions="Center" FontSize="12" TextColor="{Binding TextColor}" /> </Grid> </Frame> </ContentView>
2. ProgressCardView.xaml.cs(核心修正)
namespace ExampleApp.Controls { public partial class ProgressCardView : ContentView { private int _attempted = 0; private int _possible = 1; #region BindableProperties public static readonly BindableProperty TitleProperty = BindableProperty.Create( nameof(Title), typeof(string), typeof(ProgressCardView), // 修正为正确的控件类名 string.Empty); public static readonly BindableProperty AttemptedProperty = BindableProperty.Create( nameof(Attempted), typeof(int), typeof(ProgressCardView), // 修正为正确的控件类名 0, propertyChanged: OnAttemptedOrPossibleChanged); // 添加属性变化回调 public static readonly BindableProperty PossibleProperty = BindableProperty.Create( nameof(Possible), typeof(int), typeof(ProgressCardView), // 修正为正确的控件类名 1, propertyChanged: OnAttemptedOrPossibleChanged); // 添加属性变化回调 public static readonly BindableProperty BackgroundColorProperty = BindableProperty.Create( nameof(BackgroundColor), typeof(Color), typeof(ProgressCardView), // 修正为正确的控件类名 Color.FromArgb("#FFFFFF")); public static readonly BindableProperty HeaderColorProperty = BindableProperty.Create( nameof(HeaderColor), typeof(Color), typeof(ProgressCardView), // 修正为正确的控件类名 Color.FromArgb("#FFFFFF")); public static readonly BindableProperty TextColorProperty = BindableProperty.Create( nameof(TextColor), typeof(Color), typeof(ProgressCardView), // 修正为正确的控件类名 Color.FromArgb("#FFFFFF")); #endregion #region Properties public string Title { get => (string)GetValue(TitleProperty); set => SetValue(TitleProperty, value); } public int Attempted { get => _attempted; set => SetValue(AttemptedProperty, value); } public int Possible { get => _possible; set => SetValue(PossibleProperty, value); } // 计算属性,自动同步Attempted/Possible变化 public string Score { get => $"{_attempted}/{_possible}"; } public string Percentage { get { if (_possible == 0) return "0.0%"; // 避免除以0异常 return $"{((double)_attempted / _possible):P1}"; } } // 进度条绑定值 public double ProgressValue { get { if (_possible == 0) return 0; return (double)_attempted / _possible; } } public Color BackgroundColor { get => (Color)GetValue(BackgroundColorProperty); set => SetValue(BackgroundColorProperty, value); } public Color HeaderColor { get => (Color)GetValue(HeaderColorProperty); set => SetValue(HeaderColorProperty, value); } public Color TextColor { get => (Color)GetValue(TextColorProperty); set => SetValue(TextColorProperty, value); } #endregion #region Methods and Events public ProgressCardView() { InitializeComponent(); } // 属性变化时更新计算属性的UI绑定 private static void OnAttemptedOrPossibleChanged(BindableObject bindable, object oldValue, object newValue) { if (bindable is not ProgressCardView card) return; // 同步私有字段 card._attempted = (int)bindable.GetValue(AttemptedProperty); card._possible = Math.Max(1, (int)bindable.GetValue(PossibleProperty)); // 确保分母不为0 // 通知UI更新计算属性 card.OnPropertyChanged(nameof(Score)); card.OnPropertyChanged(nameof(Percentage)); card.OnPropertyChanged(nameof(ProgressValue)); } private void buttonEvent(object sender, EventArgs e) { // 在此添加卡片点击逻辑 } #endregion } }
关键修改说明
- 修正BindableProperty所有者类型:所有绑定属性的第三个参数改为当前控件类
ProgressCardView,解决绑定失效问题 - 添加属性变化回调:当
Attempted或Possible值变化时,自动同步私有字段并通知计算属性更新 - 实现计算属性通知:通过
OnPropertyChanged触发UI刷新,确保Score、Percentage、ProgressValue实时更新 - 异常防护:处理
Possible为0的情况,避免运行时除以0错误 - 进度条绑定:给
ProgressBar添加Progress属性绑定,展示分数对应的进度
内容的提问来源于stack exchange,提问作者ecfedele
相关产品推荐
相关产品推荐

