2010-10-04 19 views
10

Silverlight 4'ü kullanma & WPF 4, düğmenin fareyle üzerine gelindiğinde, içerilen herhangi bir metnin metin rengini değiştiren bir düğme stili oluşturmaya çalışıyorum. Hem Silverlight & WPF ile bu uyumlu hale getirmek için çalışıyorum, ben görsel devlet yöneticisini kullanıyorum: Bu normal bir eski düğme için bir şablon olduğu içinBir düğmenin denetim şablonunda, içerilen metnin rengini nasıl ayarlayabilirim?

<Style TargetType="{x:Type Button}"> 
<Setter Property="Template"> 
    <Setter.Value> 
     <ControlTemplate TargetType="Button"> 
      <Border x:Name="outerBorder" CornerRadius="4" BorderThickness="1" BorderBrush="#FF757679"> 
       <VisualStateManager.VisualStateGroups> 
        <VisualStateGroup x:Name="CommonStates"> 
         <VisualState x:Name="Normal" /> 
         <VisualState x:Name="MouseOver"> 
          <Storyboard> 
           <ColorAnimation Duration="0" To="#FFFEFEFE" 
               Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)" 
               Storyboard.TargetName="contentPresenter"/> 
          </Storyboard> 
         </VisualState> 
        </VisualStateGroup> 
       </VisualStateManager.VisualStateGroups> 
       <Grid> 
        <Border x:Name="Background" CornerRadius="3" BorderThickness="1" BorderBrush="Transparent"> 
         <Grid> 
          <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}"/> 
         </Grid> 
        </Border> 
       </Grid> 
      </Border> 
     </ControlTemplate> 
    </Setter.Value> 
</Setter> 

, ben hiçbir olduğunu biliyorum İçinde bir metin bloğu bile olduğunu garanti ettim ve ilk başta bunun mümkün olduğundan emin değildim. düğme gibi beyan edilmiş olması halinde

<Button Content="Hello, World!" /> 

ama değil değişikliği yapar:: İlginç, değişikliği yapar metin rengi düğmesi gibi beyan edilmiş olması halinde

<Button> 
    <TextBlock Text="Hello, World!" /> <!-- Same result with <TextBlock>Hello, World </TextBlock> --> 
</Button> 

