具有可绑定属性的IMarkupExtension

问题描述

我为IMarkupExtension创建了一个ImageSource,该FontimageExtension从指定的字体中获取指定的符号,并以指定的颜色和指定的高度显示它。大多数情况下,图标名称是静态的,因此我直接写入XAML。但是有时有些事物列表具有确定应使用哪个图标的属性在这种情况下,图标名称必须是可绑定的。

(或多或少)这是我的[contentproperty(nameof(IconName))] public class FontimageExtension : IMarkupExtension<ImageSource> { private readonly IconFontService iconFontService; [TypeConverter(typeof(FontSizeConverter))] public double Size { get; set; } = 30d; public string IconName { get; set; } public Color Color { get; set; } public string FontFamily { get; set; } public FontimageExtension() { iconFontService = SomeKindOfContainer.Resolve<IconFontService>(); } public ImageSource ProvideValue(IServiceProvider serviceProvider) { if (string.IsNullOrEmpty(IconName)) return null; IconFont iconFont = iconFontService.GetIconFont(); if (iconFont == null) return null; string glyphCode = iconFont.GetGlyphCode(IconName); if (string.IsNullOrEmpty(glyphCode)) return null; FontimageSource fontimageSource = new FontimageSource() { FontFamily = iconFont.GetPlatformlocation(),Glyph = glyphCode,Color = this.Color,Size = this.Size,}; return fontimageSource; } object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider) { return ProvideValue(serviceProvider); } } 的当前状态:

<Image Source="{m:Fontimage SomeIcon,Color=Black,Size=48}"/>

大多数时候,我都在XAML中使用它(它已经可以正常工作了):

<CollectionView ItemsSource={Binding SomeCollection}">
    <CollectionView.ItemTemplate>
        <StackLayout>
            <Image Source="{m:Fontimage IconName={Binding ItemIcon},Size=48}"/>
            <Label Text="{Binding ItemText}"/>
        </StackLayout>
    </CollectionView.ItemTemplate>
</CollectionView>

但是对于动态UI(例如列表等),我需要这样:

{{1}}

我该如何进行这项工作?

解决方法

似乎不能将IMarkupExtension与可绑定属性一起使用。因为只能在BindableObject的BindableProperty上设置“ Binding”。问题是MarkupExtension类不是从BindableObject派生的,这就是为什么它不是可以在其属性上设置绑定。尽管您让它实现BindableObject,但仍然无法正常工作。

一种解决方法是使用Value Converters

例如:

class ImageSourceConverter : IValueConverter
{
    public object Convert(object value,Type targetType,object parameter,CultureInfo culture)
    {
        var p = parameter.ToString().Split('|');
        string colorName = p[0];
        ColorTypeConverter colorTypeConverter = new ColorTypeConverter();
        Color color = (Color)colorTypeConverter.ConvertFromInvariantString(colorName);
        double fontSize = double.Parse(p[1]);

        //didn't test this here.
        IconFontService iconFontService = SomeKindOfContainer.Resolve<IconFontService();
        IconFont iconFont = iconFontService.GetIconFont();
        if (iconFont == null)
            return null;

        string glyphCode = iconFont.GetGlyphCode((string)value);
        if (string.IsNullOrEmpty(glyphCode))
            return null;

        FontImageSource fontImageSource = new FontImageSource()
        {
            FontFamily = iconFont.GetPlatformLocation(),Glyph = glyphCode,Color = color,Size = fontSize,};
        return fontImageSource;
    }

    public object ConvertBack(object value,CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

在您的xaml中使用:

<ContentPage.Resources>
    <ResourceDictionary>
        <local:ImageSourceConverter x:Key="imageConvert" />
    </ResourceDictionary>
</ContentPage.Resources>

<CollectionView ItemsSource={Binding SomeCollection}">
  <CollectionView.ItemTemplate>
    <StackLayout>
        <Image Source="{Binding Name,Converter={StaticResource imageConvert},ConverterParameter=Color.Black|48}"/>
        <Label Text="{Binding ItemText}"/>
    </StackLayout>
  </CollectionView.ItemTemplate>
</CollectionView>

也看到声明BindableProperty:IMarkupExtension with bindable property does not work的失败尝试,以及针对某种不同情况的更雄心勃勃的方法-可能相关:MarkupExtension for binding

,

除了IMarkupExtension之外,我还通过创建一个转换器(如@Leo Zhu建议)来解决了这个问题。因此,我的扩展名保持不变(加上在转换器中使用的常量值),转换器的代码如下:

public class FontIconConverter : IValueConverter,IMarkupExtension
{
    private IServiceProvider serviceProvider;

    public Color Color { get; set; }

    [TypeConverter(typeof(FontSizeConverter))]
    public double Size { get; set; } = FontIconExtension.DefaultFontSize;

    public string FontFamily { get; set; }

    public FontIconConverter()
    {
    }

    public object Convert(object value,CultureInfo culture)
    {
        if (!(value is string iconName))
            return null;

        var fontIcon = new FontIconExtension()
        {
            IconName = iconName,Color = Color,Size = Size,FontFamily = FontFamily,};

        return fontIcon.ProvideValue(serviceProvider);
    }

    public object ConvertBack(object value,CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    public object ProvideValue(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
        return this;
    }
}

然后可以像这样使用它:

<Image Source="{Binding IconNameProperty,Converter={c:FontIconConverter Color=Black,Size=48}}"/>

对于静态值,它保持这样:

<Image Source="{m:FontImage SomeIconsName,Color=Black,Size=48}"/>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...