开发者

How to set values into custom DataGridBound column in WPF

开发者 https://www.devze.com 2023-01-13 17:29 出处:网络
Since there is no way to paste values into a DataGr开发者_开发问答idTemplateColumn. I found some suggestions for creating my own column class derived from DataGridBoundColumn. The sample below adds a

Since there is no way to paste values into a DataGr开发者_开发问答idTemplateColumn. 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);
    }
}


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!


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>
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号