2013-10-07 20 views
6

開発中のアプリケーション全体で再利用されるUserControlがあります。 MVVMLightに基づくフレームワークを使用しています。MVVMとDataAnnotationsを使用したWPF、UserControlの検証エラー

簡潔にするため、ユーザーコントロールには1つのテキストボックスのみが含まれており、 "Quantity"という1つの依存プロパティが公開されています。ユーザーコントロールのテキストボックスは、依存プロパティ "Quantity"にデータバインドされています。

ビューでユーザーコントロールを使用すると、usercontrolの "Quantity"依存プロパティは、ViewModelのプロパティにバインドされます。 (このViewModelは、MVVMLight ViewModelLocatorによるビューのデータコンテキストです)。

これはすべて素晴らしいです!バインディングは機能し、プロパティは期待どおりに設定されます。バリデーションに至るまで、すべてがうまくいきます。

私たちは、DataAnnotationsを使ってViewModelプロパティを飾っています。 ViewModelには、INotifyDataErrorInfoのカスタム実装が含まれています。ほとんどの入力コントロールにカスタムスタイルを実装して、コントロールの周りに赤い境界線を表示し、コントロールの隣にメッセージを表示して、検証エラーメッセージを表示しました。これはすべて、通常のケースではうまくいきます(たとえば、ビューモデルのプロパティにバインドされたビュー上のテキストボックス)。

このユーザーコントロールを使用して同じアプローチを試みると、最終的にユーザーコントロール全体が赤い境界線になり、実際のテキストボックスにエラーが表示されなくなります。エラーがあるという事実はUIに反映されているように見えますが、私が望むコントロールには反映されていません。

私はこの問題の解決策についてはstackoverflowを検索しましたが、解決策がない質問はありません。

私の最初の推測は、実際のテキストボックスは、ビューモデルのプロパティではなく、依存プロパティ自体に直接バインドされているため、生成されたエラーを適切に通知されていないことです。ビューコントロールで生成されたエラーを、ユーザーコントロールからテキストボックスに伝える方法はありますか?

助けてもらえますか?ありがとうございます。

ここにUserControl xamlがあります。

<UserControl x:Class="SampleProject.UserControls.SampleControl" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     mc:Ignorable="d" x:Name="sampleControl" 
     d:DesignHeight="300" d:DesignWidth="300"> 
<Grid x:Name="LayoutRoot" DataContext="{Binding ElementName=sampleControl}"> 
     <TextBox Text="{Binding Path=Quantity, ValidatesOnDataErrors=True}" Width="100" Height="30" /> 
</Grid> 
</UserControl> 

背後にあるUserControlコード。

public partial class SampleControl : UserControl 
{ 
    public SampleControl() 
    { 
     InitializeComponent(); 
    } 

    public static readonly DependencyProperty QuantityProperty = 
     DependencyProperty.Register("Quantity", typeof(int?), typeof(SampleControl), 
    new FrameworkPropertyMetadata{DefaultValue=null, BindsTwoWayByDefault = true}); 

    public int? Quantity 
    { 
     get { return (int?)GetValue(QuantityProperty); } 
     set { SetValue(QuantityProperty, value); } 
    } 
} 

ビューに使用されます。

<userControls:SampleControl Grid.Row="1" Quantity="{Binding Path=Quantity, ValidatesOnDataErrors=True}" Height="60" Width="300"/> 

ViewModelプロパティ。

[Required(ErrorMessage = "Is Required")] 
[Range(5, 10, ErrorMessage = "Must be greater than 5")] 
public int? Quantity 
{ 
    get { return _quantity; } 
    set { Set(() => Quantity, ref _quantity, value); } 
} 
private int? _quantity; 

(*注、セッターでの設定方法は、バッキングプロパティを設定し、それのためにPropertyChangedイベントを発生させ、ベースのviewmodelでちょうどヘルパーメソッドです。)

+0

コードが機能しているとき、エラーメッセージは同じTextBoxに表示されますか? – Tico

+0

はい。そのテキストボックスがビュー自体にあり、ViewModelのQuantityプロパティに直接バインドされている場合、検証エラーがテキストボックスに表示されます。しかし、テキストボックスがユーザーコントロール内にあり、バインディングがユーザーコントロールの依存関係プロパティを通過すると、検証エラーは失われます。 – thornhill

+0

ブレークポイントを置いても? – Tico

答えて

0

からDataContextを削除してくださいUserControl

<TextBox Text="{Binding Quantity, RelativeSource={RelativeSource Mode=FindAncestor, 
    AncestorType={x:Type YourControlNamespace:SampleControl, 
    ValidatesOnDataErrors=True}}}" Width="100" Height="30" /> 

UPDATE >>>

を限り、このプロパティにバインドされていますビューモデルとして、それに失敗:その代わりRelativeSourceBindingを使用して、実際のプロパティにTextBoxから直接、そのBindを設定します常にに結合する同じ名前のプロパティを持って、あなたはこのように両親DataContext Sを検索するには、このBindingを取得することができます。

<TextBox Text="{Binding Quantity, RelativeSource={RelativeSource Mode=FindAncestor, 
    AncestorLevel=2, ValidatesOnDataErrors=True}}}" Width="100" Height="30" /> 

2を、正しいプロパティへのアクセスでコントロールに到達する前に、TextBoxが持つ正しい親要素の数に変更する必要があります。たとえば、レベルが2の場合、フレームワークはの親の親コントロールのにQuantityBindという名前のプロパティを見つけようとします。それはAncestorLevelと同じように働いていますが、Gridのような「隠された」要素は親として含まれていないと信じていますが、です。

+0

いいえ、何も修正されません。この動作は、LayoutRootで設定されているdatacontextと、RelativeSourceバインディングを使用しないバインディングとまったく同じです。 – thornhill

+0

これはうまくいきましたが、これはうまくいくでしょうが、datacontext(これは私のビューモデルです)を継承するように、ユーザーコントロール上にdatacontextを指定しないで、相対ソースバインディングを使用せずに上記のことを達成できました。次に、コントロールのバインディングは 'Text = "{Binding Quantity}"'でなければなりません。しかし、私は、UIコンポーネントを使用できるように、このコントロールのユーザーに特定の方法でビューモデルのプロパティの名前を付ける必要がないようにしたいと考えています。これ(http://goo.gl/zR2zN6)は、その問題を回避するユーザーコントロールを作成するためのパターンです。 – thornhill

関連する問題