2013-10-28 7 views
5

Ich habe 2 Sätze von Textblöcken einige von ihnen sind in einem itemcontrol und einige von ihnen sind nicht, Ich möchte einen Stil (nur basierend auf Typ), die den Hintergrund setzt der Textblock, wenn sein Vorgänger ein ItemControl ist.
Ich kann es durch den folgenden Code tun, aber das Problem ist, dass auf dem Protokoll (und Ausgabefenster) eine Fehlermeldung angezeigt wird wegen der Textblöcke, die Itemcontrol nicht als Vorfahren haben. Gibt es eine bessere Möglichkeit, diese Aufgabe auszuführen und diese Fehlermeldung zu vermeiden?Einstellung Stil basierend auf der Existenz eines Vorfahren

<Grid> 
    <Grid.Resources> 
     <local:HasAncestorConverter x:Key="HasAncestorConverter" /> 
     <Style TargetType="TextBlock"> 

      <Style.Triggers> 
       <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Converter={StaticResource HasAncestorConverter}}" Value="True"> 
        <Setter Property="Background" 
          Value="{Binding Tag, 
          RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" /> 

       </DataTrigger> 
      </Style.Triggers> 

     </Style> 
    </Grid.Resources> 
    <StackPanel> 
     <TextBlock Text="Out of ItemControl" /> 
     <ItemsControl Tag="Blue" > 
      <TextBlock Text="Inside of ItemControl" /> 
     </ItemsControl> 
    </StackPanel> 

</Grid>  

Convertor:

class HasAncestorConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     return value != null; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Fehlermeldung:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=; DataItem=null; target element is 'TextBlock' (Name=''); target property is 'NoTarget' (type 'Object')

Antwort

1

nach @ makc Antwort löste ich das Problem auf diese Weise:

<Grid> 
    <Grid.Resources> 
     <local:HasAncestorConverter x:Key="HasAncestorConverter" /> 
     <Style TargetType="TextBlock"> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, 
             Converter={StaticResource HasAncestorConverter}, 
             ConverterParameter={x:Type ItemsControl}}" 
          Value="True"> 
        <Setter Property="Background" 
          Value="{Binding Tag, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" /> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </Grid.Resources> 
    <StackPanel> 
     <TextBlock Text="Out of ItemsControl" /> 
     <ItemsControl Tag="Blue"> 
      <TextBlock Text="Inside of ItemsControl" /> 
     </ItemsControl> 
    </StackPanel> 
</Grid> 
Converter

:

class HasAncestorConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter 
     , System.Globalization.CultureInfo culture) 
    { 
     object parent = null; 
     if (value != null && parameter != null && 
      parameter is Type && value is DependencyObject) 
     { 
      var control = value as DependencyObject; 
      Type t = parameter as Type; 
      parent = ParentFinder.FindParent(control, t); 
     } 
     return parent != null; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter 
     , System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Helper-Klasse für die Eltern bestimmte Art zu finden:
Hinweis: Diese Helfer jede Art von Eltern in logische oder visuelle Struktur finden. In meinem Fall zum Beispiel ItemsControl ist ein Elternteil in der logischen Struktur, und es kann ein Großelternteil sein.

class ParentFinder 
{ 
    public static object FindParent(DependencyObject child, Type parentType) 
    { 
     object parent = null; 
     var logicalParent = LogicalTreeHelper.GetParent(child); 
     var visualParent = VisualTreeHelper.GetParent(child); 

     if (!(logicalParent == null && visualParent == null)) 
     { 
      if (logicalParent != null && logicalParent.GetType() == parentType) 
       parent = logicalParent; 
      else if (visualParent != null && visualParent.GetType() == parentType) 
       parent = visualParent; 
      else 
      { 
       if (visualParent != null) 
        parent = FindParent(visualParent, parentType); 
       if (parent == null && logicalParent != null) 
        parent = FindParent(logicalParent, parentType); 
      } 
     } 
     return parent; 
    } 
} 
0

Sie können mit FallbackValue oder TargetNullValue

arbeiten

prüfen Link aus:

http://dontcodetired.com/blog/post/FallbackValue-TargetNullValue-StringFormat-in-Silverlight-4.aspx

+0

Es kann eine andere Art und Weise sein, den Wert zu setzen, aber in diesem Fall werden Sie immer noch den Fehler in der Ausgabe erhalten, da der Nullwert die Frage, die Vorfahren nicht das Hauptproblem ist, nicht vorhanden ist, möchte ich vermeiden der Fehler dort. –

+0

Ich habe nicht getestet, ob der Fehler immer geworfen wird, aber laut msdn sollte es nicht der Fall sein. FallbackValue bedeutet den Wert, der verwendet wird, wenn keiner gefunden wurde. Ich denke also nicht, dass ein Fehler ausgelöst wurde, wenn der FallbackValue nicht benutzt wird. –

1

Verwenden Sie DataTemplate für die Elemente in ItemsControl.

Behalten Sie den Stil, den Sie haben, wenn Sie es für andere Setter benötigen, entfernen Sie einfach den Auslöser.

+0

Danke, aber das ist nicht was ich will. Ich habe das Problem vereinfacht, um es erklären zu können. In meinem Fall ist es ein Steuerelement und der Stil ist Standard-Stil und soll in "Generic.xaml" festgelegt werden und es wird an den Benutzer des Steuerelements in einem Paket übergeben. Wenn also der Benutzer dieses Steuerelement in ein ItemControl einfügt, sollte das Steuerelement einen anderen Stil haben, als es außerhalb eines ItemControls zu platzieren.Daher habe ich keinen Zugriff auf den Code, der dieses Steuerelement verwendet, und der Benutzer des Steuerelements ist nicht für die Anwendung des Standardstils verantwortlich. –

2

denke ich @Xameli Lösung ist, was Sie eigentlich suchen ...
aber wenn Sie es einfach in einem Stil tun müssen, dann können Sie es erreichen VisualTreeHelper wie die Verwendung von:

<Style.Triggers> 
      <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Converter={StaticResource HasAncestorConverter}}" Value="True"> 
       <Setter Property="Background" 
         Value="{Binding Tag,RelativeSource={RelativeSource Self}}" /> 

      </DataTrigger> 
     </Style.Triggers> 

der Wandler :

class HasAncestorConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     //you probably will have to look a few levels up 
     var parent = VisualTreeHelper.GetParent(value) as ItemsControl; 
     return item != null; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 
+0

Danke, das gab mir die Idee, die Lösung zu finden. Übrigens sollte ItemsControl gefunden werden, indem der Logische Baum überprüft wird. –

+0

@FredJand froh, dass ich helfen konnte – makc

Verwandte Themen