具有可绑定属性的IMarkupExtension

问题描述 投票:0回答:3

我为

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

这是(或多或少)我的

FontImageExtension
的当前状态:

[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);
    }
}

大多数时候我在 XAML 中像这样使用它(它已经完美运行):

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

但是对于动态 UI(例如列表或其他东西)我需要这样:

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

我怎样才能做到这一点?

c# xaml xamarin binding markup-extensions
3个回答
1
投票

看来你不能将

IMarkupExtension
与可绑定属性一起使用。因为“绑定”只能在 BindableObject 的 BindableProperty 上设置。问题是 MarkupExtension 类不是从 BindableObject 派生的,这就是为什么无法设置绑定虽然你让它实现了 BindableObject,但它仍然无法工作。

解决方法是使用值转换器

例如:

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, Type targetType, object parameter, 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 不起作用,以及针对有些不同情况的更雄心勃勃的方法 - 可能相关:用于绑定的 MarkupExtension。


1
投票
我通过创建一个转换器(就像@Leo Zhu建议的那样)解决了这个问题,但除了

IMarkupExtension

之外。因此,我的扩展保持原样(添加了转换器中使用的常量值),转换器的代码如下:

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, Type targetType, object parameter, 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, Type targetType, object parameter, 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}"/>
    

0
投票
您实际上可以同时实现 (1)

FontImageExtension

、(2) 
BindableObject
IMarkupExtension
 标记扩展:
IMultiValueConverter


最新问题
© www.soinside.com 2019 - 2024. All rights reserved.