我想知道我可以用 XAML 做什么,使用正确的 VisualState 初始化我的 UI 元素。不是后面的代码。因为我知道如何使用 C# 代码来做到这一点。
我的 UI 元素的 XAML 在某种程度上是这样的:
<Border x:Name="PART_Border" >
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CriticalnessStates">
<VisualState x:Name="NonCritical"/>
<VisualState x:Name="Critical"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<i:Interaction.Triggers>
<ei:DataTrigger Binding="{Binding IsCritical}" Value="False">
<ei:GoToStateAction StateName="NonCritical"/>
</ei:DataTrigger>
<ei:DataTrigger Binding="{Binding IsCritical}" Value="True">
<ei:GoToStateAction StateName="Critical"/>
</ei:DataTrigger>
</i:Interaction.Triggers>
</Border>
在加载 UI 元素后设置IsCritical属性时,它可以完美运行,但问题是,我需要该元素以正确的VisualState 加载;我的意思是
关键 = 真 => 处于临界状态的元素加载关键 = 假 => 处于非临界状态
的元素加载
通过 C# 代码隐藏文件是可行的,您可以为元素编写加载的事件处理程序,该处理程序通过检查相应的 DataContext 属性来设置可视状态。我想知道如何使用纯 XAML 完成此操作。
顺便说一下,ei和我指向这些 XML 命名空间:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions">
谢谢。
我实现了这个行为类:
using System;
using System.Windows;
using System.Collections.Generic;
using System.Windows.Interactivity;
using System.Windows.Markup;
[ContentProperty("Conditions")]
public class VisualStateInitializer : Behavior<FrameworkElement>
{
private bool _useTransitions = true;
public bool UseTransitions
{
get { return _useTransitions; }
set { _useTransitions = value; }
}
public List<VisualStateCondition> Conditions { get; set; }
public VisualStateInitializer()
{
Conditions = new List<VisualStateCondition>();
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += AssociatedObject_Loaded;
}
protected override void OnDetaching()
{
base.OnDetaching();
}
private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
{
if (AssociatedObject.DataContext == null)
return;
foreach (var item in Conditions)
{
var dataContextType = AssociatedObject.DataContext.GetType();
System.Reflection.PropertyInfo propertyInfo;
object value = null;
var properties = item.PropertyName.Split('.');
if (properties.Length > 1)
{
for (int i = 0; i < properties.Length; i++)
{
if(value != null)
{
dataContextType = value.GetType();
propertyInfo = dataContextType.GetProperty(properties[i]);
value = propertyInfo.GetValue(value);
}
else
{
propertyInfo = dataContextType.GetProperty(properties[i]);
value = propertyInfo.GetValue(AssociatedObject.DataContext);
}
}
}
else
{
value = AssociatedObject.DataContext.GetType().GetProperty(item.PropertyName).GetValue(AssociatedObject.DataContext);
}
if (value != null && value.Equals(item.Value))
VisualStateManager.GoToElementState(AssociatedObject, item.DesiredState, UseTransitions);
}
}
}
VisualStateCondition类是这样的:
public class VisualStateCondition
{
/// <summary>
/// The PropertyName to look for in the associated object's <see cref="FrameworkElement.DataContext"/>.
/// </summary>
public string PropertyName { get; set; }
/// <summary>
/// The Value to check for equality.
/// </summary>
public object Value { get; set; }
/// <summary>
/// The <see cref="VisualState.Name"/> that is desired for the condition.
/// </summary>
public string DesiredState { get; set; }
}
在正确的初始状态下初始化我的 View 类所需要的只是定义VisualStateConditions,如下所示:
注意 =>xaml 中的 "i" 命名空间是指 BlendSdk 的 "System.Windows.Interactivity" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
<Border>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CriticalnessStates">
<VisualState x:Name="NonCritical"/>
<VisualState x:Name="Critical"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<i:Interaction.Behaviors>
<viewHelpers:VisualStateInitializer>
<viewHelpers:VisualStateCondition PropertyName="IsCritical" DesiredState="Critical">
<viewHelpers:VisualStateCondition.Value>
<system:Boolean>
True
</system:Boolean>
</viewHelpers:VisualStateCondition.Value>
</viewHelpers:VisualStateCondition>
<viewHelpers:VisualStateCondition PropertyName="IsCritical" DesiredState="NonCritical">
<viewHelpers:VisualStateCondition.Value>
<system:Boolean>
False
</system:Boolean>
</viewHelpers:VisualStateCondition.Value>
</viewHelpers:VisualStateCondition>
</viewHelpers:VisualStateInitializer>
</i:Interaction.Behaviors>
</border>
其中 ViewHelpers 是我的 VisualStateInitializer 和 VisualStateCondition 类的命名空间。 谁能提出更好的方法?
更新 1 =>编辑属性值检索,以便我们可以传递嵌套属性,例如:
<viewHelpers:VisualStateCondition PropertyName="X.Y.NestedProperty"
Value="False"
DesiredState="StateForNestedProperty"/>
IsCritical
是一个源属性,应该在视图模型或控件本身中以编程方式实现和设置。因此,应在视图模型中或任何实现属性的位置设置默认值。
Style
或DataTrigger
无法设置视图模型属性的值。
此外,控件的实现应该定义它所处的视觉状态。通过在控件类中以编程方式调用VisualStateManager.GoToState
来执行此操作。