When are default converters inserted?

With the following code, although the Text property is tied to the DateTime source property, I noticed that WPF automatically converts the text to DateTime, without having to write a ValueConverter. Can someone shed 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; } } 
+4
source share
3 answers

It uses a DateTimeTypeConverter from the base class library ( EDIT: Well, it could use TypeConverter, however, it looks like from @DeviantSeev answer that they didn't.)

The default modes you are talking about are actually TypeConverters ( MSDN ), and they have been part of the .NET Framework since version 2.0, and they are used through the base class libraries. Another example of TypeConverters in WPF are the ThicknessTypeConverter properties for Padding , Margin and BorderThickness . It converts a comma-delimited string to a Thickness object.

There are many articles if you want to understand them further .

There are two parts to using TypeConverter - implementing the class, and then labeling your properties / types with TypeConverterAttribute .

For example, I recently had a user control that required the char[] that I wanted to install from Xaml , for example:

 <AutoCompleteTextBox MultiInputDelimiters=",;. " /> 

Using

 [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 TypeConverter ?

You can only use TypeDescriptors if you are writing a custom control, since you need to mark the property with TypeDescriptorAttribute . Also, I would use only TypeConverter if the conversion is rather straightforward - as in the example above, where I have a string and you want char[] , or if there are several possible formats from which I want to convert.

You write IValueConverter when you need extra flexibility about how a value is converted by manipulating it with data or passing a parameter. For example, a very frequent action in WPF converts a bool to Visibility ; There are three possible ways out of such a conversion ( Visible , Hidden , Collapsed ) and with only two inputs ( true , false ) this is difficult to solve in TypeConverter .

In my applications, to achieve these two inputs for three output tasks, I wrote one BoolToVisibilityConverter with TrueValue and FalseValue properties, and then I instantiated it three times in my global ResourceDictionary . I will send a sample code tomorrow morning, I am not 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"/> 
+4
source

DatePicker is a custom control that was originally part of the WPF toolkit before it was 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 that is responsible for the text conversion today:

 #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 
+1
source

In most cases, I think WPF calls ToString () for you, however, if you look at the code to select a date, the important line

 (string)GetValue(TextProperty) 

Note that it passes the value assigned to the Text property to a string? The thing is that in the more traditional sense of BooleanToVisibilityConverter there is no such converter by default or something like that.

0
source

Source: https://habr.com/ru/post/1400467/


All Articles