[WPF] ComboBox with DateTime, Binding, Converter + Formating
От: master_of_shadows Беларусь  
Дата: 24.02.11 15:57
Оценка:
Есть вот такой ComboBox который по дизайну должен содержать только даты в формате MM/dd/yyyy:

<System:String x:Key="dateTimeFormat">{0:d}</System:String>
...
<ComboBox ItemsSource="{Binding Source={StaticResource Dates}}"
    Text="{Binding EndDate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource DateFromDateTimeConverter},
       ValidatesOnDataErrors=True, ValidatesOnExceptions=True, NotifyOnValidationError=True,
       StringFormat={StaticResource DateTimeFormat}}"
    IsEditable="True"
/>


В Dates находится DateTime[], EndDate имеет тип DateTime, DateFromDateTimeConverter конвертер делает следующее:

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is DateTime)
                return ((DateTime)value).ToString("MM/dd/yyyy", culture);
            else
                return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is string)
            {
                DateTime result;
                if (DateTime.TryParseExact(value.ToString(), "MM/dd/yyyy", culture, DateTimeStyles.None, out result))
                    return result;                
            }
            return DependencyProperty.UnsetValue;
        }


Даты в списке комбика выглядят как: 12/20/2011 — ничего для этого не было сделанно в коде явно, т.е. комбик как-то сам так их форматирует . Что устраивает. Однако после выбора любой даты из комбика она попадает в Text проперти как 12/20/2011 00:00:00 и дёргается ConvertBack() который естественно ставит флаг ошибки. StringFormat игнорируется при наличии Converter .

Вопрос: как заставить комбик форматировать DateTime как "d" при выборе элемента из списка?
Re: [WPF] ComboBox with DateTime, Binding, Converter + Forma
От: notacat  
Дата: 24.02.11 17:39
Оценка:
просто поправьте конвертер, зачем вам TryParseExact, сделайте просто TryParse. Если у вас комбобокс редактируемый, то TryParse почти любой ввод поймет, даже если юзер с точками дату введет, как ему у себя в системе привычней.
Re[2]: [WPF] ComboBox with DateTime, Binding, Converter + Fo
От: master_of_shadows Беларусь  
Дата: 25.02.11 10:18
Оценка:
Здравствуйте, notacat, Вы писали:

N>просто поправьте конвертер, зачем вам TryParseExact, сделайте просто TryParse. Если у вас комбобокс редактируемый, то TryParse почти любой ввод поймет, даже если юзер с точками дату введет, как ему у себя в системе привычней.


По спекам там должно быть MM/dd/yyyy, всё остальное ошибочный ввод. Если разрешать ввод MM/dd/yyyy HH:mm:ss то этот ввод останется в Text комбика.
Re[2]: [WPF] ComboBox with DateTime, Binding, Converter + Fo
От: master_of_shadows Беларусь  
Дата: 25.02.11 12:16
Оценка:
Здравствуйте, notacat, Вы писали:

N>просто поправьте конвертер, зачем вам TryParseExact, сделайте просто TryParse. Если у вас комбобокс редактируемый, то TryParse почти любой ввод поймет, даже если юзер с точками дату введет, как ему у себя в системе привычней.


В доплнение, проблеммы с юзером как раз таки нет. Проблемма с комбиком, который в случае присутствия Converter заполняет Text как DateTime.ToString().
Re[3]: [WPF] ComboBox with DateTime, Binding, Converter + Fo
От: notacat  
Дата: 25.02.11 12:26
Оценка:
поиграйтесь с ItemTemplate
Re[4]: [WPF] ComboBox with DateTime, Binding, Converter + Fo
От: master_of_shadows Беларусь  
Дата: 25.02.11 12:36
Оценка:
Здравствуйте, notacat, Вы писали:

N>поиграйтесь с ItemTemplate


А как там делать?
Там ведь то же будет проперти Text с тем же содержимым. И с тем же результатом, увы (пробовал).
Re[5]: [WPF] ComboBox with DateTime, Binding, Converter + Fo
От: notacat  
Дата: 25.02.11 16:36
Оценка:
ну вот что-нибудь в этом роде:

public partial class MainWindow : Window
{

    public DateTime EndDate
    {
        get { return (DateTime)GetValue(EndDateProperty); }
        set { SetValue(EndDateProperty, value); }
    }
    public static readonly DependencyProperty EndDateProperty =
        DependencyProperty.Register("EndDate", typeof(DateTime), typeof(MainWindow), 
        new UIPropertyMetadata(DateTime.Today, new PropertyChangedCallback(OnEndDateChanged)));

    private static void OnEndDateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((MainWindow)d).OnEndDateChanged(e);
    }

    ObservableCollection<DateTime> _dates = new ObservableCollection<DateTime>();
    public MainWindow()
    {
        InitializeComponent();
        _dates.Add(DateTime.Today);
        _dates.Add(DateTime.Today.AddDays(1));
        _dates.Add(DateTime.Today.AddDays(2));
        _dates.Add(DateTime.Today.AddDays(3));
        _dates.Add(DateTime.Today.AddDays(4));
        _dates.Add(DateTime.Today.AddDays(5));
        _dates.Add(DateTime.Today.AddDays(6));
        this.DataContext = this;
    }
    public ObservableCollection<DateTime> Dates
    {
        get
        {
            return _dates;
        }
    }
    private void OnEndDateChanged(DependencyPropertyChangedEventArgs e)
    {
        if (!_dates.Contains(EndDate))
        {
            _dates.Add(EndDate);
        }
        cmb.SelectedIndex = _dates.IndexOf(EndDate);
    }
    private void cmb_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            if (!_dates.Contains(EndDate))
            {
                _dates.Add(EndDate);
            }
            cmb.SelectedIndex = _dates.IndexOf(EndDate);
            cmb.Text = EndDate.ToString("MM/dd/yyyy");
        }
    }
}

public class DateFromDateTimeConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is DateTime)
            return ((DateTime)value).ToString("MM/dd/yyyy", culture);
        else
            return value;
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is string)
        {
            DateTime result;
            if (DateTime.TryParse(value.ToString(), out result))
                return result;
        }
        return value;
    }
}


<Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication4"
        Title="MainWindow" Height="350" Width="525" x:Name="root"
        xmlns:my="clr-namespace:System;assembly=mscorlib" xmlns:my1="clr-namespace:System.Collections.ObjectModel;assembly=System">
    <Window.Resources>
        <local:DateFromDateTimeConverter x:Key="DateFromDateTimeConverter"/>
    </Window.Resources>
    <Grid>
        <ComboBox x:Name="cmb" KeyDown="cmb_KeyDown"
            ItemsSource="{Binding Dates, ElementName=root}" VerticalAlignment="Top" 
            Text="{Binding EndDate, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource DateFromDateTimeConverter}, 
            ValidatesOnDataErrors=True, 
            ValidatesOnExceptions=True, NotifyOnValidationError=True}"
            IsEditable="True" >
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Converter={StaticResource DateFromDateTimeConverter}}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </Grid>
</Window>


вряд ли стоит обновлять свойство по каждому изменению текста, подумайте об этом.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.