0

我正在尝试使用 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,我不会看到UI中的任何变化,直到我单击按钮来更改 viewmodel 属性。

我知道有几个与 DataState 相关的类,包括:

  • BindingListener.cs
  • 转换器助手.cs
  • 数据状态行为.cs
  • 数据状态开关行为.cs
  • 数据触发器.cs

任何线索都会很好,谢谢

4

3 回答 3

3

我实际上要添加我刚刚尝试过的第二个答案,并且似乎更干净,因为它可以在 XAML 中完成并且没有自定义行为。我将留下另一个答案作为替代解决方案的参考,因为它们都有效。

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

您只需添加对作为 Blend SDK 一部分的 Microsoft.Expression.Interactions 程序集的引用。

xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
于 2010-01-21T22:49:12.317 回答
2

试试这个 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));
        }
    }
}
于 2012-11-16T08:48:34.500 回答
1

我解决此问题的一种方法是创建一个可以添加到控件的行为,以便在加载时将其置于初始视觉状态。这是一个简单的例子:

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

然后,您只需将该行为添加到 XAML 中的 UserControl 级别:

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

您还可以轻松地对其进行修改以接受以逗号分隔的初始状态列表,然后如果您需要在加载后将控件置于一堆不同的互斥状态中,则可以拆分并循环遍历该列表。

这也可能被重构为一个 TriggerAction,您可以触发控件的 Loaded 事件,我不确定哪种方式会更干净。

于 2010-01-21T22:26:54.973 回答