2010-10-04 15 views
10

सिल्वरलाइट 4 & WPF 4 का उपयोग करके, मैं एक बटन शैली बनाने की कोशिश कर रहा हूं जो बटन को माउसओवर किए जाने पर किसी भी निहित पाठ के टेक्स्ट रंग को बदल देता है। जब से मैं इस दोनों सिल्वरलाइट & WPF के साथ संगत बनाने के लिए कोशिश कर रहा हूँ, मैं दृश्य राज्य प्रबंधक का उपयोग कर रहा:एक बटन के नियंत्रण टेम्पलेट में, मैं निहित पाठ का रंग कैसे सेट कर सकता हूं?

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

चूंकि यह एक नियमित रूप से पुराने बटन के लिए एक टेम्पलेट है, मुझे पता है कोई गारंटी है कि इसके अंदर एक टेक्स्टब्लॉक भी है, और पहले मुझे यकीन नहीं था कि यह भी संभव था। मजे की बात है, पाठ रंग में बदल जाती है बटन की तरह घोषित किया जाता है, तो:

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

लेकिन यह नहीं में बदल जाती है, तो बटन की तरह घोषित किया जाता है:

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

हालांकि दृश्य पेड़ (जब स्नूप में निरीक्षण किया जाता है) समान (बटन -> सामग्री प्रस्तुतकर्ता -> टेक्स्टब्लॉक) है, इस चेतावनी के साथ कि पहले संस्करण में बनाए गए टेक्स्टब्लॉक में इसका डेटा संदर्भ "हैलो, वर्ल्ड" पर सेट है, जबकि दूसरे संस्करण में टेक्स्टब्लॉक केवल इसके है पाठ संपत्ति सेट। मुझे लगता है कि इसने नियंत्रण निर्माण के आदेश के साथ कुछ करने के लिए कुछ किया है (बटन का पहला संस्करण टेक्स्टब्लॉक बनाता है, दूसरे संस्करण में टेक्स्टब्लॉक पहले बनाया जा सकता है? वास्तव में इस पर निश्चित नहीं है)।

इस शोध के दौरान, मैंने कुछ समाधान देखे हैं जो सिल्वरलाइट में काम करते हैं (जैसे ContentPresenter को ContentControl के साथ बदलना), लेकिन यह WPF (प्रोग्राम वास्तव में क्रैश) में काम नहीं करेगा।

चूंकि यह बटन के नियंत्रण टेम्पलेट में है, और यदि संभव हो तो मैं वीएसएम का उपयोग करना चाहता हूं, मुझे लगता है कि बटन की अपनी अग्रभूमि संपत्ति को स्पष्ट रूप से बदलना भी नियम है (मुझे नहीं पता कि मैं इसे कैसे एक्सेस करूं टेम्पलेट के भीतर?)

मैं वास्तव में किसी भी मदद की सराहना करता हूं, कोई भी सलाह दे सकता है।

+0

का उपयोग करें मुझे आश्चर्य है कि टेक्स्टलेक्शन को टेक्स्टब्लॉक के साथ कुछ भी नहीं मिला है। – Denis

उत्तर

5

तो कुछ और सोच के बाद, समाधान मैं अंततः पर पहुंच गए बटन के नियंत्रण खाके में ContentPresenter तत्व को एक संलग्न संपत्ति जोड़ना है। संलग्न संपत्ति रंग को स्वीकार करती है और जब सेट किसी भी टेक्स्टब्लॉक के लिए सामग्री प्रस्तुतकर्ता के दृश्य पेड़ की जांच करता है, और बदले में उनके अग्रभूमि गुणों को पास किए गए मान पर सेट करता है। यह स्पष्ट रूप से अतिरिक्त तत्वों को संभालने के लिए विस्तारित/बनाया जा सकता है लेकिन अब यह काम करता है मुझे जो चाहिए

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

और मैं बहुत तरह टेम्पलेट संशोधित:

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

यह भी एक अच्छा समाधान है। मैं उत्सुक हूं कि एनीमेशन स्टोरीबोर्ड जो आप उपयोग करने में सक्षम होंगे क्योंकि आप एक स्टेटिक रिसोर्स के लिए बाध्यकारी हैं। – Jeremiah

+0

मुझे कलरएनीमेशन या कुछ समान के विपरीत ऑब्जेक्टएनीमेशन यूज़िंगकेफ्रेम का उपयोग करना पड़ा। – Jordan0Day

4

यह एक मुश्किल है। अग्रभूमि उस बटन की एक संपत्ति है जो सामग्री प्रस्तुतकर्ता द्वारा नियंत्रित नियंत्रणों के माध्यम से पारित किया जाता है। चूंकि यह एक निर्भरता संपत्ति है और टेम्पलेट में उपलब्ध नियंत्रणों की संपत्ति नहीं है, इसलिए शुद्ध xaml का उपयोग करके इसे एनिमेट करना मुश्किल है।

