You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建带可绑定属性的Markup Extension?解决绑定失效问题

问题描述

我想要创建一个名为RgbColorExtension的Markup Extension,使其R属性支持绑定,以便通过Slider调整其值。但拖动Slider时,R属性未产生变化,以下是我的代码:

XAML代码

<?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"
             x:Class="Sandbox.MainPage"
             xmlns:local="clr-namespace:Sandbox">
  <VerticalStackLayout>
    <Slider x:Name="slider" Maximum="1"/>
    <Label Text="{Binding Value,Source={x:Reference slider}}"/>
    <BoxView HeightRequest="200" WidthRequest="200">
      <BoxView.Color>
        <local:RgbColor R="{Binding Value,Source={x:Reference slider}}" G="0" B="0" A="0.5"/>
      </BoxView.Color>
    </BoxView>
    <BoxView 
      HeightRequest="200" 
      WidthRequest="200"
      Color="{local:RgbColor R={Binding Value,Source={x:Reference slider}},G=0.5,B=0.5,A=.5}" />
  </VerticalStackLayout>
</ContentPage>

C#代码

namespace Sandbox;

public class RgbColorExtension : BindableObject, IMarkupExtension<Color>
{
  public static readonly BindableProperty RProperty =
    BindableProperty.Create(nameof(R), typeof(float), typeof(RgbColorExtension), 0.5f);

  public float R
  {
    get => (float)GetValue(RProperty);
    set => SetValue(RProperty, value);
  }

  public float G { get; set; }
  public float B { get; set; }
  public float A { get; set; }

  public Color ProvideValue(IServiceProvider serviceProvider)
  {
    return Color.FromRgba(R, G, B, A);
  }

  object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
  {
    return (this as IMarkupExtension<Color>).ProvideValue(serviceProvider);
  }
}

请问我遗漏了什么?


问题原因与解决方法

核心问题

Markup Extension的ProvideValue方法仅在XAML初始化阶段执行一次,返回计算后的Color值。后续即使R属性(BindableProperty)的值通过绑定更新,也不会主动重新计算Color并同步到目标控件的Color属性上。

解决方案

需要在ProvideValue方法中获取目标控件和对应的目标属性,然后订阅R属性的变化事件,当R值改变时重新计算Color并更新目标属性。

修改后的RgbColorExtension代码如下:

namespace Sandbox;

public class RgbColorExtension : BindableObject, IMarkupExtension<Color>
{
    public static readonly BindableProperty RProperty =
        BindableProperty.Create(nameof(R), typeof(float), typeof(RgbColorExtension), 0.5f, propertyChanged: OnRPropertyChanged);

    public float R
    {
        get => (float)GetValue(RProperty);
        set => SetValue(RProperty, value);
    }

    public float G { get; set; }
    public float B { get; set; }
    public float A { get; set; }

    private BindableObject? _targetObject;
    private BindableProperty? _targetProperty;

    public Color ProvideValue(IServiceProvider serviceProvider)
    {
        // 获取目标对象和目标属性
        if (serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget targetService)
        {
            _targetObject = targetService.TargetObject as BindableObject;
            _targetProperty = targetService.TargetProperty as BindableProperty;
        }

        return UpdateColor();
    }

    object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
    {
        return (this as IMarkupExtension<Color>).ProvideValue(serviceProvider);
    }

    private static void OnRPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is RgbColorExtension extension)
        {
            extension.UpdateColor();
        }
    }

    private Color UpdateColor()
    {
        var color = Color.FromRgba(R, G, B, A);
        
        // 如果存在目标对象和属性,更新其值
        if (_targetObject != null && _targetProperty != null)
        {
            _targetObject.SetValue(_targetProperty, color);
        }
        
        return color;
    }
}

关键修改点说明

  • 给RProperty添加propertyChanged回调:当R属性值变化时触发OnRPropertyChanged方法,触发颜色更新逻辑。
  • 在ProvideValue中捕获目标对象和属性:通过IProvideValueTarget服务获取绑定的目标控件(如BoxView)和目标属性(ColorProperty),为后续更新UI做准备。
  • 新增UpdateColor方法:统一计算Color值,并在目标对象存在时更新其属性值,确保绑定变化后UI能实时刷新。

修改后,拖动Slider时R属性的变化会同步触发Color的重新计算,BoxView的颜色也会随之更新。


内容的提问来源于stack exchange,提问作者D G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 16:36:18