rağmen görsel ağacı (snoop içinde incelenirken aynıdır (Button -> ContentPresenter -> TextBlock), 1. sürümde oluşturulan metin bloğunun veri bağlamının "Merhaba, Dünya" olarak ayarlanmış olmasına karşın, ikinci sürümdeki metin bloğunun yalnızca metin özellik kümesi. Bunun, kontrol oluşturma sırasına göre bir şeyler yapabileceğini sanıyorum (ilk düğme, TextBlock'u yaratır, ikinci versiyonda metin bloğu ilk olarak oluşturulabilir? Bu konuda gerçekten emin değilim).

Bu araştırmayı yaparken, Silverlight'ta (ContentPresenter'ı ContentControl ile değiştirmek gibi) çalışan bazı çözümler gördüm, ancak bu WPF'de çalışmayacaktır (program çöküyor).

Bu, düğmenin denetim şablonunda olduğundan ve eğer mümkünse VSM'yi kullanmak istediğime göre, aynı zamanda, Button'un kendi Foreground özelliğini açıkça değiştirmeyi de göz önünde bulundurduğumu düşünüyorum (buna nasıl erişeceğimi bilmiyorum şablon içinde?)

Herhangi bir yardım için minnettar olurum, kimsenin verebileceği tavsiyesi.

+0

TextElement'in TextBlock ile hiçbir ilgisi olmadığını düşündüğümde işe yaradığına şaşırdım. – Denis

cevap

5

Yani biraz daha düşünme sonra ben sonuçta vardık çözüm düğmenin kontrol şablonu içinde ContentPresenter elemana bağlı bir özellik eklemektir. Eklenen özellik bir Renk kabul eder ve ayarlandığında, herhangi bir TextBlock için içerik sunucusunun görsel ağacını inceler ve sırayla Önplan özelliklerini, iletilen değere ayarlar. Bu, ek öğeleri ele alacak şekilde genişletilebilir/oluşturulabilir, ancak şimdilik çalışır İhtiyacım olan şey için.

public static class ButtonAttachedProperties 
    { 
     /// <summary> 
     /// ButtonTextForegroundProperty is a property used to adjust the color of text contained within the button. 
     /// </summary> 
     public static readonly DependencyProperty ButtonTextForegroundProperty = DependencyProperty.RegisterAttached(
      "ButtonTextForeground", 
      typeof(Color), 
      typeof(FrameworkElement), 
      new FrameworkPropertyMetadata(Color.FromArgb(255, 0, 0, 0), FrameworkPropertyMetadataOptions.AffectsRender, OnButtonTextForegroundChanged)); 

     public static void OnButtonTextForegroundChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) 
     { 
      if (e.NewValue is Color) 
      { 
       var brush = new SolidColorBrush(((Color) e.NewValue)) as Brush; 
       if (brush != null) 
       { 
        SetTextBlockForegroundColor(o as FrameworkElement, brush); 
       } 
      } 
     } 

     public static void SetButtonTextForeground(FrameworkElement fe, Color color) 
     { 
      var brush = new SolidColorBrush(color); 
      SetTextBlockForegroundColor(fe, brush); 
     } 

     public static void SetTextBlockForegroundColor(FrameworkElement fe, Brush brush) 
     { 
      if (fe == null) 
      { 
       return; 
      } 

      if (fe is TextBlock) 
      { 
       ((TextBlock)fe).Foreground = brush; 
      } 

      var children = VisualTreeHelper.GetChildrenCount(fe); 
      if (children > 0) 
      { 
       for (int i = 0; i < children; i++) 
       { 
        var child = VisualTreeHelper.GetChild(fe, i) as FrameworkElement; 
        if (child != null) 
        { 
         SetTextBlockForegroundColor(child, brush); 
        } 
       } 
      } 
      else if (fe is ContentPresenter) 
      { 
       SetTextBlockForegroundColor(((ContentPresenter)fe).Content as FrameworkElement, brush); 
      } 
     } 
    } 

ve ben şöyle şablonu değiştirilmiş: Sen Bu kodu eklemelisiniz

<ControlTemplate TargetType="Button"> 
       <Border 
        Margin="{TemplateBinding Margin}" 
        BorderBrush="{StaticResource BorderBrush}" 
        BorderThickness="{TemplateBinding BorderThickness}" 
        CornerRadius="2" 
        > 

        <TextBlock 
         Margin="{TemplateBinding Padding}" 
         Text="{TemplateBinding Content}" 
         Foreground="White" 
         HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
         VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> 
       </Border> 

<ContentPresenter x:Name="contentPresenter" 
        ContentTemplate="{TemplateBinding ContentTemplate}" 
        local:ButtonAttachedProperties.ButtonTextForeground="{StaticResource ButtonTextNormalColor}" /> 
+0

Bu da iyi bir çözüm, bir StaticResource'a bağlandığınız için hangi animasyon storyboard'larını kullanabileceğinizi merak ediyorum. – Jeremiah

+0

Bir ColorAnimation veya benzer bir şeyin aksine ObjectAnimationUsingKeyFrames kullanmak zorunda kaldım. – Jordan0Day

4

Bu zor bir sorundur. Önplan, içerik sunucusunun oluşturduğu kontrollere aktarılan düğmenin bir özelliğidir. Bir bağımlılık özelliği olduğundan ve şablonda bulunan denetimlerin bir özelliği olmadığından, onu saf xaml kullanarak canlandırmak zordur.

