2009-10-31 12 views
13

वहाँ एक एनीमेशन एक बार XAML में कहीं परिभाषित करने के लिए (जैसे। एक संसाधन के रूप में) और फिर इसे पुन: उपयोग कई बार कोई तरीका है? मेरे पास अलग-अलग डेटामैप्लेट्स में बहुत से स्वतंत्र ब्रश हैं जिन्हें डेटाैट्रिगर के आधार पर स्वतंत्र रूप से उसी तरह की एनीमेशन शुरू करने की आवश्यकता होती है। अब ऐसा लगता है कि एक एनीमेशन को स्टोरीबोर्ड को परिभाषित करना है। लक्ष्यनाम और स्टोरीबोर्ड। लक्ष्यप्रोपर्टी। यह काफी पुन: प्रयोज्यता के उद्देश्य को हरा देता है। मैं किसी भी तरह से घोषणा करना चाहता हूं "इस एनीमेशन का उपयोग संसाधन का उपयोग करें, लेकिन इस बार इसे किसी अन्य तत्व पर लागू करें"।पुन: प्रयोज्य संसाधन के रूप में एनिमेशन और ट्रिगर परिभाषित करता है?

मेरे लिए यह एक बुनियादी, महत्वपूर्ण और आवश्यक अनुरोध प्रतीत होता है और मुझे आश्चर्य है कि यह सीधे आगे बढ़ने के लिए आगे नहीं है। क्या मुझसे कोई चूक हो रही है?

वही बात ट्रिगर्स के लिए लागू होती है। मान लीजिए मेरे पास बहुत सारे दृश्य तत्व हैं जो रंगीन एनिमेशन का उपयोग करते हुए सभी प्रकार के राज्य का प्रतिनिधित्व करते हैं। जैसे हरे रंग फीका जब "सक्रिय" "लाल" को फीका जब "त्रुटि" आदि दृश्यों के बीच फर्क सिर्फ इतना है उनके आकार/दृश्य पेड़ है वांछित एनीमेशन व्यवहार ही है, वे सब उनके दृश्य पेड़ है कि कहीं एक तत्व है प्रकार के रंग की एक संपत्ति। मुझे लगता है कि कल्पना करना मुश्किल नहीं है कि एक ही एनिमेशन और डेटाट्रिगर सेट को बार-बार फिर से परिभाषित करना कितना कठिन है। प्रत्येक डेवलपर इससे नफरत करता है। मैं बेहद आसान समाधान की तलाश में हूं जिसके लिए कोई (या कम से कम बहुत कम) सी # कोड की आवश्यकता नहीं है।

एक संसाधन में एनिमेशन को परिभाषित करें lik इस (सभी बुनियादी राज्यों के लिए यह दोहराने देखते हैं कि सक्रिय करने, सक्रिय, निष्क्रिय, त्रुटि की तरह,):

क्या मैं अब तक के साथ आए हैं यह है

<ColorAnimationUsingKeyFrames x:Key="deactivatingColorAnimation" 
        Storyboard.TargetProperty="Material.(MaterialGroup.Children)[0].Brush.(SolidColorBrush.Color)"      
        FillBehavior="HoldEnd" RepeatBehavior="Forever" AutoReverse="True"> 
     <ColorAnimationUsingKeyFrames.KeyFrames> 
     <LinearColorKeyFrame KeyTime="00:00:00" Value="Gray"/> 
     <LinearColorKeyFrame KeyTime="00:00:0.25" Value="Gray"/> 
     <LinearColorKeyFrame KeyTime="00:00:0.5" Value="Gray" /> 
     <LinearColorKeyFrame KeyTime="00:00:0.75" Value="Gray" /> 
    </ColorAnimationUsingKeyFrames.KeyFrames> 
</ColorAnimationUsingKeyFrames> 

उपयोग यह स्टोरीबोर्ड में चलाता में (प्रत्येक राज्य एक्स प्रत्येक differnt stateviusal के लिए समय की इस zillions दोहराए जाते हैं, हमेशा स्टोरीबोर्ड लिए कोई नया नाम के साथ आते हैं):

<DataTrigger Binding="{Binding SubstrateHolder.State}" Value="Deactivating"> 
     <DataTrigger.EnterActions> 
      <BeginStoryboard x:Name="someStateVisualDeactivatingStoryboard"> 
       <Storyboard Storyboard.TargetName="someStateVisual"> 
        <StaticResource ResourceKey="deactivatingColorAnimation" /> 
       </Storyboard> 
      </BeginStoryboard> 
     </DataTrigger.EnterActions> 
     <DataTrigger.ExitActions> 
      <RemoveStoryboard BeginStoryboardName="someStateVisualDeactivatingStoryboard" /> 
     </DataTrigger.ExitActions> 
</DataTrigger> 

आप आसानी से कल्पना कर सकते हैं कि एक्सएएमएल को कितने ब्लोएट को बार-बार उन सभी अरब डेटाट्रिगर्स के लिए कॉपी और पेस्ट करना है।

यह सभी ट्रिगर्स को एक बार परिभाषित करने और विभिन्न राज्य दृश्यों पर लागू करने के लिए अच्छा होगा। डब्ल्यूपीएफ में इस तरह कुछ कैसे हल किया गया है? कोई टिप?

उत्तर

1

इस सामान्य प्रॉपल के लिए कोई अच्छा XAML केवल समाधान प्रतीत नहीं होता है। मैंने अपनी खुद की संलग्न संपत्तियों को लिखना समाप्त कर दिया जो किसी दिए गए तत्व के लिए सभी एनीमेशन व्यवहार को परिभाषित करता है। कुछ इस तरह:

