Когда используются стандартные конвертеры? - PullRequest
5 голосов
/ 09 марта 2012

В следующем коде, хотя свойство 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 ]

5 голосов
/ 09 марта 2012

Он использует DateTimeTypeConverter из библиотеки базовых классов ( РЕДАКТИРОВАТЬ: Ну, он мог бы использовать TypeConverter, однако, похоже, что из @ DeviantSeev ответа , что они не сделали ).

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

Есть множество из статей , доступных, если вы хотите понять их подробнее .

Существует две части использования 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"/>
1 голос
/ 09 марта 2012

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
0 голосов
/ 09 марта 2012

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

(string)GetValue(TextProperty)

заметили, что оно преобразует значение, которое вы присвоили свойству "Текст", в строку? Все дело в том, что нет конвертера по умолчанию в более традиционном смысле BooleanToVisibilityConverter или чего-то в этом роде.

...