2012-03-28 8 views
27

TabControlのタブにある検証ルールを持つTextBoxがあります。検証ルールが失敗した場合、デフォルトのErrorTemplateが正しく表示されます(TextBoxの周囲に赤い枠線が表示されます)。
しかし、別のタブへの切り替えがあってTextBoxでタブに戻ると、ErrorTemplateのハイライトは消えてしまいます。 TextBoxに変更がある場合、検証ルールは引き続き呼び出され、falseを返しますが、エラーハイライトは表示されません。
テキストコンテンツが有効に変更され、無効になると再びハイライトが再生されます。
テキストコンテンツが無効で、別のタブに切り替えた後に無効なハイライトを保持するとしたらどうでしょう。この行動を得るためのあらゆるアイデアを大歓迎です。
XAML:次のようにValidation付きTextBoxがタブ変更時にErrorTemplateを失う

<TextBox Height="35" > 
    <TextBox.Text> 
    <Binding Path="pan_id" UpdateSourceTrigger="PropertyChanged"> 
     <Binding.ValidationRules> 
     <ps:PanIdValidation /> 
     </Binding.ValidationRules> 
    </Binding> 
    </TextBox.Text> 
</TextBox> 
+0

MVVMを使用していますか? – Paparazzi

答えて

47

のTabItemを定義する必要があります。

<TabItem Header="Foo"> 
    <Border> 
     <AdornerDecorator> 
      <Grid> 
       <TextBox Height="35" > 
        <TextBox.Text> 
         <Binding Path="pan_id" UpdateSourceTrigger="PropertyChanged"> 
          <Binding.ValidationRules> 
           <ps:PanIdValidation /> 
          </Binding.ValidationRules> 
          </Binding> 
         </TextBox.Text> 
        </TextBox> 
       </Grid> 
      </AdornerDecorator> 
     </Border> 
    </TabItem> 

問題がValidation.Errorの手がかりがAdornerレイヤに描かれている、です。タブを切り替えると、そのレイヤーは破棄されます。

+0

パーフェクト - ありがとう。 – Ricibob

+0

素晴らしい!同じスタイル属性を共有する複数のコントロールを折り返すときにも機能します。 – Salty

+0

これは私に多くの時間を保存しました、ありがとう! – akagixxer

7

特別な場合の追加:私は同様の問題を抱えていましたが、現在はディランのコードに似た解決策を使用しています。

違いは、私のTabItemにはGroupBoxが含まれており、TextBoxがその中に入っている点です。この場合、AdornerDecoratorはGroupItem自体に存在し、TabItemの直接の子孫ではありません。

だから、これは動作しませんでした:

<TabItem> 
    <AdornerDecorator> 
     <Grid> 
      <GroupBox> 
       <Grid> 
        <TextBox>...<TextBox/> 
       </Grid> 
      </GroupBox> 
     </Grid> 
    </AdornerDecorator> 
</TabItem> 

しかし、これはやった:

<TabItem> 
    <Grid> 
     <GroupBox> 
      <AdornerDecorator> 
       <Grid> 
        <TextBox>...<TextBox/> 
       </Grid> 
      </AdornerDecorator> 
     </GroupBox> 
    </Grid> 
</TabItem> 

私は簡単に解決してAdornerLayer.GetAdornerLayer()のも、ドキュメントを見つけることができなかったので、私はそれを追加しています(ただし、ここに当てはまるかどうかわからない)状態This static method traverses up the visual tree starting at the specified Visual and returns the first adorner layer found. - しかしそれはまたある時点で停止するかもしれないが、これはドキュメントからは明らかではない。

4

ディランが説明したように、これは、検証エラーが引き出されたAdornerレイヤーがタブスイッチで破棄されたためです。したがって、AdornerDecoratorでコンテンツをラップする必要があります。

私はそれがすべてのTabItems上で手動で行う必要がないように、自動的にAdornerDecoratorTabItemContentをラップ行動を作成しました。

public static class AdornerBehavior 
{ 
    public static bool GetWrapWithAdornerDecorator(TabItem tabItem) 
    { 
     return (bool)tabItem.GetValue(WrapWithAdornerDecoratorProperty); 
    } 
    public static void SetWrapWithAdornerDecorator(TabItem tabItem, bool value) 
    { 
     tabItem.SetValue(WrapWithAdornerDecoratorProperty, value); 
    } 

    // Using a DependencyProperty as the backing store for WrapWithAdornerDecorator. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty WrapWithAdornerDecoratorProperty = 
     DependencyProperty.RegisterAttached("WrapWithAdornerDecorator", typeof(bool), typeof(AdornerBehavior), new UIPropertyMetadata(false, OnWrapWithAdornerDecoratorChanged)); 

    public static void OnWrapWithAdornerDecoratorChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) 
    { 
     var tabItem = o as TabItem; 
     if (tabItem == null) return; 

     if(e.NewValue as bool? == true) 
     { 
      if (tabItem.Content is AdornerDecorator) return; 
      var content = tabItem.Content as UIElement; 
      tabItem.Content = null; 
      tabItem.Content = new AdornerDecorator { Child = content }; 
     } 
     if(e.NewValue as bool? == false) 
     { 
      if (tabItem.Content is AdornerDecorator) 
      { 
       var decorator= tabItem.Content as AdornerDecorator; 
       var content = decorator.Child; 
       decorator.Child = null; 
       tabItem.Content = content; 
      } 
     } 
    } 
} 

あなたは、デフォルトのスタイルを経由して、すべてのTabItemsに、この動作を設定することができます。

<Style TargetType="TabItem"> 
    <Setter Property="b:AdornerBehavior.WrapWithAdornerDecorator" Value="True"></Setter> 
</Style> 

bは、行動が配置されている名前空間でこのようなものは、(プロジェクトごとに異なります):

xmlns:b="clr-namespace:Styling.Behaviors;assembly=Styling" 
関連する問題