Silverlight DataStateBehavior,未使用初始值
我尝试使用Silverlight DataStateBehavior,它在大多数情况下都可以正常工作,我单击一个按钮,将视图模型中的“Selected”属性设置为false或true。DataStateBehavior然后告诉VisualStateManager转到相关状态 像这样:Silverlight DataStateBehavior,未使用初始值,silverlight,triggers,behavior,vsm,Silverlight,Triggers,Behavior,Vsm,我尝试使用Silverlight DataStateBehavior,它在大多数情况下都可以正常工作,我单击一个按钮,将视图模型中的“Selected”属性设置为false或true。DataStateBehavior然后告诉VisualStateManager转到相关状态 像这样: <Button...> <i:Interaction.Behaviors> <id:DataStateBehavior Binding="{Bin
<Button...>
<i:Interaction.Behaviors>
<id:DataStateBehavior Binding="{Binding Selected}" Value="True" TrueState="SelectedVisualState" FalseState="DeselectedVisualState"/>
</i:Interaction.Behaviors>
</Button>
以上方法很好。不过,我要做的是让它在应用程序加载时设置正确的状态,如果我在默认情况下将视图模型上的“Selected”属性设置为true,则在单击按钮更改viewmodel属性之前,我不会在UI中看到任何更改
我知道有几个类涉及DataState内容,包括:
- BindingListener.cs
- ConverterHelper.cs
- DataStateBehavior.cs
- DataStateSwitchBehavior.cs
- DataTrigger.cs
谢谢我解决这个问题的一个方法是,在加载控件时,创建一个可以添加到控件中的行为,使其进入初始视觉状态。下面是一个简单的例子:
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);
}
}
公共类InitialVisualStateBehavior:行为
{
公共静态只读DependencyProperty InitialStateProperty=DependencyProperty.Register(
“初始状态”,
类型(字符串),
类型(初始行为),
无效);
公共字符串初始状态
{
get{return(string)GetValue(InitialStateProperty);}
set{SetValue(InitialStateProperty,value);}
}
受保护的覆盖无效附加()
{
base.onatached();
if(this.AssociatedObject!=null)
{
this.AssociatedObject.Loaded+=新路由EventHandler(AssociatedObject\u Loaded);
}
}
附加时受保护的覆盖无效()
{
base.OnDetaching();
if(this.AssociatedObject!=null)
{
this.AssociatedObject.Loaded-=AssociatedObject\u Loaded;
}
}
已加载关联对象的私有无效(对象发送方,路由目标)
{
VisualStateManager.goState(this.AssociatedObject,this.InitialState,false);
}
}
然后,只需将该行为添加到XAML中的UserControl级别:
<i:Interaction.Behaviors>
<myi:InitialVisualStateBehavior InitialState="SelectedVisualState" />
</i:Interaction.Behaviors>
您还可以轻松地修改它,以接受以逗号分隔的初始状态列表,如果需要在加载后将控件置于一组不同的互斥状态,则可以拆分并循环该列表
这也可能会被重构成一个触发动作,您可以直接触发控件的已加载事件,我不确定哪种方式会更干净。我解决这个问题的一种方法是,在加载时向控件添加一个行为,使其进入初始可视状态。下面是一个简单的例子:
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);
}
}
公共类InitialVisualStateBehavior:行为
{
公共静态只读DependencyProperty InitialStateProperty=DependencyProperty.Register(
“初始状态”,
类型(字符串),
类型(初始行为),
无效);
公共字符串初始状态
{
get{return(string)GetValue(InitialStateProperty);}
set{SetValue(InitialStateProperty,value);}
}
受保护的覆盖无效附加()
{
base.onatached();
if(this.AssociatedObject!=null)
{
this.AssociatedObject.Loaded+=新路由EventHandler(AssociatedObject\u Loaded);
}
}
附加时受保护的覆盖无效()
{
base.OnDetaching();
if(this.AssociatedObject!=null)
{
this.AssociatedObject.Loaded-=AssociatedObject\u Loaded;
}
}
已加载关联对象的私有无效(对象发送方,路由目标)
{
VisualStateManager.goState(this.AssociatedObject,this.InitialState,false);
}
}
然后,只需将该行为添加到XAML中的UserControl级别:
<i:Interaction.Behaviors>
<myi:InitialVisualStateBehavior InitialState="SelectedVisualState" />
</i:Interaction.Behaviors>
您还可以轻松地修改它,以接受以逗号分隔的初始状态列表,如果需要在加载后将控件置于一组不同的互斥状态,则可以拆分并循环该列表
这也可能被重构成一个触发器操作,您可以直接触发控件的已加载事件,我不确定哪种方式更干净。我实际上要添加第二个答案,我刚刚尝试过,看起来更干净,因为它可以全部在XAML中完成,而无需自定义行为。我将留下另一个答案作为替代解决方案的参考,因为它们都有效
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<ic:GoToStateAction StateName="SelectedVisualState"/>
</i:EventTrigger>
</i:Interaction.Triggers>
实际上,我将添加第二个答案,我刚刚尝试过,而且看起来更简洁,因为它可以在XAML中完成,而无需自定义行为。我将留下另一个答案作为替代解决方案的参考,因为它们都有效
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<ic:GoToStateAction StateName="SelectedVisualState"/>
</i:EventTrigger>
</i:Interaction.Triggers>
尝试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));
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Windows;
名称空间Gusdor.Wpf
{
///
///修复数据状态行为。当目标元素加载时,该行为将触发转换。
///
类DataStateBehaviorFix:Microsoft.Expression.Interactivity.Core.DataStateBehavior
{
public bool UseTransitionsOnLoad{get;set;}
受保护的覆盖无效附加()
{
base.onatached();
AssociatedObject.Loaded+=AssociatedObject\u Loaded;
}
附加时受保护的覆盖无效()
{
base.OnDetaching();
AssociatedObject.Loaded-=AssociatedObject\u Loaded;
}
已加载无效关联对象(对象发送方,System.Windows.RoutedEventArgs e)
{
评估();
}
void Evaluate()