2011-03-03 14 views
7

Próbuję ustawić kolor Foreground na Hyperlink przy użyciu obiektu Style w obiekcie Resources przodka, ale nie ma to żadnego wpływu. Użyłem nawet końcówki BasedOn od Changing Hyperlink foreground without losing hover color, ale to nie ma znaczenia - wciąż dostaję niebieskie hiperłącze, które jest czerwone po najechaniu myszą.Jak propagować style do hiperłączy wewnątrz DataTemplate?

Oto XAML dla moich kontroli, w tym ItemsControl którego elementy są pokazane za pomocą hiperłącza:

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

a elementy w ItemsControl są podniesieniu następującym 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> 

To Warto też zauważyć, że nie chcę po prostu ustawiać różnych kolorów bezpośrednio na Hyperlink w DataTemplate. Dzieje się tak, ponieważ szablon będzie używany przez o numerach różnych obiektów ItemsControl, z których większość będzie na białym tle i dlatego może używać standardowych kolorów hiperłączy. (Zauważ, że ten w powyższym XAML ma czerwone tło).

Krótko mówiąc, nie chcę, aby DataTemplate musiał wiedzieć cokolwiek na temat kontroli, w której jest używany. Style elementów sterujących szablonu powinny po prostu odfiltrować do niego.

Więc ... czy ktoś może mi powiedzieć, dlaczego styl nie jest filtrowany i co mogę zrobić, aby to naprawić?

Dzięki.

Aktualizacja:
ponieważ nie mogłem dostać odpowiedź Pavlo do pracy w mojej aplikacji produkcyjnej, mam od próbował go w osobnej aplikacji testowej. Aplikacja jest aplikacją WinForms, z głównym formularzem zawierającym tylko numer ElementHost, który sam zawiera proste sterowanie użytkownika WPF. Oto jego XAML: „Może bazę tylko w stylu z rodzaju docelowej, która jest typ bazowy«IFrameworkInputElement»”

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

Jak stoi wyżej, to generuje InvalidOperationException, stwierdzając

Można to naprawić, umieszczając TargetType="Hyperlink" na definicji Style bezpośrednio wewnątrz elementu UserControl.Resources. Jednakże, podczas gdy komunikaty są wyświetlane, część z nich nadal ogniwo ma domyślny niebieski hiperłącza stylizacji:

Blue hyperlinks persist

W skrócie, to nie działa, więc chciałbym powitać wszelkie inne sugestie/poprawki. :(

Aktualizacja 2:
Dzięki alternatywnego rozwiązania z Pavlo, to teraz jest pracy :)

Odpowiedz

7

Po niektóre googling wpadłem na to stanowisko. http://www.11011.net/archives/000692.html.

Jak opisano tam okazuje się, że elementy, które nie pochodzą od Control (jak TextBlock i Hyperlink) nie szukać ukrytych stylów poza granicami DataTemplate.

Ponownie, jak mówi artykuł, możliwym rozwiązaniem jest jawne określenie klucza stylu. W twoim przypadku może to być coś takiego:

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

Następnie można dodać niejawny styl Hyperlink że właśnie Referencje nazwie styl w zasobach DataTemplate:

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

A ponieważ szablonu danych może być używany w różnych miejscach, istnieje możliwość, że kontener macierzysty nie definiuje stylu za pomocą klucza "MyDefaultHyperlinkStyle". W takim przypadku zostanie zgłoszony wyjątek, że nie można znaleźć zasobu "MyDefaultHyperlinkStyle". Aby rozwiązać ten problem, można zdefiniować styl z takiego klucza, który będzie dziedziczyć tylko domyślny styl gdzieś w App.xaml:

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

Aktualizacja:

Kod ty zawarte w aktualizacji nie będzie działać, ponieważ charakteru zasobów statycznych, co oznacza, że ​​następuje odniesienie zasobem data szablonu ...

BasedOn="{StaticResource MyDefaultHyperlinkStyle}" 

... zawsze będzie wskazywać na poniższej zasobu (który jest domyślny styl):

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

Statyczne odniesienia do zasobów są rozwiązywane w czasie kompilacji, dlatego używany jest najbliższy zasób w drzewie.

Może być pokusę użycia DynamicResource, ale niestety nie jest obsługiwana właściwość BasedOn.

ALE Foreground nieruchomość obsługuje dynamicznych zasobów, dzięki czemu możemy korzystać z tego samego triku ze szczotkami używamy wewnątrz naszego stylu. Oto twoja kontrola użytkownik testu zmodyfikowane do wykorzystania dynamicznych pędzli:

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

To działa zgodnie z oczekiwaniami, czyli wszystkie linki wewnętrzne StackPanel będzie Żółty/Biały, podczas gdy na zewnątrz będą niebieskie.

Mam nadzieję, że to pomoże.

+0

Niesamowite umiejętności googlingowe - dzięki! I bardzo kompletna odpowiedź. Po prostu wypróbuję to i oznaczę jako zaakceptowany, gdy tylko zadziała. –

+0

Nie pamiętam, że moja aplikacja to aplikacja WinForms używająca elementu ElementHost, więc nie mam pliku app.xaml. Zasada wydawała się jednak dobra, więc próbowałem dodać pusty "MyDefaultHyperlinkStyle" bezpośrednio przed 'DataTemplate' w moim słowniku' UserControl' i opuściłem określony 'StackPanel' widziany powyżej, aby zastąpić go własną definicją. Niestety, wciąż nie działa. Będę próbować rzeczy ... –

+0

@Mal - Nie można zapomnieć w tym stylu w szablonie samego danych: ' '? –

Powiązane problemy