1

.NET 4.0 中存在一个问题,在 3.5 中不存在(没有测试过更早或更晚的框架)。

我创建了一个演示用户控件,它只有一个属性 Num(整数类型):

Public Class UserControl1

Public Shared NumProperty As DependencyProperty = _
            DependencyProperty.Register("Num", _
                                        GetType(Integer), _
                                        GetType(UserControl1), _
                                        New PropertyMetadata(defaultValue:=0, _
                                                PropertyChangedCallback:=New PropertyChangedCallback(AddressOf OnNumPropertyChanged), _
                                                CoerceValueCallback:=New CoerceValueCallback(AddressOf OnNumPorpertyCoerce)), _
                                        New ValidateValueCallback(AddressOf IsNumValid))

Public Property Num As Integer
    Get
        Return GetValue(NumProperty)
    End Get
    Set(value As Integer)
        SetValue(NumProperty, value)
    End Set
End Property

Public Shared Function IsNumValid(value As Object) As Boolean
    If value IsNot Nothing And TypeOf value Is Integer Then
        If CInt(value) < 0 Then
            Return False
        End If
    End If

    Return True
End Function

Public Shared Sub OnNumPropertyChanged(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
    ' do nothing here
End Sub

End Class

因此,基本上,您不能将任何小于零的值设置为 Num。

问题

当我在 WPF 窗口中使用此控件并尝试设置 Num=-1 时,我得到了异常。但是,如果我尝试将此控件用作 DataTemplate 的一部分,并且还设置 Num=-1,则不会引发异常

我试图在我的用户控件的验证过程中放置​​一个断点,但它只在窗口中的用户控件的情况下被击中,如果我在 DataTemplate 中有用户控件,它不会被击中。

谁能解释为什么不从 DataTemplate 执行验证?

PS 你可以在微软的论坛上找到相关的帖子:http: //social.msdn.microsoft.com/Forums/en-US/wpf/thread/f7fd05a5-cae3-496a-8abe-590541ecdd0a

4

3 回答 3

1

在我的情况下,这一切似乎都工作正常......在正常托管的情况下以及在用户控件的模板托管的情况下,我都会遇到验证错误!

用户控制 XML:

<UserControl x:Class="ContentControlTest.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:ContentControlTest">
    <StackPanel>        
        <TextBox Text="{Binding Num,
                 RelativeSource={RelativeSource
                       AncestorType={x:Type local:UserControl1}},
                 ValidatesOnExceptions=True, ValidatesOnDataErrors=True,
                 NotifyOnValidationError=True, NotifyOnSourceUpdated=True,
                 UpdateSourceTrigger=LostFocus}"/>
    </StackPanel>
</UserControl>

背后的用户控制代码:

public partial class UserControl1 : UserControl
{
    public static readonly DependencyProperty NumProperty
        = DependencyProperty.Register(
            "Num",
            typeof (int),
            typeof (UserControl1),
            new PropertyMetadata(
                0, NumPropertyChangedCallback,
                NumCoerceValueCallback), NumValidateValueCallback);

    public static void NumPropertyChangedCallback
           (DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var i = Convert.ToInt32(e.NewValue);
    }

    public static object NumCoerceValueCallback
                 (DependencyObject d, object baseValue)
    {
        if (Convert.ToInt32(baseValue) < 0)
        {
            return 0;
        }

        return baseValue;
    }

    public static bool NumValidateValueCallback(object value)
    {
        var i = Convert.ToInt32(value);
        return i >= 0;
    }

    public int Num
    {
        get
        {
            return (int)this.GetValue(NumProperty);
        }

        set
        {
            this.SetValue(NumProperty, value);
        }
    }

    public UserControl1()
    {
        InitializeComponent();
    }
}

窗口 XAML:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:System="clr-namespace:System;assembly=mscorlib"
        xmlns:usrctrl="clr-namespace:ContentControlTest;assembly=ContentControlTest"
        Height="300" Width="300">
    <StackPanel>        
        <usrctrl:UserControl1 Margin="5" Num="-1"/>
        <Separator Margin="5"/>        
        <ItemsControl Margin="5">
            <ItemsControl.ItemsSource>
                <x:ArrayExtension Type="{x:Type System:String}">
                    test
                </x:ArrayExtension>
            </ItemsControl.ItemsSource>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <usrctrl:UserControl1 Num="-1"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>  
    </StackPanel>
</Window>

如果您按原样编译上述 Window.XAML 代码,您将获得编译异常本身,即“-1”不是在基于数据模板和非模板用户控件中设置为 Num 属性有效值.

但是,如果您从两个用户控件中删除 Num="-1" 然后编译并运行应用程序,它会加载默认值为 0 的两个文本框。

现在在文本框中,如果您输入 -1 ,则两个文本框都会变为红色,表示验证模型正在处理它们的固有绑定。

所以我不确定为什么这不适用于您的情况!

于 2012-05-15T07:34:40.283 回答
1

虽然 Microsoft 解决了这个问题(在https://connect.microsoft.com/VisualStudio/feedback/details/742083/dependencyproperty-validation-is-not-call-from-data-template上投票),但可以使用解决方法:

在您的强制函数调用验证函数中(为所有这些情况保留验证函数,然后调用它)。如果验证结果为 False,则引发 System.ArgumentException 并带有此类模式的消息:“%INVALID VALUE%”不是属性“%PROPERTY_NAME%”的有效值。通过提供这样的代码,您将为您的用户控件的用户提供他或她从常规验证中获得的相同信息。

于 2012-05-15T08:40:57.243 回答
0

WPF 中的 DataBinding 不会抛出异常,只是在发生异常时不起作用。我对此有复杂的感觉,但这肯定会使调试变得困难。请参阅这篇文章了解如何实现跟踪。我打赌你会看到错误。

于 2012-05-14T22:14:43.593 回答