【问题标题】:Dependency property callback on datagrid custom column not firingdatagrid自定义列上的依赖属性回调未触发
【发布时间】:2013-06-02 11:31:39
【问题描述】:

我有以下自定义数据网格列,用于将 DatePart 依赖属性的值作为 ConverterParameter 传递给编辑元素的转换器:

Public Class DataGridTimeColumn
    Inherits DataGridTextColumn

    Shared ReadOnly DatePartProperty = DependencyProperty.Register("DatePart", GetType(DateTime?), GetType(DataGridTimeColumn), New FrameworkPropertyMetadata(Nothing, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, AddressOf RefreshBinding))
    Property DatePart As DateTime?
        Get
            Return GetValue(DatePartProperty)
        End Get
        Set(value As DateTime?)
            SetValue(DatePartProperty, value)
        End Set
    End Property

    Private Shared Sub RefreshBinding(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
        Dim tc As DataGridTimeColumn = d
        tc.Binding = tc.Binding
    End Sub

    Public Overrides Property Binding As BindingBase
        Get
            Return MyBase.Binding
        End Get
        Set(value As BindingBase)
            Dim b As Data.Binding = value
            With b
                .Converter = New TimeConverter
                .ConverterParameter = DatePart
            End With
            MyBase.Binding = b
        End Set
    End Property
End Class

使用以下 XAML:

<my:DataGridTimeColumn Header="From" Binding="{Binding FromDate}" DatePart="{Binding FromDate}" />
<my:DataGridTimeColumn Header="Until" Binding="{Binding TillDate}" DatePart="{Binding TillDate}" />

但是RefreshBinding 永远不会被调用(我设置了一个断点并且它从未被触发),因此当设置ConverterParameterDatePart 总是Nothing(null)。我该如何解决这个问题?

编辑

在 C# 中:

public class DataGridTimeColumn : DataGridTextColumn
{
    static readonly DependencyProperty DatePartProperty = DependencyProperty.Register(
        "DatePart", typeof(DateTime?), typeof(DataGridTimeColumn),
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, RefreshBinding)
    );

    public DateTime? DatePart
    {
        get { return (DateTime?)GetValue(DatePartProperty); }
        set { SetValue(DatePartProperty, value); }
    }

    private static void RefreshBinding(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    {
        var tc = (DataGridTimeColumn)d;
        tc.Binding = tc.Binding;
    }

    public override System.Windows.Data.BindingBase Binding
    {
        get { return base.Binding; }
        set
        { 
            var b = (Binding)value;
            b.Converter = new TimeConverter();
            b.ConverterParameter = DatePart;
            base.Binding = b;
        }
    }
}

【问题讨论】:

  • 您是否为FromDateTillDate 属性实现了INotifyPropertyChanged?
  • 中的列不是可视化树的一部分,因此它们没有连接 DataContex。如果您在调试时查看输出窗口,您应该会看到类似“找不到目标元素的管理 FrameworkElement 或 FrameworkContentElement...”之类的错误
  • 在这里查看可能的解决方案:stackoverflow.com/questions/7660967/…
  • @Clemens - 不,我没有实现 INPC;我试试看。
  • @AdrianFaciu 我知道我不能通过绑定 DataGridColumn 中的属性来绑定生成元素中的任何属性。我正在尝试绑定 DataGridColumn 的属性,并且对绑定源的任何更改都应导致设置绑定的 ConverterParameter。假设尚未生成数据网格的元素,它们应该使用带有 ConverterParameter 的新绑定,因为绑定已复制/克隆到生成的元素。

标签: wpf data-binding dependency-properties datagridcolumn


【解决方案1】:

我可能不明白您到底想要做什么,但是仅仅查看/编辑 DatePart 似乎需要做很多工作。使用格式化程序和 DataGridTextColumn 会更容易吗? WPF Binding StringFormat Short Date String

【讨论】:

  • 除非在 .NET 4.5 中已修复此问题,否则使用 StringFormatDataGridTextColumn 会产生相同的结果 - 编辑仅时间列时,日期部分设置为当前日期,而不是原始日期部分。
【解决方案2】:

首先,请使用debug检查你的绑定路径是否正常。 其次,检查您的 FromDate 属性是否被触发。 三、请使用Snoop监控此DP是否更新。

最后,我记得 DataGrid 有动态绑定错误,所以我不确定上述步骤能否解决您的问题。如果不合适,请告诉我。

【讨论】:

  • 1) 我在调试中收到以下错误:Cannot find governing FrameworkElement or FrameworkContentElement for target element. 2) 永远不会触发 DatePart 设置器。
  • 说你绑定的elementName有错误,请根据错误信息检查你的绑定。
