0

I have 3 TextBoxes to edit a DateTime. What is important to notice is that those 2 TextBoxes are editing the hour and minutes of the first TextBox DateTime value. One to edit the Date and 2 to edit hour and minutes. How would you do that? The code below doesn't reflect the DateTime changes when editing the hour or minute, because it does ToString("HH") and the DateTime value is lost:

 <TextBox Text="{Binding MyDateTime}"  />

    <!--This cannot work : it's just for clearing purposes -->
    <TextBox Text="{Binding MyDateTime, StringFormat=\{0:HH\}}}"  />
    <TextBox Text="{Binding MyDateTime}, StringFormat=\{0:mm\}}"  />

Of course I can have a ViewModel as DataContext where I would solve it programmatically. But I just want to know if there is any possiblity directly in XAML

theSpyCry
  • 12,073
  • 28
  • 96
  • 152

4 Answers4

2

It is not easily possible with XAML only. There are several possibilities how to solve this:

1. Write custom control or user control that can do this

You could wirte a custom control / user control (e.g. DateTimeTextBox) that has a Property DateTime Value that your xaml can bind against and that contains logic to convert to the datetime value entered in one of its two textboxes. Instead of two textboxes you could also have something like maskedtextbox.

2. Two dedicated properties in the ViewModel

If you go with MVVM you could give your ViewModel two dedicated properties int DateTimeHours int DateTimeMinutes and bind against that:

<TextBox Text="{Binding MyDateTimeHours}"  />
<TextBox Text="{Binding MyDateTimeMinutes}"  />

Your ViewModel would then merge the two properties to a single DateTime value.

bitbonk
  • 48,890
  • 37
  • 186
  • 278
  • Let's talk about 3.: Well the problem is that I cannot merge it with the actual DateTime, because those hours and minutes are part of the first DateTime ! So I need to provide the recent DateTime to the ConvertBack method. – theSpyCry May 21 '10 at 08:20
  • Yes you are right this is not easily possible. I deleted that idea – bitbonk May 21 '10 at 08:22
  • Yep.. u know.. it seems to me like some problems cannot be overcome without MVVM. – theSpyCry May 21 '10 at 08:43
  • MVVM makes a lot of things easier. One must just not fall into the pit of going all tunnel visioned on MVVM. – bitbonk May 21 '10 at 08:52
0

You will need to use a converter with 2way binding and a converter parameter. Save the original hour in the Converter. Then you can update the binding source appropriately.

Anemoia
  • 7,928
  • 7
  • 46
  • 71
  • Well.. if it's true, I'd like to see an example of that converter. ConverteBack: You only have a string value (let's say "16"), how would you get the whole Date from it ? – theSpyCry May 21 '10 at 08:17
  • This is not going to work, because you do not have any acess to current DateTime value (as a whole) and hence you can not merge the hours/minutes with it. You also not save any state in a converter because the same instance can be used used multiple times. – bitbonk May 21 '10 at 08:24
  • Create a user control with the textbox in it and save it like that? – Anemoia May 21 '10 at 08:32
0

I appreciate this is an old post, but I came across this today and found another way to handle bindings with date and time.

I created a partial class called dateTime with 4 properties one for the date, 1 for hour and another for minutes. Then a readonly dateTime property that returns a completed date.

    Partial Public Class dateTimeValue
        Property Dt As Date
        Property Hr As Integer
        Property Mn As Integer

        ReadOnly Property dateTime As Date
            Get
                Dim d = Dt
                d = d.AddHours(d.Hour * -1).AddHours(Hr)
                d = d.AddMinutes(d.Minute * -1).AddMinutes(Mn)
                d = d.AddSeconds(d.Second * -1)
                Return d
            End Get
        End Property
    End Class

Then in the XAML I used a grid layout with the bindings to a DateTimePicker and a couple of ComboBoxes.

            <UniformGrid Columns="2">
                <TextBlock Text="Date"/>
                <DatePicker SelectedDate="{Binding dateTime.Dt}"/>
                <TextBlock Text="Time"/>
                <WrapPanel>
                    <ComboBox SelectedValue="{Binding dateTime.Hr}" SelectedValuePath="Content">
                        <ComboBoxItem>00</ComboBoxItem>
                        <ComboBoxItem>01</ComboBoxItem>
                        <ComboBoxItem>02</ComboBoxItem>
                        .........
                        <ComboBoxItem>22</ComboBoxItem>
                        <ComboBoxItem>23</ComboBoxItem>
                    </ComboBox>
                    <TextBlock Text=":"/>
                    <ComboBox SelectedValue="{Binding dateTime.Mn}" SelectedValuePath="Content">
                        <ComboBoxItem>00</ComboBoxItem>
                        <ComboBoxItem>15</ComboBoxItem>
                        <ComboBoxItem>30</ComboBoxItem>
                        <ComboBoxItem>45</ComboBoxItem>
                    </ComboBox>
                </WrapPanel>
                <Button Click="saveTask" Content="Save Task"/>
            </UniformGrid>

Then to display the correct date and time in say a textblock you can use

<TextBlock Text="{Binding dateTime.dateTime, StringFormat={}{0:dd MMM yyyy - HH:mm}}"/>

Hope this helps someone else out.

Richard Harrison
  • 355
  • 6
  • 19
0

100% MVVM

public class DateTimeConverter : IValueConverter
{
    private DateTime _target = DateTime.Now;
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var source = value as DateTime?;
        if (source is null) return null;
        _target = source.Value;
        switch (parameter as string)
        {
            case "y": return source.Value.Year;
            case "m": return source.Value.Month;
            case "d": return source.Value.Day;
            case "h": return source.Value.Hour;
            case "i": return source.Value.Minute;
            default: return null;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        switch (parameter as string)
        {
            case "y": return new DateTime(System.Convert.ToInt32(value), _target.Month, _target.Day, _target.Hour, _target.Minute, 0);
            case "m": return new DateTime(_target.Year, System.Convert.ToInt32(value), _target.Day, _target.Hour, _target.Minute, 0);
            case "d": return new DateTime(_target.Year, _target.Month, System.Convert.ToInt32(value), _target.Hour, _target.Minute, 0);
            case "h": return new DateTime(_target.Year, _target.Month, _target.Day, System.Convert.ToInt32(value), _target.Minute, 0);
            case "i": return new DateTime(_target.Year, _target.Month, _target.Day, _target.Hour, System.Convert.ToInt32(value), 0);
            default: return _target;
        }
    }
}
  • While this code may solve the question, [including an explanation](https://meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Brian61354270 Apr 09 '20 at 14:20