问题描述
我为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}"/>