ToString()
上object
和ICommand
聲明不是object
這是一個接口。它只有可分配到object
。
正如您所說,綁定系統並不區分聲明的類型。但默認IValueConverter
用於轉換爲string
的情況。
當沒有給出用戶定義的轉換器時,框架內部使用DefaultValueConverter
。在Create
方法,你可以看到爲什麼界面會採取不同的那麼這裏的對象(外觀爲sourceType.IsInterface
特殊檢查):
internal static IValueConverter Create(Type sourceType,
Type targetType,
bool targetToSource,
DataBindEngine engine)
{
TypeConverter typeConverter;
Type innerType;
bool canConvertTo, canConvertFrom;
bool sourceIsNullable = false;
bool targetIsNullable = false;
// sometimes, no conversion is necessary
if (sourceType == targetType ||
(!targetToSource && targetType.IsAssignableFrom(sourceType)))
{
return ValueConverterNotNeeded;
}
// the type convert for System.Object is useless. It claims it can
// convert from string, but then throws an exception when asked to do
// so. So we work around it.
if (targetType == typeof(object))
{
// The sourceType here might be a Nullable type: consider using
// NullableConverter when appropriate. (uncomment following lines)
//Type innerType = Nullable.GetUnderlyingType(sourceType);
//if (innerType != null)
//{
// return new NullableConverter(new ObjectTargetConverter(innerType),
// innerType, targetType, true, false);
//}
//
return new ObjectTargetConverter(sourceType, engine);
}
else if (sourceType == typeof(object))
{
// The targetType here might be a Nullable type: consider using
// NullableConverter when appropriate. (uncomment following lines)
//Type innerType = Nullable.GetUnderlyingType(targetType);
// if (innerType != null)
// {
// return new NullableConverter(new ObjectSourceConverter(innerType),
// sourceType, innerType, false, true);
// }
//
return new ObjectSourceConverter(targetType, engine);
}
// use System.Convert for well-known base types
if (SystemConvertConverter.CanConvert(sourceType, targetType))
{
return new SystemConvertConverter(sourceType, targetType);
}
// Need to check for nullable types first, since NullableConverter is a bit over-eager;
// TypeConverter for Nullable can convert e.g. Nullable<DateTime> to string
// but it ends up doing a different conversion than the TypeConverter for the
// generic's inner type, e.g. bug 1361977
innerType = Nullable.GetUnderlyingType(sourceType);
if (innerType != null)
{
sourceType = innerType;
sourceIsNullable = true;
}
innerType = Nullable.GetUnderlyingType(targetType);
if (innerType != null)
{
targetType = innerType;
targetIsNullable = true;
}
if (sourceIsNullable || targetIsNullable)
{
// single-level recursive call to try to find a converter for basic value types
return Create(sourceType, targetType, targetToSource, engine);
}
// special case for converting IListSource to IList
if (typeof(IListSource).IsAssignableFrom(sourceType) &&
targetType.IsAssignableFrom(typeof(IList)))
{
return new ListSourceConverter();
}
// Interfaces are best handled on a per-instance basis. The type may
// not implement the interface, but an instance of a derived type may.
if (sourceType.IsInterface || targetType.IsInterface)
{
return new InterfaceConverter(sourceType, targetType);
}
// try using the source's type converter
typeConverter = GetConverter(sourceType);
canConvertTo = (typeConverter != null) ? typeConverter.CanConvertTo(targetType) : false;
canConvertFrom = (typeConverter != null) ? typeConverter.CanConvertFrom(targetType) : false;
if ((canConvertTo || targetType.IsAssignableFrom(sourceType)) &&
(!targetToSource || canConvertFrom || sourceType.IsAssignableFrom(targetType)))
{
return new SourceDefaultValueConverter(typeConverter, sourceType, targetType,
targetToSource && canConvertFrom, canConvertTo, engine);
}
// if that doesn't work, try using the target's type converter
typeConverter = GetConverter(targetType);
canConvertTo = (typeConverter != null) ? typeConverter.CanConvertTo(sourceType) : false;
canConvertFrom = (typeConverter != null) ? typeConverter.CanConvertFrom(sourceType) : false;
if ((canConvertFrom || targetType.IsAssignableFrom(sourceType)) &&
(!targetToSource || canConvertTo || sourceType.IsAssignableFrom(targetType)))
{
return new TargetDefaultValueConverter(typeConverter, sourceType, targetType,
canConvertFrom, targetToSource && canConvertTo, engine);
}
// nothing worked, give up
return null;
}
根據綁定到不同的屬性時,你應該提供一個用戶定義的IValueConverter
文檔因爲依賴於被調用的ToString
是一個框架默認轉換機制的實現細節(並且據我所知,它沒有記錄,它只爲明確定義的情況指定默認值和回退值),並且可能會改變任何時候。
這是真的,但爲什麼WPF首先查看聲明的屬性類型?它不應該只是看看實際返回的內容嗎? –
已編輯。 InterfaceConverter的行爲與其他行爲不同。這是來自C#4.0源代碼。所以我最初的答案是有點關閉,更多的是因爲Type.IsInterface將爲不同的聲明屬性類型返回不同的值。 – MrDosu
我注意到的一件有趣的事情是,如果我將屬性聲明爲「MyExampleCommand」(預先設置「public」類型),則該按鈕仍然爲空。如果'MyExampleCommand'不再實現'ICommand',則正確調用'ToString'。這是如何相關的,也就是說爲什麼實現一些在Propery聲明中沒有直接提到的接口會改變什麼? –