什么时候默认转换器启动?

时间:2012-03-08 21:03:56

标签: wpf converters

使用以下代码,虽然Text属性绑定到DateTime源属性,但我注意到WPF似乎自动将文本转换为DateTime,而不需要编写ValueConverter。有人可以说明如何做到这一点

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

3 个答案:

答案 0 :(得分:5)

它正在使用基类库中的DateTimeTypeConverter编辑:嗯,它可能使用了TypeConverter,但它似乎来自@DeviantSeev's answer他们没有)

您所谈论的'默认'转换器实际上是TypeConvertersMSDN),它们自v2.0以来一直是.NET Framework的一部分,它们在整个Base中使用类库。 WPF中TypeConverters的另一个示例是ThicknessTypeConverterPaddingMargin属性的BorderThickness。它将逗号分隔的字符串转换为Thickness对象。

如果您想plenty,可以articles understand them further

使用TypeConverter有两个部分 - 类的实现,然后用TypeConverterAttribute标记属性/类型。

例如,我最近有一个自定义控件需要char[],我想从Xaml设置<AutoCompleteTextBox MultiInputDelimiters=",;. " /> ,如下所示:

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

<强>用法

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

}

<强>实施

TypeConverter

何时使用TypeDescriptors

如果您正在编写自定义控件,则只能使用TypeDescriptorAttribute,因为您需要能够使用TypeConverter标记属性。此外,我只会使用char[],如果转换相当简单 - 如上例中我有一个字符串并想要IValueConverter - 或者我想要多种可能的格式转换自。

当您希望通过数据驱动或传递参数来更灵活地转换值时,可以编写bool。例如,WPF中一个非常常见的操作是将Visibility转换为Visible;这种转换有三种可能的输出(HiddenCollapsedtrue),只有两个输入(falseTypeConverter)很难确定这是BoolToVisibilityConverter

在我的应用程序中,要实现这两个输入到三个输出问题,我编写了一个TrueValue FalseValueResourceDictionary属性,然后我在全局实例三次[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"/> 我明天早上会发布代码示例,我现在不在我面前。

{{1}}

答案 1 :(得分:1)

DatePicker是一个自定义控件,最初是WPF Toolkit的一部分,之后作为.NET 4中的标准控件添加。

我刚刚访问控件的源代码存储库,找到了负责将文本转换为日期的确切源代码:

#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

答案 2 :(得分:0)

在大多数情况下,我相信WPF会为您调用ToString(),但是如果您查看日期选择器的代码,重要的一行是

(string)GetValue(TextProperty)

请注意,它将您分配给“Text”属性的值强制转换为字符串?重点是更传统的BooleanToVisibilityConverter或类似的东西没有默认转换器。