2011-03-03 11 views
7

Sto provando a impostare il colore Foreground su un Hyperlink utilizzando un oggetto Style in un antenato Resources, ma non ha alcun effetto. Ho persino usato il suggerimentoda Changing Hyperlink foreground without losing hover color, ma non ha fatto alcuna differenza - ho ancora un collegamento ipertestuale blu che è rosso al passaggio del mouse.Come propagare gli stili ai collegamenti ipertestuali all'interno di un DataTemplate?

Ecco il codice XAML per i miei controlli, tra cui un ItemsControl i cui elementi sono indicati con un collegamento ipertestuale:

<StackPanel Background="Red" TextElement.Foreground="White"> 
    <StackPanel.Resources> 
    <Style TargetType="Hyperlink" BasedOn="{StaticResource {x:Type Hyperlink}}"> 
     <Setter Property="Foreground" Value="Yellow"/> 
     <Style.Triggers> 
     <Trigger Property="IsMouseOver" Value="True"> 
      <Setter Property="Foreground" Value="White"/> 
     </Trigger> 
     </Style.Triggers> 
    </Style> 
    </StackPanel.Resources> 
    <TextBlock>Data import errors</TextBlock> 
    <ItemsControl ItemsSource="{Binding Errors}"/> 
</StackPanel> 

E le voci del ItemsControl stanno raccogliendo il seguente DataTemplate:

<DataTemplate DataType="{x:Type Importer:ConversionDetailsMessage}"> 
    <TextBlock> 
    <Run Text="{Binding Message, Mode=OneTime}"/> 
    <Hyperlink Command="Common:ImportDataCommands.ExplainConversionMessage" CommandParameter="{Binding}"> 
     <Run Text="{Binding HelpLink.Item2, Mode=OneTime}"/> 
    </Hyperlink> 
    </TextBlock> 
</DataTemplate> 

E ' degno di nota, anche, che non voglio semplicemente impostare i diversi colori direttamente su Hyperlink nello DataTemplate. Questo perché il modello verrà utilizzato da un numero di diversi oggetti ItemsControl, la maggior parte dei quali sarà su uno sfondo bianco e quindi può utilizzare i colori del collegamento ipertestuale standard. (Si noti che quello in XAML sopra, tuttavia, ha un fondo rosso.)

In breve, non voglio il DataTemplate a dover sapere nulla circa il controllo in cui è in uso. Gli stili per i controlli del modello dovrebbero solo filtrare fino ad esso.

Quindi ... qualcuno può dirmi perché lo stile non sta filtrando e cosa posso fare per risolverlo?

Grazie.

Aggiornamento:
Dal momento che non ho potuto ottenere la risposta di Pavlo a lavorare nella mia app di produzione, allora ho provato in un'applicazione di prova separata. L'app è un'app WinForms, con il modulo principale che contiene nient'altro che ElementHost, che a sua volta contiene un semplice usercontrol di WPF. Ecco il suo XAML:

<UserControl x:Class="DataTemplateStyling.StylingView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:DataTemplateStyling="clr-namespace:DataTemplateStyling" 
      x:Name="root" Loaded="StylingViewLoaded"> 

    <UserControl.Resources> 
    <Style x:Key="MyDefaultHyperlinkStyle" BasedOn="{StaticResource {x:Type Hyperlink}}"/> 

    <DataTemplate DataType="{x:Type DataTemplateStyling:ImportMessage}"> 
     <DataTemplate.Resources> 
     <Style TargetType="{x:Type Hyperlink}" 
       BasedOn="{StaticResource MyDefaultHyperlinkStyle}"/> 
     </DataTemplate.Resources> 
     <TextBlock> 
     <Run Text="{Binding Message, Mode=OneTime}"/> 
     <Hyperlink NavigateUri="{Binding HelpLink.Item1}"> 
      <Run Text="{Binding HelpLink.Item2, Mode=OneTime}"/> 
     </Hyperlink> 
     </TextBlock> 
    </DataTemplate> 
    </UserControl.Resources> 

    <Grid DataContext="{Binding ElementName=root}"> 
    <StackPanel Background="Red" TextElement.Foreground="White"> 
     <StackPanel.Resources> 
     <Style x:Key="MyDefaultHyperlinkStyle" TargetType="Hyperlink" BasedOn="{StaticResource {x:Type Hyperlink}}"> 
      <Setter Property="Foreground" Value="Yellow"/> 
      <Style.Triggers> 
      <Trigger Property="IsMouseOver" Value="True"> 
       <Setter Property="Foreground" Value="White"/> 
      </Trigger> 
      </Style.Triggers> 
     </Style> 
     </StackPanel.Resources> 
     <TextBlock>Data import errors</TextBlock> 
     <ItemsControl ItemsSource="{Binding Messages}"/> 
    </StackPanel> 
    </Grid> 
