Silverlight DataStateBehavior, начальное значение не используется - PullRequest
0 голосов
/ 21 января 2010

Я пытаюсь использовать Silverlight DataStateBehavior, он отлично работает в большинстве случаев, когда я нажимаю кнопку, которая устанавливает для свойства «Выбранное» в модели представления значение false или true. Затем DataStateBehavior сообщает VisualStateManager перейти в соответствующее состояние.

Как это:

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

Выше работает нормально. Однако я пытаюсь заставить его установить правильное состояние при загрузке приложения. Если бы я установил свойство Selected в модели представления по умолчанию на true, я бы не увидел никаких изменений в пользовательском интерфейсе, пока Я нажал кнопку, чтобы изменить свойство viewmodel.

Я знаю, что с DataState связано несколько классов, включая:

  • BindingListener.cs
  • ConverterHelper.cs
  • DataStateBehavior.cs
  • DataStateSwitchBehavior.cs
  • DataTrigger.cs

Любые подсказки были бы хороши, Спасибо

Ответы [ 3 ]

3 голосов
/ 22 января 2010

На самом деле я собираюсь добавить второй ответ, который я только что попробовал, и, кажется, он чище, поскольку все это можно сделать в XAML и без специального поведения. Я оставлю другой ответ просто как ссылку на альтернативное решение, так как они оба работают.

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

Вам просто нужно добавить ссылку на сборку Microsoft.Expression.Interactions, которая является частью Blend SDK.

xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
2 голосов
/ 16 ноября 2012

Попробуйте это расширение класса 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));
        }
    }
}
1 голос
/ 22 января 2010

Одним из способов решения этой проблемы является создание поведения, которое вы можете добавить к своему элементу управления, чтобы при загрузке перевести его в исходное визуальное состояние. Вот простой пример:

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>

Вы также можете легко изменить это, чтобы принимать разделенный запятыми список начальных состояний, которые вы могли бы затем разделить и перебрать, если вам нужно было поместить элемент управления в кучу различных взаимоисключающих состояний после загрузки.

Это также может быть преобразовано в действие TriggerAction, которое можно просто вызвать из события Loaded элемента управления, я не уверен, какой путь будет более чистым.

...