MSDN Ön plan renginin nasıl değiştirileceğine dair birkaç örneği vardır. Ancak, bu işi koddan yapmak istediğiniz gibi gelmiyor. (http://msdn.microsoft.com/en-us/library/system.windows.controls.button(VS.95).aspx)

Düğmenin varsayılan şablonu sizi geri tutuyor. Fark ettiğiniz gibi, düğme içeriksiz bir kontroldür; Tasarımcının anlamı, içinde rastgele bir görsel nesne itebilir. İçeriği daha az olmak, ön plan özelliğinin, rengin ayarlanması için bir guarrantlı bileşen olmadığından, denetimden ziyade şablonun bir üyesi olmasını zorlar. Bunun için içinde bir içerik sunucusu var.

Şimdi iki seçeneğiniz var. 1. Kolay ama esnek değil (saf xaml), 2. Bir düğmenin yaptığı her şeyi yapan kendi kontrolünüzü yaratın (kod ve çok sayıda test gerektirir)

Sizin için # 1 uygulayacağım.

Düğmenin şablonunu değiştirirseniz ve İçerik Sunucusu'u kaldırırsanız, iki metin bloğunun içine yerleştirebilirsiniz. Biri normal renkle, diğeri ise farenizle renkteyken.

Metin Bloklarının Metin özelliklerinin düğmeden içeriğe nasıl bağlandığına dikkat edin. Metin dışında bir HERHANGİ BİR ŞEKİLDE bağlama gereksinimi varsa bu sorun olur. TextBlocks sadece AlphaNumeric değerleri bir şey gösteremez. Ayrıca, varsayılan olarak RedBlock üzerindeki görünürlüğü daraltmış olduğumu da unutmayın.

Sonra benim MouseOver VisualState's Storyboard I görünür olmasını RedBlock canlandırabilirsiniz ve BlueBlock görünmez olmak:

<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="RedBlock"> 
    <DiscreteObjectKeyFrame KeyTime="0"> 
     <DiscreteObjectKeyFrame.Value> 
      <Visibility>Visible</Visibility> 
     </DiscreteObjectKeyFrame.Value> 
    </DiscreteObjectKeyFrame> 
</ObjectAnimationUsingKeyFrames> 
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="BlueBlock"> 
    <DiscreteObjectKeyFrame KeyTime="0"> 
     <DiscreteObjectKeyFrame.Value> 
      <Visibility>Collapsed</Visibility> 
     </DiscreteObjectKeyFrame.Value> 
    </DiscreteObjectKeyFrame> 
</ObjectAnimationUsingKeyFrames> 

O kesmek gibi hissediyor, ve muhtemelen pek çok yeri bu düğmeye uygulamak olmaz . Bağlamak için iyi DependencyProperties ile kendi Düğme yapmak istiyorum. HighlightForeground ve Metin için bir tane. Ayrıca, içeriği bir şeyi AlphaNumeric değerleri dışındaki herhangi bir şeye ayarlamaya çalıştıysa gizlemek veya en azından bir istisna atmak istiyorum. Bununla birlikte, XAML aynı olurdu, farklı görsel durumlar için farklı metin blokları olurdu.

Umarım bu yardımcı olur.

Harika bir gün geçirin.

-Jeremiah

+0

Merhaba Yeremya, bu gerçekten güzel bir çözüm ve düğmenin sadece metin içerdiği bir durumda iyi çalışıyor. Benim durumumda daha genel bir çözüme sahip olmak istiyorum, böylece herhangi bir metin engelli çocuk ön plan renklerini ayarlayacak. (Dikkat edilmesi gereken ilginç bir şey, Button'ın Foreground özelliğini açıkça ayarladığınızda nasıl çalıştığıdır - herhangi bir çocuk TextBlock, düğmelerin içeriğindeki paneller/denetimler arasında nasıl yuvalanmış olursa olsun, uygun rengi alır. Sonunda bu konudaki ekli özellikleri kullanmaya başladım: – Jordan0Day

0

Şablonumdaki bu kullanmak ve iyi çalışıyor senin düğme şablonu oluşturma ama bunu kullanıyorum, düğme içeriğine metin koydum ve isterseniz üzerine başka kontroller eklemek için normal stili kullanın