एमएसडीएन में अग्रभूमि रंग बदलने के तरीके पर कुछ नमूने हैं। हालांकि, ऐसा लगता है कि आप कोड से यह काम नहीं करना चाहते हैं। (http://msdn.microsoft.com/en-us/library/system.windows.controls.button(VS.95).aspx)

बटन का डिफ़ॉल्ट टेम्पलेट आपको वापस पकड़ रहा है। जैसा कि आपने देखा है, बटन एक सामग्री-कम नियंत्रण है; जिसका मतलब है कि डिजाइनर इसके अंदर कुछ यादृच्छिक दृश्य वस्तु को धक्का दे सकता है। कंटेंट-कम होने के कारण फोरग्राउंड प्रॉपर्टी को नियंत्रण के बजाए टेम्पलेट का सदस्य बनना पड़ता है क्योंकि रंग को सेट करने के लिए कोई गारंटेंटेड घटक नहीं है। यही कारण है कि इसके अंदर एक सामग्री प्रस्तुतकर्ता है।

तो अब आपके पास दो विकल्प हैं। 1. आसान लेकिन लचीला नहीं (शुद्ध xaml), 2. अपना स्वयं का नियंत्रण बनाएं जो सब कुछ करता है बटन (कोड और बहुत सारे परीक्षण की आवश्यकता होती है)

मैं आपके लिए # 1 लागू करूंगा।

यदि आप बटन के टेम्पलेट को संशोधित करते हैं और सामग्री प्रस्तुतकर्ता हटाते हैं तो आप इसके अंदर दो टेक्स्टब्लॉक रख सकते हैं। एक सामान्य रंग के साथ, दूसरा माउस पर रंग के साथ।

<TextBlock x:Name="RedBlock" Text="{TemplateBinding Content}"  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Foreground="Red" Visibility="Collapsed"/>  
<TextBlock x:Name="BlueBlock" Text="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Foreground="#FF0027FF"/> 

ध्यान दें कि टेक्स्टब्लॉक्स के टेक्स्ट गुण बटन से सामग्री के लिए बाध्य हैं। पाठ के अलावा किसी भी चीज से बंधने की आवश्यकता होने पर यह एक समस्या बन जाती है। टेक्स्टब्लॉक बस अल्फा न्यूमेरिक मानों के अलावा कुछ भी नहीं दिखा सकते हैं।

यह भी ध्यान दें कि डिफ़ॉल्ट रूप से मैंने RedBlock पर दृश्यता को ध्वस्त कर दिया है।

फिर, मेरी MouseOver VisualState's Storyboard में मैं RedBlock चेतन दिखाई दे सकता है कर सकते हैं और BlueBlock अदृश्य होने के लिए:

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

यह एक हैक की तरह लगता है, और मैं शायद बहुत-से स्थान में इस बटन को लागू नहीं होता । मैं अपने खुद के बटन को अच्छी निर्भरता के साथ बांधना चाहता हूं। हाइलाइटफॉरग्राउंड और टेक्स्ट के लिए प्रत्येक एक। अगर कोई अल्फा न्यूमेरिक मानों के अलावा किसी भी चीज़ को सामग्री सेट करने का प्रयास करता है तो मैं छिपाना या कम से कम अपवाद फेंकना चाहता हूं। हालांकि, एक्सएएमएल वही होगा, मेरे पास अलग-अलग दृश्य राज्यों के लिए अलग-अलग टेक्स्टब्लॉक होंगे।

मुझे उम्मीद है कि इससे मदद मिलती है।

एक अच्छा दिन है।

-Jeremiah

+0

हाय यिर्मयाह, यह वास्तव में एक अच्छा समाधान है और ऐसी परिस्थिति में अच्छी तरह से काम करता है जहां बटन में केवल टेक्स्ट होगा। मेरे मामले में मैं एक समाधान अधिक सामान्य बनाना चाहता हूं, ताकि किसी भी टेक्स्टब्लॉक बच्चों को उनके अग्रभूमि रंग सेट मिल जाए। (ध्यान देने योग्य कोई भी दिलचस्प बात यह है कि जब आप अपनी फोरग्राउंड संपत्ति को स्पष्ट रूप से सेट करते हैं तो बटन काम करता है - किसी भी बच्चे टेक्स्टब्लॉक को उचित रंग प्राप्त होता है, इससे कोई फर्क नहीं पड़ता कि वे बटन की सामग्री में पैनल/नियंत्रण के अंदर घोंसला कैसे रखते हैं। मैंने समाधान का विस्तृत विवरण दिया है मैं अंततः इस धागे में संलग्न गुणों का उपयोग करने के लिए पहुंचा हूं। – Jordan0Day

0

मैं अपने टेम्पलेट में इस का उपयोग करें और यह ठीक काम करता है

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

आप इस कोड डालना होगा अपने बटन टेम्पलेट निर्माण लेकिन जब मैं बटन सामग्री में टेक्स्ट डालता हूं और यदि आप चाहते हैं तो मैं इसका उपयोग करता हूं इस पर अन्य नियंत्रण जोड़ने के लिए सामान्य शैली