当使用WriteValue更新布尔绑定时,为什么会出现格式异常?

13

我在表单上有一堆复选框,它们的选中属性与数据模型上的布尔属性绑定:

chk1.DataBindings.Add(new BindingValue(this, "Checked", "MyBooleanProperty1", false))
chk2.DataBindings.Add(new BindingValue(this, "Checked", "MyBooleanProperty2", false))
chk3.DataBindings.Add(new BindingValue(this, "Checked", "MyBooleanProperty3", false))

屏幕上的所有复选框也共用一个事件处理程序,以确保数据绑定的值正确设置为所选值。

private void AllCheckboxes_CheckedChanged(object sender, EventArgs e)
{
    var chk = ((CheckBox)sender);

    var binding = chk.DataBindings["Checked"];
    if (binding != null)
        binding.WriteValue();
}
在某些情况下,当首次加载此表格和绑定时,我会遇到异常:

无法将值格式化为所需的类型。

在System.ComponentModel.ReflectPropertyDescriptor.SetValue(Object component, Object value)处 在System.Windows.Forms.BindToObject.SetValue(Object value)处 在System.Windows.Forms.Binding.PullData(Boolean reformat, Boolean force)处 在System.Windows.Forms.Binding.WriteValue()处

第一个复选框正确处理事件,但接着第二个会抛出此异常。

数据源是我的数据模型的一个接口。

public interface IMyDataModel
{
    bool MyBooleanProperty1 { get; set; }
    bool MyBooleanProperty2 { get; set; }
    bool MyBooleanProperty3 { get; set; }
}

我可以验证数据模型本身是否正确设置,方法是在事件处理程序中的 .WriteValue 之前设置断点。我甚至可以在绑定的布尔属性的 setter 中设置断点,也会被正确调用。

如果我将绑定的 FormattingEnabled 属性设置为 true,则可以解决该问题。但是我想知道为什么我必须这样做,因为我正在将 UI 对象中的 System.Boolean 属性绑定到数据源上的 bool 属性。

为什么在这种情况下会出现异常?


你是否启用了 IsThreeState 属性? - Dave Alperovich
不,IsThreeState 没有被设置。 - Rachel
我会尝试设置IsThreeState或将绑定设置为可空布尔值。我知道这看起来不像是一个空绑定问题,但我希望复选框能够处理空值。 - Dave Alperovich
有任何真实的可复现代码吗?BindingValue是什么? - Simon Mourier
@SimonMourier 您说得对,我无法在测试项目中轻松地重现这个问题。我会逐步添加代码并查看是否能够确定导致此异常的原因。BindingValue是一个自定义类,其中包含用于在我们代码基础设施中创建绑定的属性。 - Rachel
这个错误可能与问题相距甚远(并且很难指示出具体位置)。我上次遇到这个错误是当我将可空图像绑定到picturebox时。这个链接可能会有帮助 - http://stackoverflow.com/questions/9884917/databinding-exception-cannot-format-the-value-to-the-desired-type-hard-to-debug - Cody Barnes
4个回答

1
“没有办法重现问题,很难确定具体情况。”
“但至少我可以解释为什么设置 FormattingEnabled 会使异常消失:”

http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Binding.cs,853

WriteData会以reformat = trueforce = true的参数调用PullData

从您的调用堆栈来看,似乎您必须进入此代码块:

            // Put the value into the data model
            if (!parseFailed) {
                this.bindToObject.SetValue(parsedValue);
            }

紧接着,除非 FormattingEnabled = true,否则该异常将被重新抛出。因此,在此处设置 FormattingEnabled 会隐藏问题,因为似乎 Binding 假设您将自己处理到目前为止发现的任何格式化/解析问题。
至于为什么首先会引发异常......我不知道。在这里看起来没有明显的东西:

http://referencesource.microsoft.com/#system/compmod/system/componentmodel/ReflectPropertyDescriptor.cs,1138

如果您找到一种方法在不使用 BindingValue 自定义类的情况下添加数据绑定,我很想知道您的问题是否仍然存在。我还想知道您是否已经在 BindingValue 中连接了任何侦听器。

1
谢谢您提供的代码链接,这些对我很有帮助。我已经缩小了问题范围,发现是由于我们内部更改通知代码在属性的get/set中引起的。使用常规的通用get; set;不会导致异常。我授予您赏金,因为MSDN代码链接提供了最好的解释,说明我为什么会出现错误,并建议可能出错的地方,所以当我有更多时间时,我将继续朝那个方向进行调试。谢谢。 - Rachel

0

1
正如我在问题中所说的那样,我知道启用格式化将“修复”它,但我想知道首先是什么导致了这个问题。 - Rachel

0

我认为如果没有处理解析/格式化,它会抛出异常,这就是为什么formattingEnabled似乎有效的原因。

尝试处理Binding.FormatBinding.Parse事件,以验证发送(和期望)的类型是否正确。


这两个事件正确地显示e.DesiredTypee.ValueSystem.Boolean。它们似乎都能正常运行,没有发生任何异常。 - Rachel

0
这是我会做的事情。 该模型应实现INotifyPropertyChanged接口。 从工具箱中向您的表单添加BindingSource。将其DataSource设置为您的模型。在每个复选框上设置数据绑定。我会使用高级窗口并将数据源更新模式设置为OnPropertyChanged。 在这种情况下,您不必为复选框设置任何事件处理程序。


在一个更好的世界里,我会使用INotifyPropertyChanged,但是在这种情况下,我无法控制应用程序基础架构,而且如果没有大量麻烦,我不能进行更改。此外,我正在寻找关于为什么会发生这种情况的答案,而不是潜在的解决方案。 - Rachel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接