Когда запускаются конвертеры по умолчанию?

StackOverflow https://stackoverflow.com//questions/9624915

  •  09-12-2019
  •  | 
  •  

Вопрос

С помощью следующего кода, хотя свойство 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;
        }
    }
Это было полезно?

Решение

Он использует DateTimeTypeConverter из библиотеки базового класса (Редактировать: Ну, он мог бы использовать TypeConverter, однако, похоже, что из Ответ @deviantseev's этого они не сделали).

Конвертеры "по умолчанию", о которых вы говорите, на самом деле являются TypeConverters (MSDN) и они были частью .NET Framework начиная с версии 2.0, и они используются во всех библиотеках базовых классов.Другим примером преобразователей типов в WPF является ThicknessTypeConverter для Padding, Margin, и BorderThickness свойства.Он преобразует строку, разделенную запятыми, в Thickness объект.

Есть такие много из Статьи доступно, если вы хотите разберитесь в них подробнее.

Использование a состоит из двух частей 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.

В моих приложениях для решения этой задачи с двумя входами и тремя выходами я написал один BoolToVisibilityConverter с помощью TrueValue и FalseValue свойства, а затем я создаю его экземпляр три раза в моем глобальном ResourceDictionary. Я опубликую пример кода завтра утром, прямо сейчас он у меня перед глазами..

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

Другие советы

Дата 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
.

В большинстве случаев я считаю, что WPF вызывает TOSTRING () для вас, однако, если вы посмотрите на код для сборщика даты Важная строка -

(string)GetValue(TextProperty)
.

Обратите внимание, что он отличает значение, которое вы назначаете на свойство «Text» в строку?Весь смысл в том, что нет преобразователя по умолчанию в более традиционном чувстве булентноупотребления контроллера или что-то подобное.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top