<DataTemplate> 
    <!-- ... --> 
    <Rectangle Fill="Gray"> 
    <v:AnimationHelper.Animations> 
     <v:StandardColorStateAnimation TargetColorProperty="(Rectangle.Fill).(SolidColorBrush.Color)" TraggetSateProperty={Binding State} /> 
    </v:AnimationHelper.Animations> 
    </Rectangle> 
<DataTemplate> 

बाकी (एनीमेशन आदि बनाने) codebehind में किया जाता है।

+0

हां पता है कि मैंने इसके लिए एक सुझाव के साथ आने के लिए विभिन्न चीजों का एक गुच्छा करने की कोशिश की और यह कोड में कुछ किए बिना संभव नहीं था। यह एक अच्छा समाधान है जैसा कि मुझे लगता है कि आप प्राप्त करने जा रहे हैं। WPF विस्तारशीलता के लिए Hurray, है ना? :) –

+0

इसके लिए Silverlight व्यवहार API का उपयोग करना एक अच्छा विचार हो सकता है। क्या आप सहमत हैं? क्या यह मानक .NET 3.5 ढांचे के साथ संगत है? – bitbonk

+0

नहीं, यह संगत नहीं है, हालांकि उन्हें माना जाता है। ईमानदारी से मुझे लगता है कि आपको एक बहुत अच्छा समाधान मिला है जो डब्ल्यूपीएफ आर्किटेक्चर को "प्राकृतिक" तरीके से लेता है और इसे यहां बिल्कुल दूसरा अनुमान नहीं लगाया जाना चाहिए। –

3

आप कुछ इस तरह की कोशिश कर सकता है?

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

मुझे एहसास है कि इस पोस्ट के समय इस मुद्दे को थोड़ा सा मृत है, लेकिन मुझे एक समाधान मिला जिसके लिए बहुत कम कोड की आवश्यकता है।

आप UserControl with custom properties (चित्र 8 के बारे में नीचे स्क्रॉल कर सकते हैं) जिसमें आपके आयत के साथ-साथ एनिमेशन और राज्य ट्रिगर्स भी शामिल हो सकते हैं। यह उपयोगकर्ता नियंत्रण एक सार्वजनिक संपत्ति को परिभाषित करेगा जैसे कि स्थिति जो बदलते समय रंग परिवर्तन को ट्रिगर करेगी।

कोड में अपने चर बनाने के लिए केवल एक ही कोड-बैक आवश्यक है।

उपयोगकर्ता नियंत्रण उन्हें XAML स्टोरीबोर्ड या डेटा ट्रिगर्स को फिर से लिखने के बिना बार-बार उपयोग किया जा सकता है। , मैं उन Storyboard.Target के एक सबसेट के लिए सीमित हैं मान -

0

सबसे "XAML तरीका" इस लक्ष्य को मैं के बारे में सोच सकते हैं प्राप्त करने के लिए समर्पित MarkupExtension जो संसाधनों शब्दकोश से एनीमेशन और आवश्यक गुण सेट खींच जाएगा बनाने के लिए है Storyboard.TargetName और Storyboard.TargetProperty। यद्यपि इसे कुछ कोड-बैक की आवश्यकता है, लेकिन यह एक बार का प्रयास है, इसके अलावा, MarkupExtension एस XAML के साथ उपयोग करने के लिए डिज़ाइन किए गए हैं। यहाँ सबसे सरल संस्करण है:

[MarkupExtensionReturnType(typeof(Timeline))] 
public class AnimationResourceExtension : StaticResourceExtension 
{ 
    //This property is for convienience so that we 
    //don't have to remember to set x:Shared="False" 
    //on all animation resources, but have an option 
    //to avoid redundant cloning if it is 
    public bool IsShared { get; set; } = true; 

    public DependencyObject Target { get; set; } 

    public string TargetName { get; set; } 

    public PropertyPath TargetProperty { get; set; } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     if (base.ProvideValue(serviceProvider) is Timeline animation) 
     { 
      //If the animation is shared we shall clone it 
      //Checking if it is frozen is optional and we can 
      //either clone it or throw an exception 
      //(or simply proceed knowing one will be thrown anyway) 
      if (IsShared || animation.IsFrozen) 
       animation = animation.Clone(); 
      Storyboard.SetTarget(animation, Target); 
      Storyboard.SetTargetName(animation, TargetName); 
      Storyboard.SetTargetProperty(animation, TargetProperty); 
      return animation; 
     } 
     else 
      throw new XamlException("The referenced resource is not an animation"); 
    } 
} 

प्रयोग बहुत सीधा है:

<FrameworkElement.Resources> 
    <DoubleAnimation x:Key="MyAnimation" From="0" To="1" Duration="0:0:1" /> 
</FrameworkElement.Resources> 
(...) 
<Storyboard> 
    <utils:AnimationResource ResourceKey="MyAnimation" TargetName="SomeElement" TargetProperty="Opacity" /> 
</Storyboard> 

के रूप में सरल होने के नाते के रूप में यह इस समाधान की अपनी सीमाएं हैं हो सकता है - यह ऊपर उल्लिखित संपत्तियों के लिए न Binding है और न ही DynamicResource एक्सटेंशन का समर्थन नहीं करता। हालांकि यह प्राप्त करने योग्य है, लेकिन कुछ अतिरिक्त प्रयास की आवश्यकता है। Binding समर्थन बहुत सरल होना चाहिए - XamlSetMarkupExtensionAttribute (साथ ही कुछ बॉयलरप्लेट कोड) के उचित उपयोग का प्रश्न। DynamicResource समर्थन थोड़ा ट्रिकियर होगा, और XamlSetMarkupExtensionAttribute का उपयोग करने के अतिरिक्त कार्यान्वयन को वापस करने के लिए IServiceProvider को लपेटने की आवश्यकता होगी, लेकिन अभी भी संभव है।

संबंधित मुद्दे