0

I have a DataGrid within a UserControl. I want to have a DataGridTextColumn bound to a DateTime field, showing only the time. When the user enters a time, the date portion (year, month, day) should be taken from a property (AttendDate) on the UserControl.

My first thought was to bind the user control's property to ConverterParameter:

<DataGridTextColumn Header="From" 
    Binding="{Binding FromDate, Converter={StaticResource TimeConverter},ConverterParameter={Binding AttendDate,ElementName=UC}}"
/>

but ConverterParameter doesn't take a binding. I then thought to do this using a MultiBinding:

<DataGridTextColumn Header="משעה" Binding="{Binding FromDate, Converter={StaticResource TimeConverter}}" />
    <DataGridTextColumn.Binding>
        <MultiBinding Converter="{StaticResource TimeConverter}">
            <Binding Path="FromDate" />
            <Binding Path="AttendDate" ElementName="UC" />
        </MultiBinding>
    </DataGridTextColumn.Binding>
</DataGridTextColumn>

However IMultiValueConverter.Convert -- which takes multiple parameters -- is only called when formatting the display. IMultiValueConverter.ConvertBack which is called on editing, only takes one parameter - the entered string.

How can I do this?

(I am not using MVVM; not something I can change.)

Zev Spitz
  • 13,950
  • 6
  • 64
  • 136

2 Answers2

0

One idea for the solution is to have another property with only a getter that merges the info you want.

something like

property string Time {get {return this.FromDate.toshortdate().tostring() + AttendDate.hour.tostring() + attenddate.minutes.tostring()}; }

The code might be not exactly this, but then you can bind this property to show the info you want where it should be presented.

regards,

=============EDIT===========

I tried this, a very simple example...don't know if it works for you:

XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:conv ="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <conv:TimeConverter x:Key="tmeConverter"></conv:TimeConverter>
    </Window.Resources>

    <Grid>
        <DataGrid ItemsSource="{Binding listExample}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="teste" >
                    <DataGridTextColumn.Binding>
                        <MultiBinding Converter="{StaticResource tmeConverter}">
                            <Binding Path="FromDate" />
                            <Binding Path="AttendDate" />
                        </MultiBinding>
                    </DataGridTextColumn.Binding>
                </DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

Code behind (.cs)

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public List<Example2> listExample { get; set; }

        public Example2 Test { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            this.listExample = new List<Example2>();
            //listExample.Add(new Example { IsChecked = false, Test1 = "teste" });
            //listExample.Add(new Example { IsChecked = false, Test1 = "TTTTT!" });

            this.Test = new Example2 { AttendDate = "1ui", FromDate = "ff" };
            this.listExample.Add(this.Test);

            DataContext = this;


        }
    }
}

And Example2 class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfApplication1
{
    public class Example2
    {
        public string FromDate { get; set; }

        public string AttendDate { get; set; }
    }
}

