圖像控件演示XAML的一個有趣屬性,稱爲類型轉換。例如,對於圖像的XAML API是這樣的:
<Image Source="http://lorempixel.com/100/100/people" />
然而,編程API是這樣的:
class Image {
ImageSource Source { get; set;}
DependencyProperty SourceProperty // etc.
}
怎麼字符串得到變成了一個開放的,然後變成了一個ImageSource的?
答案在於TypeConverters。
[TypeConverter(typeof(ImageSourceConverter))]
public class ImageSource {}
當我們以編程方式創建一個綁定到Uri,上面的魔術不會發生。結果是沒有圖片顯示。
// No picture is shown.
BindingOperations.SetBinding(myImage,
Image.SourceProperty, new Binding("MyUri"));
同樣,我們不能做到這一點:
// compile time error
myImage.Source = new Uri("http://...")
相反,正確的方法是取從ImageSource的的自定義屬性的類型轉換器和按摩到一個的IValueConverter。下面是我的 - 主要工作是通過這一條線上public object Convert(...)
執行 - 一切是腳手架:
namespace Caliburn.Micro
{
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
public class ValueTypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var result = TypeDescriptor.GetConverter(targetType).ConvertFrom(value);
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
/// <summary>
/// Binding Image.Source to an Uri typically fails.
/// Calling the following during application bootstrap will set this up properly.
/// ConventionManager.ApplyValueConverter = ValueTypeConverter.ApplyValueConverter;
/// </summary>
/// <param name="binding"></param>
/// <param name="bindableProperty"></param>
/// <param name="info"></param>
public static void ApplyValueConverter(Binding binding, DependencyProperty bindableProperty, PropertyInfo info)
{
if (bindableProperty == UIElement.VisibilityProperty && typeof(bool).IsAssignableFrom(info.PropertyType))
binding.Converter = ConventionManager.BooleanToVisibilityConverter;
else if (bindableProperty == Image.SourceProperty && typeof(Uri).IsAssignableFrom(info.PropertyType))
binding.Converter = new ValueTypeConverter();
else
{
foreach (var item in _Conventions)
{
if (bindableProperty == item.Item1 && item.Item2.IsAssignableFrom(info.PropertyType))
binding.Converter = new ValueTypeConverter();
}
}
}
/// <summary>
/// If there is a TypeConverter that can convert a <paramref name="SourceType"/>
/// to the type on <paramref name="bindableProperty"/>, then this has to
/// be manually registered with Caliburn.Micro as Silverlight is unable to
/// extract sufficient TypeConverter information from a dependency property
/// on its own.
/// </summary>
/// <example>
/// ValueTypeConverter.AddTypeConverter<ImageSource>(Image.SourceProperty);
/// </example>
/// <typeparam name="SourceType"></typeparam>
/// <param name="bindableProperty"></param>
public static void AddTypeConverter<SourceType>(DependencyProperty bindableProperty)
{
_Conventions.Add(Tuple.Create<DependencyProperty, Type>(bindableProperty, typeof(SourceType)));
}
private static IList<Tuple<DependencyProperty, Type>> _Conventions = new List<Tuple<DependencyProperty, Type>>();
}
}
然後在引導程序,我們連線了新的IValueConverter:
protected override void Configure()
{
// ...
ConventionManager.ApplyValueConverter =
ValueTypeConverter.ApplyValueConverter;
}
Caliburn不允許簡單地寫' '?對我來說看起來好多了。 –
Clemens
請注意*強制*表示不同的意思。你的意思是所謂的類型轉換。 – Clemens
你說的都對。謝謝。我實際上正在研究使用類型轉換來顯示可以被用戶替換的圖像,因爲它似乎是隱藏大部分相關複雜性的好方法。 –