</UserControl> 

Così com'è sopra, questo genera un InvalidOperationException, affermando "Può unica base su di uno stile con tipo di destinazione che è di tipo base 'IFrameworkInputElement'."

Questo problema può essere risolto inserendo TargetType="Hyperlink" nella definizione Style all'interno dell'elemento UserControl.Resources. Tuttavia, mentre i messaggi vengono visualizzati, la parte di collegamento di loro ha ancora il valore predefinito styling collegamento ipertestuale blu:

Blue hyperlinks persist

Insomma, non funziona, quindi mi piacerebbe accogliere eventuali altri suggerimenti/correzioni. :(

Aggiornamento 2:
Grazie ad una soluzione alternativa da Pavlo, ora è lavoro :)

risposta

7

Dopo un po 'googling mi sono imbattuto in questo post:. http://www.11011.net/archives/000692.html.

Come descritto lì, si scopre che gli elementi che non sono derivati ​​da Control (come TextBlock e Hyperlink) non cercano stili impliciti al di fuori del confine DataTemplate.

Ancora una volta, come dice l'articolo, la possibile soluzione è specificare esplicitamente la chiave di stile. Nel tuo caso potrebbe essere qualcosa di simile:

<StackPanel Background="Red" TextElement.Foreground="White"> 
    <StackPanel.Resources> 
    <Style x:Key="MyDefaultHyperlinkStyle" TargetType="Hyperlink" BasedOn="{StaticResource {x:Type Hyperlink}}"> 
     <Setter Property="Foreground" Value="Yellow"/> 
     <Style.Triggers> 
     <Trigger Property="IsMouseOver" Value="True"> 
      <Setter Property="Foreground" Value="White"/> 
     </Trigger> 
     </Style.Triggers> 
    </Style> 
    </StackPanel.Resources> 
    <TextBlock>Data import errors</TextBlock> 
    <ItemsControl ItemsSource="{Binding Errors}"/> 
</StackPanel> 

Quindi, è possibile aggiungere uno stile implicito per Hyperlink che appena fa riferimento il nostro stile di nome nelle DataTemplate risorse:

<DataTemplate DataType="{x:Type Importer:ConversionDetailsMessage}"> 
    <DataTemplate.Resources> 
    <Style TargetType="{x:Type Hyperlink}" 
      BasedOn="{StaticResource MyDefaultHyperlinkStyle}"/> 
    </DataTemplate.Resources> 
    <TextBlock> 
    <Run Text="{Binding Message, Mode=OneTime}"/> 
    <Hyperlink Command="Common:ImportDataCommands.ExplainConversionMessage" CommandParameter="{Binding}"> 
     <Run Text="{Binding HelpLink.Item2, Mode=OneTime}"/> 
    </Hyperlink> 
    </TextBlock> 
</DataTemplate> 

E perché il modello di dati può essere usato in posti diversi, c'è la possibilità che il contenitore genitore non definisca uno stile con la chiave "MyDefaultHyperlinkStyle". In questo caso verrà generata un'eccezione dicendo che la risorsa "MyDefaultHyperlinkStyle" non può essere trovata. Per far fronte a questo, si può definire uno stile con tale chiave che erediterà solo stile predefinito da qualche parte nel App.xaml:

<Style x:Key="MyDefaultHyperlinkStyle" 
     BasedOn="{StaticResource {x:Type Hyperlink}}/> 

Aggiornamento:

Il codice è stato incluso nel vostro aggiornamento non funzionerà perché della natura delle risorse statiche, il che significa che il seguente riferimento risorsa nel modello di data ...

