WPF Binding and Dynamically Assigning StringFormat Property

前端 未结 5 1311
慢半拍i
慢半拍i 2021-01-04 12:06

I have a form that is generated based on several DataTemplate elements. One of the DataTemplate elements creates a TextBox out of a class that looks like this:



        
5条回答
  •  萌比男神i
    2021-01-04 12:15

    This code (inspired from DefaultValueConverter.cs @ referencesource.microsoft.com) works for a two way binding to a TextBox or similar control, as long as the FormatString leaves the ToString() version of the source property in a state that can be converted back. (i.e. format like "#,0.00" is OK because "1,234.56" can be parsed back, but FormatString="Some Prefix Text #,0.00" will convert to "Some Prefix Text 1,234.56" which can't be parsed back.)

    XAML:

    
        
            
                
                
            
        
    
    

    Note duplicate TargetNullValue if the source property can be null.

    C#:

    /// 
    /// Allow a binding where the StringFormat is also bound to a property (and can vary).
    /// 
    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;
        }
    }
    

提交回复
热议问题