繁体   English   中英

如何通过XAML,WPF中的数据绑定设置VisualState初始化

[英]How to set VisualState INITIALIZATION via data binding in XAML, WPF

我想知道如何使用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; 我的意思是,

IsCritical = true =>处于临界状态的元素加载
IsCritical = false =>处于非关键状态的元素加载

通过文件后面的C#代码是可行的,您可以为元素编写一个加载的事件处理程序,该处理程序通过检查相应的DataContext属性来设置可视状态。 我想知道如何使用纯XAML做到这一点。

顺便说一下, eii指向这些XML名称空间:

xmlns:ei =“ http://schemas.microsoft.com/expression/2010/interactivity” xmlns:ei =“ http://schemas.microsoft.com/expression/2010/interactions”

谢谢。

我实现了这个Behavior类:

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 xmlns的“ System.Windows.Interactivity”: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类的名称空间。 谁能建议一个更好的方法?

UPDATE 1 =>编辑属性值检索,以便我们可以传递嵌套属性,例如:

<viewHelpers:VisualStateCondition PropertyName="X.Y.NestedProperty"
    Value="False"
    DesiredState="StateForNestedProperty"/>

IsCritical是一种源属性,应该在视图模型或控件本身中通过编程方式实现和设置。 因此,应在视图模型中或在实现属性的任何位置设置默认值。

StyleDataTrigger无法设置视图模型属性的值。

另外,应该是控件的实现,该控件应定义控件所在的视觉状态。您可以通过在控件类中以编程方式调用VisualStateManager.GoToState实现此目的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM