1

.NET 4.0 には、3.5 には存在しない問題があります (以前または以降のフレームワークはテストしていません)。

Num プロパティ (整数型) を 1 つだけ持つデモ ユーザー コントロールを作成しました。

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 を設定しても、例外は発生しません。

ユーザー コントロールの Validation プロシージャにブレークポイントを配置しようとしましたが、ウィンドウ内のユーザー コントロールの場合にのみヒットし、DataTemplate 内にユーザー コントロールがある場合はヒットしません。

DataTemplate から検証が実行されない理由を説明できる人はいますか?

PS Microsoftのフォーラムで関連するスレッドを見つけることができます。

4

3 に答える 3

1

Microsoftがこの問題を解決している間(https://connect.microsoft.com/VisualStudio/feedback/details/742083/dependencyproperty-validation-is-not-called-from-data-templateで賛成)、回避策を使用できます。

強制関数で検証関数を呼び出します(これらすべての場合に検証関数を残してから呼び出されます)。また、検証結果がFalseの場合は、次のようなパターンのメッセージでSystem.ArgumentExceptionを発生させます。'%INVALID VALUE%'はプロパティ'%PROPERTY_NAME%'の有効な値ではありません。このようなコードを提供することにより、ユーザーコントロールのユーザーに、定期的な検証から取得するのと同じ情報を提供します。

于 2012-05-15T08:40:57.243 に答える
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 に答える
0

WPFのDataBindingは例外をスローせず、例外が発生したときに機能しません。私はこれについて複雑な気持ちを持っていますが、それは確かにデバッグを難しくします。トレースの実装方法については、この記事を参照してください。きっとエラーが表示されるでしょう。

于 2012-05-14T22:14:43.593 に答える