2013-10-28 14 views
5

Ho 2 set di TextBlocks alcuni di loro sono in un itemcontrol e alcuni di loro non sono, Voglio fare uno stile (solo in base al tipo), che stabilisce il fondo di il blocco di testo se il suo antenato è un oggetto ItemControl.
Posso farlo tramite il seguente codice, ma il problema è che sul log (e sulla finestra di output) verrà visualizzato un messaggio di errore nell'input dei dati a causa dei blocchi di testo che non hanno ItemControl come antenato. C'è un modo migliore per fare questo compito ed evitare questo messaggio di errore?stile impostazione in base all'esistenza di un tipo antenato

<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>  

Converter:

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(); 
    } 
} 

Messaggio di errore:

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')

risposta

1

Secondo la risposta di @ Makc ho risolto il problema in questo modo:

<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(); 
    } 
} 

classe Helper per trovare la madre di tipo specifico:
Nota: questo helper trovare qualsiasi tipo di genitore nella struttura ad albero logico o visivo. per esempio nel mio caso ItemsControl è un genitore nell'albero logico e può essere un nonno.

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

È possibile lavorare con FallbackValue o TargetNullValue

controllare questo link out:

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

+0

Può essere un altro modo per impostare il valore, ma in questo caso si continua a ottenere l'errore in uscita perché il valore null non è il problema principale del problema è che antenato non esiste, voglio evitare l'errore lì. –

+0

Non ho provato se l'errore verrà sempre lanciato ma secondo msdn non dovrebbe essere il caso. FallbackValue indica il valore che verrà utilizzato quando non è stato trovato alcun valore. Quindi non penso che sia stato lanciato un errore quando non si è trovato il valore FallbackValue. –

1

Utilizzare DataTemplate per gli articoli in ItemsControl.

Mantieni lo stile che hai se ne hai bisogno per altri setter, basta rimuovere il grilletto.

+0

Grazie, ma questo non è quello che voglio. Ho semplificato il problema per poterlo spiegare. Nel mio caso è un controllo e lo stile è uno stile predefinito e deve essere impostato in "Generic.xaml" e sarà trasferito all'utente del controllo in un pacchetto. Quindi, se l'utente inserisce questo controllo in un oggetto ItemControl, il controllo deve avere uno stile diverso anziché collocarlo al di fuori di un oggetto ItemControl.Quindi non ho accesso al codice che utilizza questo controllo e l'utente del controllo non è responsabile dell'applicazione dello stile predefinito. –

2

Penso soluzione @Xameli è quello che si sta effettivamente cercando ...
ma se si deve semplicemente farlo in uno stile, allora si può ottenere utilizzando VisualTreeHelper così:

<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> 

convertitore :

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

Grazie, questo mi ha dato l'idea di trovare la soluzione. A proposito, ItemsControl deve essere trovato controllando l'albero logico. –

+0

@FredJand felice di poterti aiutare – makc

Problemi correlati