Question

Avec le code suivant, bien que la propriété Text est liée à une propriété source DateTime, j'ai remarqué que WPF semble convertir automatiquement le texte en une heureTetime, sans que je puisse avoir besoin d'écrire un ValueConverter.Quelqu'un peut-il faire une lumière sur la façon dont cela se fait

<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;
        }
    }

Était-ce utile?

La solution

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"/>

Autres conseils

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

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top