Silverlight DatastateBehavior ، القيمة الأولية غير المستخدمة

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

سؤال

أحاول استخدام DataStateBehavior Silverlight ، فهو يعمل بشكل جيد في معظم الحالات التي أنقر عليها زرًا يطلق على خاصية "محددة" في نموذج العرض إما كاذبة أو صحيحة. ثم يخبر DatastateBehavior VisualStatemanager الذهاب إلى الدولة ذات الصلة.

مثله:

   <Button...>
   <i:Interaction.Behaviors>
             <id:DataStateBehavior Binding="{Binding Selected}" Value="True" TrueState="SelectedVisualState" FalseState="DeselectedVisualState"/>
          </i:Interaction.Behaviors>
   </Button>

ما سبق يعمل بشكل جيد. ما أحاول القيام به رغم ذلك هو جعلها تعيين الحالة الصحيحة عند تحميل التطبيق ، إذا كنت سأقوم بتعيين خاصية "محددة" على نموذج العرض إلى True بشكل افتراضي ، فلن أرى أي تغييرات في واجهة المستخدم حتى قمت بالنقر فوق الزر لتغيير خاصية ViewModel.

أعلم أن هناك العديد من الفصول المتورطة في أشياء DataState بما في ذلك:

  • bindinglistener.cs
  • enterterhelper.cs
  • datastatebehavior.cs
  • DataStateswitchbehavior.cs
  • datatrigger.cs

أي أدلة ستكون جيدة ، شكرا

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

المحلول

سأضيف في الواقع إجابة ثانية جربتها للتو ، ويبدو أنها أكثر نظافة حيث يمكن القيام بها في XAML وبدون سلوك مخصص. سأترك الإجابة الأخرى تمامًا كمرجع لحل بديل لأن كلاهما يعملان.

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Loaded">
        <ic:GoToStateAction StateName="SelectedVisualState"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

ستحتاج فقط عند إضافة مرجع إلى Microsoft.expression.Interctions Assembly الذي يعد جزءًا من SDK المزيج.

xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"

نصائح أخرى

جرب هذا الامتداد لفئة DatastateBehavior. عندما يتم تحميل العنصر المستهدف ، سيتم تقييم DataStateBehavior كما لو أن الخاصية قد تم تحديثها.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;

namespace Gusdor.Wpf
{
    /// <summary>
    /// Fix for data state behavior. Behavior will trigger transitions when target element loads.
    /// </summary>
    class DataStateBehaviorFix: Microsoft.Expression.Interactivity.Core.DataStateBehavior
    {
        public bool UseTransitionsOnLoad { get; set; }

        protected override void OnAttached()
        {
            base.OnAttached();

            AssociatedObject.Loaded += AssociatedObject_Loaded;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();

            AssociatedObject.Loaded -= AssociatedObject_Loaded;
        }

        void AssociatedObject_Loaded(object sender, System.Windows.RoutedEventArgs e)
        {
            Evaluate();
        }

        void Evaluate()
        {
            if (Value == null)
            {
                GotoState(Binding == null, this.AssociatedObject);
            }
            else GotoState(Value.Equals(Binding), this.AssociatedObject);
        }

        /// <summary>
        /// Attempts to change to the named state. Walks up tree to first match.
        /// </summary>
        /// <param name="flag"></param>
        /// <param name="element"></param>
        void GotoState(bool flag, FrameworkElement element)
        {          
            string stateName = flag ? TrueState : FalseState;

            if (HasState(element, stateName))
            {
                bool ret = System.Windows.VisualStateManager.GoToElementState(element, stateName, UseTransitionsOnLoad);
            }
            else if (element.Parent as FrameworkElement != null)
                GotoState(flag, element.Parent as FrameworkElement);
        }
        /// <summary>
        /// Checks if an element has the state named
        /// </summary>
        /// <param name="element"></param>
        /// <param name="stateName"></param>
        /// <returns></returns>
        bool HasState(FrameworkElement element, string stateName)
        {
            var groups = Microsoft.Expression.Interactivity.VisualStateUtilities.GetVisualStateGroups(element).Cast<VisualStateGroup>();

            return groups.Any(p => p.States.Cast<VisualState>().Any(s => s.Name == stateName));
        }
    }
}

إحدى الطرق التي قمت بحل هذه المشكلة هي جعل سلوكًا يمكنك إضافته إلى سيطرتك لوضعه في حالة بصرية أولية عند التحميل. اليك مثال بسيط:

public class InitialVisualStateBehavior : Behavior<Control>
{
    public static readonly DependencyProperty InitialStateProperty = DependencyProperty.Register(
        "InitialState",
        typeof(string),
        typeof(InitialVisualStateBehavior),
        null);

    public string InitialState
    {
        get { return (string)GetValue(InitialStateProperty); }
        set { SetValue(InitialStateProperty, value); }
    }

    protected override void OnAttached()
    {
        base.OnAttached();

        if (this.AssociatedObject != null)
        {
            this.AssociatedObject.Loaded += new RoutedEventHandler(AssociatedObject_Loaded);
        }
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();

        if (this.AssociatedObject != null)
        {
            this.AssociatedObject.Loaded -= AssociatedObject_Loaded;
        }
    }

    private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        VisualStateManager.GoToState(this.AssociatedObject, this.InitialState, false);
    }
}

يمكنك بعد ذلك فقط إضافة هذا السلوك إلى مستوى USERCONTROL في XAML:

<i:Interaction.Behaviors>
    <myi:InitialVisualStateBehavior InitialState="SelectedVisualState" />
</i:Interaction.Behaviors>

يمكنك أيضًا تعديل هذا بسهولة لقبول قائمة مفصولة بفاصلة من الحالات الأولية التي يمكنك بعد ذلك تقسيمها والتحلق إذا كنت بحاجة إلى وضع السيطرة في مجموعة من الحالات الحصرية المختلفة بعد التحميل.

قد يتم أيضًا إعادة تمثيل هذا في عملية تحريك يمكن أن تنطلق من الحدث المحمّل للتحكم ، لست متأكدًا من الطريقة التي ستكون أكثر نظافة.

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