Converter:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace WpfApplication1
{
    class TimeConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return values[0].ToString() + values[1].ToString();
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

The final window appears 3 columns, and if I change the last two columns, the first one is automatically edited.

Is that it?

sexta13
  • 1,558
  • 1
  • 11
  • 19
  • I have no problem displaying the value with a customized format; that I can do with a MultiBinding. My issue is that the actual value needs to be changed in accordance with the value of the `AttendDate` property. – Zev Spitz May 29 '13 at 17:14
  • Then, you must implement INotifyPropertyChanged. Check http://stackoverflow.com/questions/16787757/how-to-uncheck-all-checkbox-in-side-datatemplate-of-gridcontrol-on-button-click/16788035#16788035 , the part that has the Example Class. – sexta13 May 29 '13 at 17:19
  • One question, have you tried the ? – sexta13 May 29 '13 at 17:42
  • Yes I have; it's in my question. – Zev Spitz May 29 '13 at 17:50
  • I can't see it in your question. anyway, if you want I can try to make an working example :) – sexta13 May 29 '13 at 17:54
  • This is not quite what I need - a single column which can draw the date-part of a datetime from a different bound field, and will apply that datepart when the user edits the value. – Zev Spitz Jun 06 '13 at 12:57
0

Get rid of DataGridTextColumn and use DataGridTemplateColumn with CellTemplate containing a textblock bound to your multibinding, and cell editing template containing TextBox bound to FromDate, possibly via short-date converter, depending on usability you intend to achieve.

On of possible solutions:

XAML

    <StackPanel>
    <StackPanel Orientation="Horizontal">
        <Label>From time</Label>
        <DatePicker SelectedDate="{Binding FromTime}"/>
    </StackPanel>
    <DataGrid ItemsSource="{Binding AllUsers}" AutoGenerateColumns="False">
        <DataGrid.Resources>
            <local:TimeConverter x:Key="TimeConverter"/>
        </DataGrid.Resources>
        <DataGrid.Columns>
            <DataGridTemplateColumn>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate DataType="local:UserViewModel">
                        <TextBlock>
                            <TextBlock.Text>
                                <MultiBinding Converter="{StaticResource TimeConverter}">
                                    <Binding ElementName="root" Path="DataContext.FromTime"/>
                                    <Binding Path="AttendTimeHour"/>
                                    <Binding Path="AttendTimeMinute"/>
                                </MultiBinding>
                            </TextBlock.Text>
                        </TextBlock>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate DataType="local:UserViewModel">
                        <StackPanel Orientation="Horizontal">
                            <TextBlock>
                                <Run>Attend on </Run>
                                <Run Text="{Binding ElementName=root, Path=DataContext.FromTime, StringFormat=d}"/>
                                <Run> at </Run>
                            </TextBlock>
                            <TextBox Text="{Binding AttendTimeHour}"/><TextBlock>:</TextBlock>
                            <TextBox Text="{Binding AttendTimeMinute}"/>
                        </StackPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</StackPanel>

View model (UserViewModel) part:

    private DateTime _attendTime;

    public DateTime AttendTime
    {
        get { return _attendTime; }
        set
        {
            if (value == _attendTime) return;
            _attendTime = value;
            OnPropertyChanged();
            OnPropertyChanged("AttendTimeHour");
            OnPropertyChanged("AttendTimeMinute");
        }
    }

    public int AttendTimeHour
    {
        get { return attendTimeHour; }
        set
        {
            if (value.Equals(attendTimeHour)) return;
            attendTimeHour = value;
            AttendTime = new DateTime(AttendTime.Year, AttendTime.Month, AttendTime.Day, AttendTimeHour, AttendTime.Minute, AttendTime.Second);
            OnPropertyChanged();
        }
    }

    private int _attendTimeMinute;

    public int AttendTimeMinute
    {
        get { return _attendTimeMinute; }
        set
        {
            if (value == _attendTimeMinute) return;
            _attendTimeMinute = value;
            AttendTime = new DateTime(AttendTime.Year, AttendTime.Month, AttendTime.Day, AttendTime.Hour, AttendTimeMinute, AttendTime.Second);
            OnPropertyChanged();
        }
    }

And the converter

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values.Length < 2) return null;
        if (!(values[0] is DateTime && values[1] is int && values[2] is int)) return null;

        var fromDate = (DateTime) values[0];
        var attendTimeHour = (int) values[1];
        var attendTimeMinutes = (int)values[2];

        var result = new DateTime(fromDate.Year, fromDate.Month, fromDate.Day, attendTimeHour, attendTimeMinutes, 0);
        return result.ToString();
    }
morincer
  • 884
  • 6
  • 6
  • Won't the user still have to enter a complete datetime, instead of just the time? – Zev Spitz Jun 06 '13 at 12:58
  • In case of celleditingtemplate in the template column you have the full control about how your UI will be presented to the user, so what a user HAVE to enter depends only on what developer has given him in the UI. I've updated my answer with a simple example of one of possible variants. There is some tricks due to immutable nature of DateTime, but I think you'll catch the ided – morincer Jun 06 '13 at 15:32