BasedOn="{StaticResource MyDefaultHyperlinkStyle}" 

... sarà sempre puntare al seguente risorsa (che è lo stile predefinito):

<Style x:Key="MyDefaultHyperlinkStyle" BasedOn="{StaticResource {x:Type Hyperlink}}"/> 

riferimenti di risorse statiche sono risolti al momento della compilazione, pertanto, la risorsa più vicina nella struttura viene utilizzata.

Potresti essere tentato di utilizzare DynamicResource, ma sfortunatamente non è supportato dalla proprietà BasedOn.

MA, Foreground proprietà supporta risorse dinamiche, in modo da poter usare lo stesso trucco con le spazzole che utilizziamo all'interno della nostra stile. Qui è il vostro controllo utente di prova modificati per utilizzare pennelli dinamici:

<UserControl x:Class="DataTemplateStyling.StylingView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:DataTemplateStyling="clr-namespace:DataTemplateStyling" 
      x:Name="root" 
      Loaded="StylingViewLoaded"> 

    <UserControl.Resources> 
     <SolidColorBrush x:Key="HyperlinkForeground" 
         Color="Blue" /> 

     <SolidColorBrush x:Key="HyperlinkHoverForeground" 
         Color="Gray" /> 

     <Style x:Key="MyDefaultHyperlinkStyle" 
       TargetType="Hyperlink" 
       BasedOn="{StaticResource {x:Type Hyperlink}}"> 
      <Setter Property="Foreground" 
        Value="{DynamicResource HyperlinkForeground}" /> 
      <Style.Triggers> 
       <Trigger Property="IsMouseOver" 
         Value="True"> 
        <Setter Property="Foreground" 
          Value="{DynamicResource HyperlinkHoverForeground}" /> 
       </Trigger> 
      </Style.Triggers> 
     </Style> 

     <DataTemplate DataType="{x:Type DataTemplateStyling:ImportMessage}"> 
      <DataTemplate.Resources> 
       <Style TargetType="{x:Type Hyperlink}" 
         BasedOn="{StaticResource MyDefaultHyperlinkStyle}" /> 
      </DataTemplate.Resources> 
      <TextBlock> 
       <Run Text="{Binding Message, Mode=OneTime}" /> 
       <Hyperlink NavigateUri="{Binding HelpLink.Item1}"> 
        <Run Text="{Binding HelpLink.Item2, Mode=OneTime}" /> 
       </Hyperlink> 
      </TextBlock> 
     </DataTemplate> 
    </UserControl.Resources> 

    <Grid DataContext="{Binding ElementName=root}"> 
     <StackPanel Background="Red" 
        TextElement.Foreground="White"> 
      <StackPanel.Resources> 
       <SolidColorBrush x:Key="HyperlinkForeground" 
           Color="Yellow" /> 

       <SolidColorBrush x:Key="HyperlinkHoverForeground" 
           Color="White" /> 
      </StackPanel.Resources> 
      <TextBlock>Data import errors</TextBlock> 
      <ItemsControl ItemsSource="{Binding Messages}" /> 
     </StackPanel> 
    </Grid> 
</UserControl> 

funziona come previsto, vale a dire tutti i collegamenti all'interno StackPanel sarà giallo/bianco, mentre all'esterno saranno blu.

Spero che questo aiuti.

+0

Abilità fantastiche googling - grazie! E una risposta molto completa. Lo proverò e lo contrassegnerò come accettato una volta che avrò funzionato. –

+0

Hai dimenticato la mia app è un'app di WinForms che utilizza un 'ElementHost', quindi non ho un file app.xaml. Tuttavia, il principio sembrava valido, quindi ho provato ad aggiungere un 'MyDefaultHyperlinkStyle' vuoto immediatamente prima di' DataTemplate' nel mio dizionario delle risorse 'UserControl' e ho lasciato lo specifico 'StackPanel' visto in precedenza per sostituirlo con una sua definizione. Purtroppo, non funziona ancora. Continuerò a provare le cose ... –

+0

@Mal - Non hai dimenticato di includere lo stile nel modello dati stesso: '