绑定到 WPF 中的可为 null 的数据类型

Binding to a nullable data type in WPF

好吧,WPF 的这个小怪癖让我很反感。所以,我有一个像这样的 DataGrid

<DataGrid x:Name="Rates" AlternatingRowBackground="#FCFCFC" AutoGenerateColumns="False" CanUserReorderColumns="True" CanUserResizeColumns="True" CanUserAddRows="False" SelectionUnit="FullRow" CanUserSortColumns="True">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Item" Width="Auto" IsReadOnly="True" Binding="{Binding item}"/>
        <DataGridTextColumn Header="Rate" Width ="*" Binding="{Binding rate, UpdateSourceTrigger=PropertyChanged}"/>
    </DataGrid.Columns>

它只是在 A 列中有一个项目列表,我们必须在 B 列中输入费率。听起来很简单。

这是ViewModel中绑定的属性。

private BindableCollection<Rate> _rates;

public BindableCollection<Rate> Rates
{
    get
    {
        return _rates;
    }

    set
    {
        if (value == _rates)
        {
            return;
        }

        _rates = value;
        NotifyOfPropertyChange();
    }
}

这里是 Rate 的定义:

public partial class Rate
{
    public int ID { get; set; }
    public string client { get; set; }
    public string item { get; set; }
    public Nullable<decimal> rate { get; set; }
}

因此,我的 DataGrid 的第二列正在绑定到 Rate.rate,即 Nullable<decimal>。问题就出在这里。 Nullable<decimal> 确实接受 NULLTextBox 不允许我输入空白值。此外,如果我输入像 5 这样的值然后删除它,ViewModel 会保留以前的值。

我见过涉及 IValueConverter 的解决方案,但我更喜欢基于 XAML 的解决方案。有没有?我有几个模块,其中 DataTypeNullable,如果我每次都必须使用 IValueConverter,它很快就会变得非常乏味。

编辑

我正在使用 Caliburn.Micro,因此使用 TargetNullValue='' 不会在任何地方都有效,因为绑定是自动的。它会在上面的示例中工作,其中明确提到了 binding

嗯,在 CaliburnConventionManager 中自定义绑定是正确的选择。

解决方法如下: https://github.com/Caliburn-Micro/Caliburn.Micro/issues/448

如果您正在使用 Caliburn.Micro,您可以配置 CM 在您的 View 和 ViewModel 之间应用自动绑定的方式。

所以在 Bootstrapper 类的 Configure 方法中你可以这样写:

protected override void Configure()
{
    ConventionManager.SetBinding = delegate(Type viewModelType, string path, PropertyInfo property, FrameworkElement element, ElementConvention convention, DependencyProperty bindableProperty)
    {
        Binding binding = new Binding(path);
        ConventionManager.ApplyBindingMode(binding, property);
        ConventionManager.ApplyValueConverter(binding, bindableProperty, property);
        ConventionManager.ApplyStringFormat(binding, convention, property);
        ConventionManager.ApplyValidation(binding, viewModelType, property);
        ConventionManager.ApplyUpdateSourceTrigger(bindableProperty, element, binding, property);

        if (Nullable.GetUnderlyingType(property.PropertyType) != null)
        {
            binding.TargetNullValue = String.Empty;
        }

        BindingOperations.SetBinding(element, bindableProperty, binding);
    };

    // Your own configurations... 
}

如您所见,如果源 属性 是 Nullable,此代码会设置 BindingTargetNullValue 属性。它适用于 CM 在您的应用程序中为您创建的所有自动绑定。

希望对您有所帮助。

编辑

关于你最后的评论,考虑到 Caliburn Micro 在应用 [=40] 时不处理已经绑定(在 XAML 中)到 属性 =].

因此,如果您想自动设置 "manual" 绑定的 TargetNullValue,那么最简单的想法就是创建您自己的绑定:

public class NullableBinding : Binding
{
    public NullableBinding(string path)
        : base(path)
    {
        TargetNullValue = String.Empty;
    }

    public NullableBinding()
        : base()
    {
        TargetNullValue = String.Empty;
    }
}

然后在您的 XAML:

中使用它
<DataGridTextColumn Header="Rate" Width ="*" Binding="{local:NullableBinding rate}"/>