When do default converters kick in?

我的梦境 提交于 2019-12-10 14:56:09

问题


With the following code, although Text property is bound to a DateTime source property, I noticed WPF seems to automatically convert the text to a DateTime, without me needing to write a ValueConverter. Can someone please shed some light on how this is done

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:WpfApplication1="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525"
        >    
    <StackPanel>
        <DatePicker Height="25" Name="datePicker1" Width="213" Text="{Binding Path=DueDate,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
    </StackPanel>
</Window>
public class P
    {
        private DateTime? dueDate = DateTime.Now;
        public DateTime? DueDate
        {
            get { return dueDate; }
            set 
            { 
                dueDate = value;
            }
        }
    }

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            P p = new P();
            this.DataContext = p;
        }
    }

回答1:


It is using the DateTimeTypeConverter from the Base Class Library (EDIT: Well, it could have used a TypeConverter however it appears that from @DeviantSeev's answer that they did not).

There 'default' converters you are talking about are actually TypeConverters (MSDN) and they have been a part of the .NET Framework since v2.0 and they are used through-out the Base Class Libraries. Another example of TypeConverters in WPF is the ThicknessTypeConverter for Padding, Margin, and BorderThickness properties. It converts a comma-delimited string to a Thickness object.

There are plenty of articles available if you want to understand them further.

There are two parts to using a TypeConverter - implementation of the class and then marking up your properties/types with TypeConverterAttribute.

For example, I recently had a custom control that required a char[] that I wanted to set from Xaml like so:

<AutoCompleteTextBox MultiInputDelimiters=",;. " />

Usage

[TypeConverter(typeof(CharArrayTypeConverter))]
public char[] MultiInputDelimiters
{
      get { return (char[])GetValue(MultiInputDelimitersProperty); }
      set { SetValue(MultiInputDelimitersProperty, value); }
}

Implementation

public class CharArrayTypeConverter : TypeConverter
{

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return (Type.GetTypeCode(sourceType) == TypeCode.String);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        if (value is string)
            return ((string)value).ToCharArray();

        return value;
    }

}

When to use a TypeConverter?

You can only use TypeDescriptors if you are writing a custom control as you need to be able to mark-up the property with the TypeDescriptorAttribute. Also I would only use TypeConverter if the conversion is rather a straight-forward - as in the example above where I have a string and want a char[] - or if there are multiple possible formats that I want to convert from.

You write IValueConverter when you want more flexibility on how the value to converted by driving it by data or a passing a parameter. For example, a very common action in WPF is converting a bool to Visibility; there are three possible outputs from such a conversion (Visible, Hidden, Collapsed) and with only two inputs (true, false) it difficult to decide this in a TypeConverter.

In my applications, to achieve this two inputs to three output problem I have written a single BoolToVisibilityConverter with a TrueValue and FalseValue properties and then I instance it three times in my global ResourceDictionary. I'll post the code sample tomorrow morning, I don't it in front of me right now..

[ValueConversion(typeof(bool), typeof(Visibility))]
public class BooleanToVisibilityConverter : IValueConverter
{
    public Visibility FalseCondition { get; set; }
    public Visibility TrueCondition { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ((bool)value) ? TrueCondition : FalseCondition;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if ((bool)value)
            return TrueCondition;

        return FalseCondition;
    }
}

<converters:BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" FalseCondition="Collapsed" TrueCondition="Visible"/>
<converters:BooleanToVisibilityConverter x:Key="BoolToVisibilityCollapsedConverter" FalseCondition="Visible" TrueCondition="Collapsed"/>
<converters:BooleanToVisibilityConverter x:Key="BoolToVisibilityHiddenConverter" FalseCondition="Visible" TrueCondition="Hidden"/>
<converters:BooleanToVisibilityConverter x:Key="BoolToVisibilityHiddenWhenFalseConverter" FalseCondition="Hidden" TrueCondition="Visible"/>



回答2:


The DatePicker is a custom control that was initially part of the WPF Toolkit before being added as a standard control in .NET 4.

I just went to the source code repository for the control to find you the exact source code which is responsible for the conversion of the text to date:

#region Text

    /// <summary>
    /// Gets or sets the text that is displayed by the DatePicker.
    /// </summary>
    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    /// <summary>
    /// Identifies the Text dependency property.
    /// </summary>
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register(
        "Text",
        typeof(string),
        typeof(DatePicker),
        new FrameworkPropertyMetadata(string.Empty, OnTextChanged, OnCoerceText));

    /// <summary>
    /// TextProperty property changed handler.
    /// </summary>
    /// <param name="d">DatePicker that changed its Text.</param>
    /// <param name="e">DependencyPropertyChangedEventArgs.</param>
    private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        DatePicker dp = d as DatePicker;
        Debug.Assert(dp != null);

        if (!dp.IsHandlerSuspended(DatePicker.TextProperty))
        {
            string newValue = e.NewValue as string;

            if (newValue != null)
            {
                if (dp._textBox != null)
                {
                    dp._textBox.Text = newValue;
                }
                else
                {
                    dp._defaultText = newValue;
                }

                dp.SetSelectedDate();
            }
            else
            {
                dp.SetValueNoCallback(DatePicker.SelectedDateProperty, null);
            }
        }
    }

    private static object OnCoerceText(DependencyObject dObject, object baseValue)
    {
        DatePicker dp = (DatePicker)dObject;
        if (dp._shouldCoerceText)
        {
            dp._shouldCoerceText = false;
            return dp._coercedTextValue;
        }

        return baseValue;
    }

    /// <summary>
    /// Sets the local Text property without breaking bindings
    /// </summary>
    /// <param name="value"></param>
    private void SetTextInternal(string value)
    {
        if (BindingOperations.GetBindingExpressionBase(this, DatePicker.TextProperty) != null)
        {
            Text = value;
        }
        else
        {
            _shouldCoerceText = true;
            _coercedTextValue = value;
            CoerceValue(TextProperty);
        }
    }

    #endregion Text



回答3:


In most cases I believe WPF is calling ToString() for you however if you look at the code for the date picker the important line is

(string)GetValue(TextProperty)

notice it casts the value you assigned to the "Text" property to a string? The whole point is there is no default converter in the more traditional sense of BooleanToVisibilityConverter or something like that.



来源:https://stackoverflow.com/questions/9624915/when-do-default-converters-kick-in

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!