3

Since there is no way to paste values into a DataGridTemplateColumn. I found some suggestions for creating my own column class derived from DataGridBoundColumn. The sample below adds a DatePicker to the column without using a template.

However this sample does not allow me to manually set a value using the DatePicker and I'm not sure why. I'm thinking there is something with the binding. It will load date values that I bind to it initially so it's halfway there.

Interestingly enough using some other helper classes I'm able to paste dates as well which was the origianl purpose. I just didn't want to break anything else. :-)

Any ideas how to make the datepicker selected value bind properly?

class MyDateColumn : DataGridBoundColumn 
{
    public string DateFormat { get; set; }
    protected override void CancelCellEdit(FrameworkElement editingElement, object uneditedValue)
    {
        DatePicker dp = editingElement as DatePicker;
        if (dp != null)
        {
            dp.SelectedDate = DateTime.Parse(uneditedValue.ToString());
        }
    }
    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
    {
        DatePicker dp = new DatePicker();
        Binding b = new Binding();
        Binding bb = this.Binding as Binding;
        b.Path = bb.Path;
        b.Source = DatePicker.SelectedDateProperty;
        if (DateFormat != null)
        {
            DateTimeConverter dtc = new DateTimeConverter();
            b.Converter = dtc;
            b.ConverterParameter = DateFormat;
        }
        dp.SetBinding(DatePicker.SelectedDateProperty, this.Binding);

        return dp;
    }

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        TextBlock txt = new TextBlock();
        Binding b = new Binding();
        Binding bb = this.Binding as Binding;
        b.Path = bb.Path;
        b.Source = cell.DataContext;

        if (DateFormat != null)
        {
            DateTimeConverter dtc = new DateTimeConverter();
            b.Converter = dtc;
            b.ConverterParameter = DateFormat;
        }
        txt.SetBinding(TextBlock.TextProperty, this.Binding);
        return txt;
    }

    protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
    {
        DatePicker dp = editingElement as DatePicker;
        if (dp != null)
        {
            DateTime? dt = dp.SelectedDate;
            if (dt.HasValue)
                return dt.Value;
        }
        return DateTime.Today;
    }

    protected override bool CommitCellEdit(FrameworkElement editingElement)
    {
        DatePicker dp = editingElement as DatePicker;
        dp.SelectedDate = DateTime.Today.AddYears(1);

        return true;
        //return base.CommitCellEdit(editingElement);
    }
}

2 Answers 2

2

The solutions is a modification to CommitCellEdit()...

    protected override bool CommitCellEdit(FrameworkElement editingElement)
    {
        DatePicker dp = editingElement as DatePicker;
        DateTime dt;
        try
        {
            dt = Convert.ToDateTime(dp.Text);
            dp.SelectedDate = dt;
        }
        catch (FormatException)
        {
            dp.Text = String.Empty;
        }


        BindingExpression binding = editingElement.GetBindingExpression(DatePicker.SelectedDateProperty);
        if (binding != null)
            binding.UpdateSource();
        return true;
        //return base.CommitCellEdit(editingElement);
    }

Original code and help comes from the following link...

http://leeontech.wordpress.com/2009/01/21/creating-datagriddatecolumn-for-datagrid/#comment-1033

Thanks for creating the sample and the help Lee!

Sign up to request clarification or add additional context in comments.

Comments

0

I found an easier and more generic way of solving it. Instead of creating a custom column for each template column you have I created 1 custom column that inherits from DataGridTemplateColumn. This will solve it for all your templates you want to have. The custom column has additional BindingPath property in which you specify which property on the bound object you want to update with the pasted in data. Obviously the bound object needs to implement INotifyPropertyChanged interface. Once the source is updated your controls will update automatically.

Here's the custom column code:

using System.Reflection;
using Microsoft.Windows.Controls;

namespace Bartosz.Wojtowicz.Wpf
{
    public class PastableDataGridTemplateColumn : DataGridTemplateColumn
    {
        public string BindingPath { get; set; }

        public override void OnPastingCellClipboardContent(object item, object cellContent)
        {
            if (item != null)
            {
                PropertyInfo propertyInfo = item.GetType().GetProperty(BindingPath);
                if (propertyInfo != null)
                {
                    propertyInfo.SetValue(item, cellContent, null);
                }
            }
        }
    }
}

And here is how you use it in xaml:

 <local:PastableDataGridTemplateColumn Header="Value" BindingPath="ValueView" ClipboardContentBinding="{Binding ValueView}" >
  <local:PastableDataGridTemplateColumn.CellTemplate >
    <DataTemplate>
      <!-- your template ... -->
    </DataTemplate>
  </local:PastableDataGridTemplateColumn.CellTemplate>
  <local:PastableDataGridTemplateColumn.CellEditingTemplate>
    <DataTemplate>
      <!-- your template ... -->
    </DataTemplate>
  </local:PastableDataGridTemplateColumn.CellEditingTemplate>
</local:PastableDataGridTemplateColumn>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.