2013-10-07 33 views
6

我有一個UserControl,它將在我們正在開發的應用程序中重用。 我們正在使用基於MVVMLight的框架。帶有MVVM和DataAnnotations的WPF,用戶控件中的驗證錯誤

爲了簡單起見,可以說用戶控件只包含一個文本框,並公開了一個名爲「數量」一個依賴屬性。用戶控件上的文本框是依賴關係屬性「數量」的數據綁定。

當用戶控制是在視圖上使用時,該用戶控件的「數量」依賴屬性數據綁定是在一個ViewModel的屬性。 (這個ViewModel是MVVMLight ViewModelLocator的視圖的datacontext)。

這一切都很好!綁定工作,屬性設置像我所期望的。一切都很好,直到驗證。

我們正在使用DataAnnotations來裝飾我們的視圖模型屬性。 ViewModel包含INotifyDataErrorInfo的自定義實現。我們爲大多數輸入控件實現了自定義樣式,以在控件周圍顯示紅色邊框,並在控件旁邊顯示驗證錯誤消息。所有這些在正常情況下工作得很好(例如,視圖上的文本框綁定到視圖模型中的屬性)。

當我使用該用戶的控制,我結束了嘗試同樣的方法是圍繞整個用戶控制和實際文本沒有錯誤指示的紅色邊框。看起來有一個錯誤的事實正在反映在用戶界面中,但它只是沒有達到我想要的控制。

我搜索計算器上對這個問題的解決方案與這些問題,沒有人可以對我的情況下工作。

我的第一個猜測是,因爲實際的文本框直接綁定到依賴屬性本身,而不是財產在我的視圖模型,它沒有被正確地通知所產生的錯誤。有沒有什麼方法通過usercontrol傳播視圖模型中生成的錯誤,然後傳播到文本框?

任何幫助或建議,你可以給予很大,謝謝。

這是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事件爲它的輔助方法。)

+0

當代碼正常工作時,錯誤消息出現在同一個文本框? – Tico

+0

是的。如果該文本框位於視圖本身上並直接綁定到ViewModel上的數量屬性,則驗證錯誤將出現在文本框中。但是,當文本框位於usercontrol內並且綁定通過用戶控件的依賴項屬性時,驗證錯誤將丟失。 – thornhill

+0

即使你把一個斷點? – Tico

回答

0

嘗試刪除從該DataContextUserControl。取而代之的是,Bind直接從TextBox實際財產使用RelativeSourceBinding設置:

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

UPDATE >>>

做不到這一點,只要綁定到這個屬性視圖模型會總是必須綁定到同一名稱的屬性,你可以得到這個Binding通過父母的DataContext就像這個搜索:

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

您需要將2更改爲TextBox在訪問正確屬性的控件之前具有的父元素的正確數目。例如,使用級別爲2意味着框架將嘗試在TextBox父母的父控件的DataContext中找到名爲QuantityBind的屬性。它棘手得到這與AncestorLevel工作,但我相信'隱藏'元素像Grid s不包括在內作爲父母。

+0

不,這不能解決任何問題。該行爲與在LayoutRoot上設置的datacontext完全相同,而綁定不使用RelativeSource綁定。 – thornhill

+0

感謝您的建議,這將工作,雖然我可以實現你上面沒有使用相關的源綁定,只是沒有在用戶控件上指定datacontext,所以它會繼承父母datacontext(這是我的viewmodel)。然後,控件上的綁定只需要'Text =「{Binding Quantity}」'。但是,我寧願不強制使用此控件的用戶必須以某種方式命名其viewmodel上的屬性,以便他們可以使用UI組件。這(http://goo.gl/zR2zN6)是一種創建用戶控件的模式,可以避免這個問題。 – thornhill