تحديد الرسوم المتحركة والمشغلات كمورد قابلة لإعادة الاستخدام؟

StackOverflow https://stackoverflow.com/questions/1654355

سؤال

هل هناك طريقة لتحديد الرسوم المتحركة في مكان ما في XAML (على سبيل المثال. كموارد) مرة واحدة ثم إعادة استخدامها عدة مرات؟ لدي الكثير من الفرش المستقل عبر Different DataTemplates التي تحتاجها بشكل مستقل لبدء نفس النوع من الرسوم المتحركة بناء على DataTrigger. الآن لأنه يبدو أن الرسوم المتحركة يجب أن تحدد لوحة القصة المصورة. هذا يهزم الكثير من الغرض من إعادة الاستخدام. أود بطريقة أو بأخرى أن أعلن "استخدام هذه الرسوم المتحركة شكل المورد ولكن تطبيقه على عنصر آخر هذه المرة".

بالنسبة لي، يبدو أن هذا طلب أساسي ومهما وأساسيا وانا مفاجئا أنه ليس على التوالي إلى الأمام لإغراء. نسيت شيئا ما هنا؟

نفس الشيء ينطبق على المشغلات. لنفترض أن لدي الكثير من العناصر المرئية المختلفة التي تمثلها جميعها نفس النوع من الحالة باستخدام الرسوم المتحركة الملونة. على سبيل المثال، تتلاشى إلى اللون الأخضر عندما تتلاشى "نشط" إلى "الأحمر" عند "الخطأ" وما إلى ذلك. الفرق الوحيد بين المرئيات هو شكله / شجرة البصرية هو نفسه هو نفسه، لديهم جميعا عنصر في مكان ما في شجرة البصرية لديه خاصية من النوع من النوع. أعتقد أنه ليس من الصعب تخيل مدى ذكاءه لإعادة تعريف نفس الرسوم المتحركة ومجموعات datatrigger مرارا وتكرارا. كل مطور يكره هذا. بحثا عن حلا أسهل لا يتطلب أي رمز (أو على الأقل قليلا جدا) C # خلف.

ما الذي وصلت إليه حتى الآن هو:

حدد الرسوم المتحركة في مورد يحب هذا (كرر هذا لجميع الدول الأساسية التي يوجد بها، مثل التنشيط والنشطة وغير النشطة والخطأ):

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

استخدامه في لوحة العمل في المشغلات (كرر Zillions من المرات بالنسبة لكل ولاية X كلف، يأتي دائما مع اسم جديد لوحدة القصة):

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

يمكنك بسهولة تخيل مدى تفكيك XAML الذي يجب أن نسخه ومرارا وتكرارا لجميع هؤلاء zillion datatriggers.

سيكون من الرائع تحديد كل هذا المشغلات مرة واحدة وتطبيقه على مرئيات الحالة المختلفة. كيف شيء مثل هذا حل في WPF؟ أي نصيحة؟

هل كانت مفيدة؟

المحلول 2

لا يبدو أن هناك أي حل جيد xaml فقط لهذه المشكلة العامة. انتهى بي الأمر بكتابة خصائص الخاصة بي التي تحدد جميع سلوكيات الرسوم المتحركة لعنصر معين. شيء من هذا القبيل:

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

تتم بقية (إنشاء الرسوم المتحركة وما إلى ذلك) في CodeBehind.

نصائح أخرى

هل يمكن أن تجرب شيئا مثل هذا؟

  • لف جميع قوالب التحكم الحالية الخاصة بك بعنصر جذر غير مرئي، مثل حدود أو StackPanel، يقوم صندوق التحديد بتغطية التحكم بالكامل.
  • قم بإنشاء نمط أو قالب مراقبة لهذا المربع غير المرئي الذي يحتوي على جميع المشغلات والرسوم المتحركة.
  • لديك الرسوم المتحركة تحريك خاصية ملونة تعسفية على المربع غير المرئي.
  • في الأشجار المرئية لجميع عناصر التحكم المختلفة، قم بربط أي خصائص تريد تحريكها على خاصية الألوان على عنصر الجذر غير المرئي.

أدرك أن هذه المشكلة ميتة قليلا في وقت النشر، لكنني وجدت حلا يتطلب رمز قليل جدا وراءه.

يمكنك صنع Usercontrol مع خصائص مخصصة(قم بالتمرير لأسفل إلى حوالي الشكل 8) يحتوي على المستطيل الخاص بك وكذلك الرسوم المتحركة ومشغلات الحالة. سيحدد عنصر تحكم المستخدم هذا خاصية عامة مثل الحالة التي من شأنها أن تؤدي إلى تغيير اللون عند تغييرها.

الكود الوحيد وراء المطلوب هو إنشاء المتغيرات الخاصة بك في التعليمات البرمجية.

يمكن إعادة استخدام عنصر تحكم المستخدم مرارا وتكرارا دون إعادة كتابة ألواح Store أو مشغلات البيانات XAML.

أكثر "XAML. طريقة "لتحقيق هذا الهدف الذي يمكنني التفكير فيه هو إنشاء مخصص MarkupExtension والتي من شأنها سحب الرسوم المتحركة من قاموس الموارد وتعيين الخصائص الضرورية - أفترض أن تلك تقتصر على مجموعة فرعية من Storyboard.Target, Storyboard.TargetName و Storyboard.TargetProperty. وبعد على الرغم من أنه يتطلب بعض الكود وراء، إلا أنه جهد لمرة واحدة، علاوة على ذلك MarkupExtensionS مصممة لاستخدامها مع 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 لإعادة كافية IProvideValueTarget التنفيذ، ولكن لا يزال ممكنا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top