Этот код (вдохновленный от DefaultValueConverter.cs @ referencesource.microsoft.com) работает на два пути связывания с TextBox или подобным контролем, до тех пор, как FormatString оставляет версию ToString() свойство источника в состоянии, которое может быть преобразовано обратно. (т. Е. Формат «#, 0.00» в порядке, потому что «1,234.56» можно разобрать, но FormatString = «Some Prefix Text #, 0.00» преобразуется в «Some Prefix Text 1,234.56», который не может быть проанализирован обратно.)
XAML:
<TextBox>
<TextBox.Text>
<MultiBinding Converter="{StaticResource ToStringFormatConverter}"
ValidatesOnDataErrors="True" NotifyOnValidationError="True" TargetNullValue="">
<Binding Path="Property" TargetNullValue="" />
<Binding Path="PropertyStringFormat" Mode="OneWay" />
</MultiBinding>
</TextBox.Text>
</TextBox>
Примечание дублируют TargetNullValue если свойство источника может быть пустым.
C#:
/// <summary>
/// Allow a binding where the StringFormat is also bound to a property (and can vary).
/// </summary>
public class ToStringFormatConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length == 1)
return System.Convert.ChangeType(values[0], targetType, culture);
if (values.Length >= 2 && values[0] is IFormattable)
return (values[0] as IFormattable).ToString((string)values[1], culture);
return null;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
var targetType = targetTypes[0];
var nullableUnderlyingType = Nullable.GetUnderlyingType(targetType);
if (nullableUnderlyingType != null) {
if (value == null)
return new[] { (object)null };
targetType = nullableUnderlyingType;
}
try {
object parsedValue = ToStringFormatConverter.TryParse(value, targetType, culture);
return parsedValue != DependencyProperty.UnsetValue
? new[] { parsedValue }
: new[] { System.Convert.ChangeType(value, targetType, culture) };
} catch {
return null;
}
}
// Some types have Parse methods that are more successful than their type converters at converting strings
private static object TryParse(object value, Type targetType, CultureInfo culture)
{
object result = DependencyProperty.UnsetValue;
string stringValue = value as string;
if (stringValue != null) {
try {
MethodInfo mi;
if (culture != null
&& (mi = targetType.GetMethod("Parse",
BindingFlags.Public | BindingFlags.Static, null,
new[] { typeof(string), typeof(NumberStyles), typeof(IFormatProvider) }, null))
!= null) {
result = mi.Invoke(null, new object[] { stringValue, NumberStyles.Any, culture });
}
else if (culture != null
&& (mi = targetType.GetMethod("Parse",
BindingFlags.Public | BindingFlags.Static, null,
new[] { typeof(string), typeof(IFormatProvider) }, null))
!= null) {
result = mi.Invoke(null, new object[] { stringValue, culture });
}
else if ((mi = targetType.GetMethod("Parse",
BindingFlags.Public | BindingFlags.Static, null,
new[] { typeof(string) }, null))
!= null) {
result = mi.Invoke(null, new object[] { stringValue });
}
} catch (TargetInvocationException) {
}
}
return result;
}
}
Это хорошее предложение. Я должен посмотреть на это. Я как бы надеялся, что будет решение, которое не связано с пользовательскими элементами управления, но я, безусловно, открыт для него. Я вернусь после небольшого исследования. –
Я пытаюсь сделать то же самое, но я не уверен, как настроить прикрепленные свойства, чтобы справиться с этим. Я разместил новый вопрос: http://stackoverflow.com/q/24119097/65461 –