關於WPF數據綁定是什麼,請參考Data Binding Overview:http://msdn.microsoft.com/en-us/library/ms752347.aspx
關於WPF數據綁定的Validation更多細節,請參考Data Validation in 3.5:http://blogs.msdn.com/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx
關於WPF數據綁定的Validation中的ErrorTemplate怎麼用,請參考ErrorTemplate Attached Property:http://msdn.microsoft.com/en-us/library/system.windows.controls.validation.errortemplate.aspx
ErrorTemplate將被繪制在Adorner Layer上,關於Adorner Layer,請參考Adorners Overview:http://msdn.microsoft.com/en-us/library/ms743737.aspx
在Adorners Overview裡,對Adorner是這樣解釋的,
Adorners are rendered in an AdornerLayer, which is a rendering surface that is always on top of the adorned element or a collection of adorned elements.
Adorned element的紅色是我加的。表面上看,這個adorned element就是一個element,但是這個element的范圍有多大呢?對我們的程序會有什麼影響呢?看文檔很難想到。用過之後才知道,影響太大了。
還有這樣一個不太起眼的Note。
Anything placed in the adorner layer is rendered on top of the rest of any styles you have set. In other words, adorners are always visually on top and cannot be overridden using z-order.
這句話是對的。大意就是說這個Adorner layer裡的東西,總會被繪制在它所adorn的東西之上。這個無可厚非,人家這樣設計,我們就這麼用就是了。但是,問題就在於,一個Window裡的東西,是可以有層次的,有區域,有可見性的。但是adorner layer不分青紅皂白地總在最上。結果就出了問題。請看下面的例子。
DemoWindow
<Window x:Class="FixErrorTemplate.DemoWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Stubborn Error Template Demo"
Height="200" Width="300"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Name="window">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="5"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Height="50">
<TextBox HorizontalAlignment="Center" VerticalAlignment="Center" Width="100">
<TextBox.Text>
<Binding ValidatesOnDataErrors="True" ElementName="window" Path="Value"/>
</TextBox.Text>
</TextBox>
</Grid>
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch"/>
<Grid Grid.Row="2" Margin="12">
<TabControl>
<TabItem Header="Tab1">
<TextBox HorizontalAlignment="Center" VerticalAlignment="Center" Width="100">
<TextBox.Text>
<Binding ValidatesOnDataErrors="True" ElementName="window" Path="Value"/>
</TextBox.Text>
</TextBox>
</TabItem>
<TabItem Header="Tab2"/>
</TabControl>
</Grid>
</Grid>
</Window>
這個窗口,就出了兩個問題。看圖。
啟動時如下圖所示。
圖1. Startup Window
窗體的上下由一個GridSplitter分割,可以上下拖動。
在TextBox中輸入一個字符。會產生一個Validation Error,並用默認的ErrorTemplate顯示出來。如圖2所示。
圖2. TextBox in Error
好了,我們慢慢地將GridSplitter向上拖。慢慢地,看到什麼了?TextBox消失了,可是那個紅框卻賴著不走了!如圖3所示。
圖3. Move GridSplitter Up
再來看看下面的紅框。把GridSplitter慢慢地向下拖。TabPanel的空間小了,TextBox也變矮,最後消失,那個紅框也很盡忠,化成了一條線也要告訴我們那個TextBox其實還在。如圖4所示。
圖4. Move GridSplitter Down
再細看看,那個紅線甚至已經在TabControl之外了!
當然,我們總可以想辦法解決或是繞過這個問題,然後說這不是個問題。但是最自然的代碼寫出來的東西卻不對,就象之前一篇介紹的如何用代碼選中一個ListBoxItem一樣,很不爽。因為按理說,adorned element都消失了,這個紅框也應該跟著消失的。