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

Xamarin中对象属性无法绑定到AppThemeBinding的问题

Xamarin AppThemeBinding 绑定自定义控件属性失效的解决办法

问题核心是AppThemeBinding本身不支持嵌套{Binding}表达式——它的Dark/Light参数仅接受静态资源键或直接的ImageSource值,没法直接绑定到数据源的属性上,这就是你两种写法都失效的原因。而单独绑定DarkImage/LightImage是直接绑定数据源属性,所以能正常工作。

这里给你两种可行的解决思路:

方案一:ViewModel层面处理主题切换(推荐)

在ViewModel里维护一个对应当前主题的图片属性,监听系统主题变化自动切换图片,然后直接绑定这个属性到自定义控件。

1. 改造ViewModel

实现INotifyPropertyChanged,添加CurrentImage属性,并订阅主题变化事件:

using Xamarin.Essentials;
using System.ComponentModel;
using System.Runtime.CompilerServices;

public class YourItemViewModel : INotifyPropertyChanged
{
    // 原有属性
    public ImageSource DarkImage { get; set; }
    public ImageSource LightImage { get; set; }

    // 对应当前主题的图片属性
    private ImageSource _currentImage;
    public ImageSource CurrentImage
    {
        get => _currentImage;
        set
        {
            _currentImage = value;
            OnPropertyChanged();
        }
    }

    public YourItemViewModel()
    {
        // 初始化时设置当前主题对应的图片
        UpdateCurrentImage(AppInfo.RequestedTheme);
        // 订阅主题变化事件
        AppInfo.AppThemeChanged += OnAppThemeChanged;
    }

    private void OnAppThemeChanged(object sender, AppThemeChangedEventArgs e)
    {
        UpdateCurrentImage(e.RequestedTheme);
    }

    private void UpdateCurrentImage(AppTheme theme)
    {
        CurrentImage = theme == AppTheme.Dark ? DarkImage : LightImage;
    }

    // INotifyPropertyChanged实现
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. XAML绑定修改

直接绑定自定义控件的Source到CurrentImage:

<CollectionView.ItemTemplate>
    <DataTemplate>
        <local:YourCustomControl Source="{Binding CurrentImage}" />
    </DataTemplate>
</CollectionView.ItemTemplate>

方案二:自定义附加属性(进阶)

如果不想修改ViewModel,可以自定义一个附加属性,在控件层面处理主题绑定逻辑。不过这种方式代码量更大,适合需要复用多个控件的场景:

1. 创建附加属性类

using Xamarin.Forms;

public class ThemeImageBinding : BindableObject
{
    public static readonly BindableProperty DarkImageProperty =
        BindableProperty.CreateAttached("DarkImage", typeof(ImageSource), typeof(ThemeImageBinding), null, propertyChanged: OnImageChanged);

    public static readonly BindableProperty LightImageProperty =
        BindableProperty.CreateAttached("LightImage", typeof(ImageSource), typeof(ThemeImageBinding), null, propertyChanged: OnImageChanged);

    public static ImageSource GetDarkImage(BindableObject view)
    {
        return (ImageSource)view.GetValue(DarkImageProperty);
    }

    public static void SetDarkImage(BindableObject view, ImageSource value)
    {
        view.SetValue(DarkImageProperty, value);
    }

    public static ImageSource GetLightImage(BindableObject view)
    {
        return (ImageSource)view.GetValue(LightImageProperty);
    }

    public static void SetLightImage(BindableObject view, ImageSource value)
    {
        view.SetValue(LightImageProperty, value);
    }

    private static void OnImageChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is YourCustomControl customControl)
        {
            UpdateCustomControlSource(customControl);
        }
    }

    private static void UpdateCustomControlSource(YourCustomControl control)
    {
        var theme = Application.Current.RequestedTheme;
        var darkImage = GetDarkImage(control);
        var lightImage = GetLightImage(control);
        control.Source = theme == OSAppTheme.Dark ? darkImage : lightImage;
    }

    // 监听主题变化
    static ThemeImageBinding()
    {
        Application.Current.RequestedThemeChanged += (s, e) =>
        {
            foreach (var page in Application.Current.MainPage.Navigation.NavigationStack)
            {
                UpdateAllControls(page);
            }
        };
    }

    private static void UpdateAllControls(Element element)
    {
        if (element is YourCustomControl customControl)
        {
            UpdateCustomControlSource(customControl);
        }

        if (element is Layout layout)
        {
            foreach (var child in layout.Children)
            {
                UpdateAllControls(child);
            }
        }
    }
}

2. XAML中使用附加属性

<CollectionView.ItemTemplate>
    <DataTemplate>
        <local:YourCustomControl 
            local:ThemeImageBinding.DarkImage="{Binding DarkImage}"
            local:ThemeImageBinding.LightImage="{Binding LightImage}" />
    </DataTemplate>
</CollectionView.ItemTemplate>

两种方案里,方案一更简单易维护,适合大多数场景;方案二适合需要在多个控件上复用主题绑定逻辑的情况。

内容的提问来源于stack exchange,提问作者Stefan Vogel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 23:30:32