6

I have 2 controls:

DatePicker: For Date Only
TextBox with TimeMask: For Time Only

They are both linked to the same property DateTime EffectiveDate But the problem is when I change the Date on the DatePicker, it changes the Time in the TimeTextBox back to 12:00.

I understand the reason for it, but what best solution is out there to let these work separately but bound to the same property?

I have tried to take the current time and build a new Date in the set property but always end up with overflow errors.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
user1702369
  • 1,089
  • 2
  • 13
  • 31

4 Answers4

5

You can use a value converter to hold on to the value

public class DateConverter : IValueConverter
{
    private DateTime timePickerDate;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        timePickerDate = ((DateTime)(value));

        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null) return timePickerDate;

        var datePickerDate = ((DateTime)(value));

        // compare relevant parts manually
        if (datePickerDate.Hour != timePickerDate.Hour
            || datePickerDate.Minute != timePickerDate.Minute
            || datePickerDate.Second != timePickerDate.Second)
        {
            // correct the date picker value
            var result = new DateTime(datePickerDate.Year,
                 datePickerDate.Month,
                 datePickerDate.Day,
                 timePickerDate.Hour,
                 timePickerDate.Minute,
                 timePickerDate.Second);

            // return, because this event handler will be executed a second time
            return result;
        }

        return datePickerDate;
    }
}

And have the two controls in question bind to the one property but have the date picker use the converter to not override the time.

<Grid Margin="10,5" >        
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition Width="auto"/>
    </Grid.ColumnDefinitions>
    <sdk:DatePicker Grid.Column="0" TabIndex="1" Padding="0" SelectedDate="{Binding EffectiveDate, Mode=TwoWay, Converter={StaticResource DateConverter}}" SelectedDateFormat="Short"/>
    <toolkit:TimePicker Grid.Column="1" Value="{Binding EffectiveDate, Mode=TwoWay}" Margin="0" Padding="0" HorizontalAlignment="Left" TabIndex="2" />
</Grid>
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • 1
    Excactly what I needed, no need to even fiddle with the objects property.Thanks a million. – user1702369 Jan 31 '17 at 12:22
  • 1
    Ok, found a problem. Lets say I have chosen 21/01/2017 and the time is 12:00. The moment I change the time, the Date Jumps back to Today (31/01/2017). Wil I need a converter for the time aswell to keep the Date as is? – user1702369 Jan 31 '17 at 12:58
  • No. Do you have proper notify property changed wired up on the property? I'll new up a project quick to see if I can reproduce that. – Nkosi Jan 31 '17 at 13:02
  • @user1702369 works as described. I changed the date via picker when updated time and date remained for multiple changes. – Nkosi Jan 31 '17 at 13:28
  • I am using an extended TextBox with Mask for the time. What TimePicker are you using – user1702369 Jan 31 '17 at 13:34
  • Take a look at the [WPFToolkit Timepicker](https://wpftoolkit.codeplex.com/wikipage?title=TimePicker&referringTitle=Home) – Nkosi Jan 31 '17 at 13:36
  • Grrr, these limitations I have to stick to ;-). Cant use it, still though dont understand why it does not work on a normal textbox. It should. Text="{Binding Path=EffectiveDateTime, StringFormat={}{0:HH:mm}, Mode=TwoWay}" – user1702369 Jan 31 '17 at 13:56
  • My suspicion is that while updating a time, if it does not parse correctly then it may case an issue. That is what I think was causing the overflows. as well. I could be mistaken. – Nkosi Jan 31 '17 at 14:07
  • The best solution for the most annoying problem. – Konrad Jun 18 '19 at 09:32
  • Funnily, I have the same issue as @user1702369 now. Date jumps back to today. Weird. – Konrad Jun 26 '19 at 14:41
  • I created another `TimeConverter` that does the same thing but keeps the date part. Very ugly but works. – Konrad Jun 26 '19 at 14:51
3

You could do something like this:

private DateTime _effectiveDate;
...
public DateTime DateOfEffectiveDate
{
    get { return _effectiveDate; }
    set
    {
        _effectiveDate = new DateTime(value.Year, value.Month, value.Day, _effectiveDate.Hour, _effectiveDate.Minute, _effectiveDate.Second);
    }
}

public DateTime TimeOfEffectiveDate
{
    get { return _effectiveDate; }
    set
    {
        _effectiveDate = new DateTime(_effectiveDate.Year, _effectiveDate.Month, _effectiveDate.Day, value.Hour, value.Minute, value.Second);
    }
}
dvjanm
  • 2,351
  • 1
  • 28
  • 42
1

The built-in DatePicker control selects only a date without any specific time so I am afraid it makes no sense to try to display the time of the selected date in a TextBox. The DatePicker will effectively clear out the time part each time a new date is selected. This is how the control works.

So you should bind the DatePicker and the TextBox to two different source properties, a DateTime? and a TimeSpan respectively.

The other option would be to use another control that selects a date and a time, for example this one: http://wpftoolkit.codeplex.com/wikipage?title=DateTimePicker

mm8
  • 163,881
  • 10
  • 57
  • 88
0

Catch dateTimePicker1_ValueChanged event and then set binded field value combining date and time parts

private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
        {
            DateTime dt = dateTimePicker1.Value;

            int hour = Convert.ToInt32(textBox1.Text.Split(':')[0]);
            int minute = Convert.ToInt32(textBox1.Text.Split(':')[1]);

            bindedfield = new DateTime(dt.Year, dt.Month, dt.Day, hour, minute, 0);
        }
kgzdev
  • 2,770
  • 2
  • 18
  • 35