【解决方案3】:

如果您只需要格式化值,我会推荐 Darlene 方法。如果你真的需要一个转换器来实现一些魔法,我建议通过你在 XAML 中的绑定来设置它(我真的不知道你为什么要在属性定义中设置它)。

您的 XAML 将是这样的:

 <my:DataGridTimeColumn Header="From" Binding="{Binding FromDate, Converter={StaticResource myTimeConverter}} />

TimeConverter 必须实现 IValueConverter 并且必须在您的窗口/数据网格资源中定义一个实例。您还可以在该绑定中定义 TwoWay。

你可以找到一个完整的例子here

如果您想合并两条或更多条数据,您可以使用MultiBinding

【讨论】:

  • 问题是在编辑值时,TimeConverter.ConvertBack 只获取显示的值——仅时间(例如 17:00)而不是完整日期(5/7/12 17:00 )。无法单独使用转换器返回原始日期 + 编辑时间
  • 如果我单独使用转换器,则无需实现DataGridTimeColumn;我可以使用标准的DataGridTextColumn
  • Ok tell me if follow,你想合并两个数据:原始日期和编辑时间,对吧?实现它的简单方法(我认为)是让您拥有一个新属性,您可以在其中将这些数据组合到模型中。但是还有一种方法可以使用 MultiBindings 进行绑定,它与我之前告诉过您的方法非常相似。 Check this example at MSDN 是的,如果您单独使用转换器,则不必实现自己的 DataGirdTextColumn
  • MultiBinding 没有帮助;它有同样的问题——ConvertBack 中的 value 参数只有时间部分,没有日期部分。
  • 当用户编辑时间并输入 15:00 时,它会在转换器中转换回 DateTime。
【解决方案4】:

试图了解您想从 cmets 中实现什么,如果我做对了,您可以只使用视图模型和转换器来实现它,并有一个小的解决方法:

在您的转换器 ConvertBack 方法中,您可以尝试确定用户输入的值是否只有时间部分,如果是,请将日期设置为不会使用的内容(例如 DateTime.MinValue):

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
    var convertedDateTime = DateTime.Parse(value.ToString());
    var hasOnlyTime = value.ToString().Trim().Length <= 5; // This should be replaced with something more consistent

    if (hasOnlyTime)
        return new DateTime(DateTime.MinValue.Year, DateTime.MinValue.Month, DateTime.MinValue.Day, convertedDateTime.Hour, convertedDateTime.Minute, convertedDateTime.Second);

    return convertedDateTime;
}

然后在日期的对象设置器中,您可以检查并使用所需的值,如果日期部分是 DateTime.MinValue 将其更改回前一个,如果不是保持原样:

 private DateTime _fromDate;
 public DateTime FromDate
 {
    get { return _fromDate; }
    set 
    {
        if (value.Date != DateTime.MinValue)
            _fromDate = value;
        else
            _fromDate = new DateTime(_fromDate.Year, _fromDate.Month, _fromDate.Day, value.Hour, value.Minute, value.Second);

        OnPropertyChanged("FromDate");
    }
 }

在 .NET 4.5 上测试并按预期工作。

【讨论】:

  • 我没有使用 MVVM(我无法更改),但该类是 EF 生成的 POCO,我可以通过将 POCO 的属性定义为私有/内部来完成同样的事情,并且部分类的附加属性。
  • 这适用于现有实例。我可以对新实例做些什么?我在允许输入新记录的 DataGrid 中使用此类。
  • 好吧,新实例有什么问题?什么不符合您的预期?
  • DataGrid 将自动创建该类的新实例。如何通过绑定指定新实例的日期部分? DataGrid 中的每一列都有不同的日期部分。
  • 只需使用类的构造函数将值初始化为您想要的任何值,它应该与绑定无关。
猜你喜欢
  • 2014-06-14
  • 2016-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-14
  • 2013-10-16
  • 2012-07-30
相关资源
最近更新 更多