2012-03-08 38 views
4

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

回答

4

它使用来自基类库的DateTimeTypeConverter编辑:那么,它也可以使用的TypeConverter,但似乎从@DeviantSeev's answer他们没有)。

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

plentyarticles可用,如果你想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。例如,WPF中的一个非常常见的操作是将bool转换为Visibility;有三种可能的输出来自这种转换(Visible,Hidden,Collapsed),并且只有两个输入(true,false)很难在TypeConverter中决定。

在我的应用程序,来实现这个两个输入三个输出问题,我在全球ResourceDictionary写一个BoolToVisibilityConverterTrueValueFalseValue属性,然后我实例三次。 明天早上我会发布代码示例,现在我不在眼前。

[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"/> 
+0

感谢Dennis,但是那么您何时需要编写自己的IValueConverter?据推测,涉及的房产类型没有定义转换器? – sturdytree 2012-03-08 22:10:37

+0

我的理解是TypeConverters主要被WPF用来将XAML属性值(它们都是字符串)转换为相关的对象,例如Point =“10,10”会导致WPF使用PointConverter。 – sturdytree 2012-03-08 22:24:13

+0

编辑发布并回复您的评论,因为评论字段中没有足够的空间足够详细地解释。 – Dennis 2012-03-08 22:29:58

1

的DatePicker的是,最初的WPF工具包的一部分自定义控件被添加作为标准控制在.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 
+0

谢谢DeviantSeev,但我相信代码不会将字符串转换为DateTime? – sturdytree 2012-03-08 22:15:35

+0

这个类还有其他的代码,我只是拿出了Text部分。正如你所看到的,有一个名为OnTextChanged的方法,它处理文本的更改并调用db.SetSelectedDate方法,以便将实际日期设置为新值。我不想粘贴整个类,因为它很大,所以你可以在这里找到它:http://wpf.codeplex.com/SourceControl/changeset/view/40156#370450 – evasilchenko 2012-03-08 22:25:05

+0

在该类中找到名为SetSelectedDate的函数并查看通过名为DateTimeToString的另一个函数将字符串转换为dateTime,该函数执行实际的转换。不需要转换器,因为在这个自定义控件中,他们正在控制类中处理转换。 – evasilchenko 2012-03-08 22:28:09

0

在大多数情况下,我相信WPF是愈伤组织NG的ToString()为您但是如果你看一下代码,日期选择器的重要线路

(string)GetValue(TextProperty) 

通知它蒙上你分配到“文本”属性设置为一个字符串值?整个观点是没有更传统意义上的BooleanToVisibilityConverter或类似的默认转换器。

+1

谢谢Kenn,但问题是我们如何从字符串中获取DateTime - 上面的Dennis指示涉及TypeConverter – sturdytree 2012-03-08 22:12:08