<Window x:Class="SRQC_触发器实现自动回退.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
          xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
         Title="MainWindow" Height="350" Width="525">
     <StackPanel>
         <TextBox Text="" x:Name="input"/>
         <Button x:Name="btn1">
             <Button.Style>
                 <Style TargetType="Button">
                     <Style.Triggers>
                         <DataTrigger Binding="{Binding Text,ElementName=input,UpdateSourceTrigger=PropertyChanged}" Value="1">
                             <Setter Property="Content" Value="我是Style修改的"></Setter>
                         </DataTrigger>
                     </Style.Triggers>
                 </Style>
             </Button.Style>
         </Button>
         <Button x:Name="btn2">
             <i:Interaction.Triggers>
                 <ei:DataTrigger Binding="{Binding Text,ElementName=input,UpdateSourceTrigger=PropertyChanged}" Value="1">
                     <ei:ChangePropertyAction PropertyName="Content" Value="我是Interaction修改的"/>
                 </ei:DataTrigger>
             </i:Interaction.Triggers>
         </Button>
     </StackPanel>
 </Window> 上面
一个是用Style.DataTrigger的
一个是用Interaction.Triggers的
当Text输入1的时候,两个触发器都能得到响应对Button.Content进行修改
然后当Text不为1的时候Style.DataTrigger能自动回退,但Interaction.Triggers不能自动回退这两个触发器内部有什么本质的区别?
如何让Interaction.Triggers也实现自动回退功能(最好是有一个开关来设置)万分感谢

解决方案 »

  1.   

    我帮你搜了一下没有找到,应该是没有,不过可以自己对Expression.Interactivity进行扩展
      

  2.   

    帮你做了个例子:using System;
    using System.Windows;
    using System.Linq;namespace WpfApp1
    {
    public partial class MainWindow : Window
    {
    public MainWindow()
    {
    InitializeComponent();
    }
    } public class DataTrigger : Microsoft.Expression.Interactivity.Core.DataTrigger
    {
    public bool AutoRevert { get; set; } private bool _triggered;
    private bool _reverting; // prevent possible recursive triggering
    protected override void EvaluateBindingChange(object args)
    {
    bool invoked = false;
    PreviewInvoke += (o, eventArgs) => invoked = true;
    base.EvaluateBindingChange(args); // if binding data is changed and actions are not invoked, which means the conditions are not satisfied, then try revert back the orgianal values
    if (_triggered && !invoked && AutoRevert && !_reverting)
    {
    _reverting = true;
    foreach (var action in Actions.OfType<ChangePropertyAction>())
    action.RevertOriginalValue();
    _reverting = false;
    }
    _triggered = (!_triggered || invoked) && (invoked || _triggered);
    }
    } public class ChangePropertyAction : Microsoft.Expression.Interactivity.Core.ChangePropertyAction
    {
    private object _orginalValue;
    private bool _valueSaved; protected override void Invoke(object parameter)
    {
    // save orginal value before change it
    if (!_valueSaved && Target != null && !string.IsNullOrEmpty(PropertyName))
    {
    _orginalValue = Target.GetType().GetProperty(PropertyName).GetValue(Target);
    _valueSaved = true;
    }
    base.Invoke(parameter);
    } public void RevertOriginalValue()
    {
    try
    {
    if (_valueSaved && Target != null && !string.IsNullOrEmpty(PropertyName))
    Target.GetType().GetProperty(PropertyName).SetValue(Target, _orginalValue);
    _valueSaved = false;
    }
    catch (Exception ex)
    {
    throw new InvalidOperationException(
    "can not revert back to original value, may be target or property name changed after changing the original property", ex);
    }
    }
    }
    }前台用法:<Window x:Class="WpfApp1.MainWindow"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
            xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
            xmlns:local="clr-namespace:WpfApp1"
            Title="MainWindow" Height="350" Width="525">
        <StackPanel>
            <TextBox Text="" x:Name="input"/>
            <Button x:Name="btn1">
                <Button.Style>
                    <Style TargetType="Button">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Text,ElementName=input,UpdateSourceTrigger=PropertyChanged}" Value="1">
                                <Setter Property="Content" Value="我是Style修改的"></Setter>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Button.Style>
            </Button>
            <Button x:Name="btn2">
                <i:Interaction.Triggers>
                    <ei:DataTrigger Binding="{Binding Text,ElementName=input,UpdateSourceTrigger=PropertyChanged}" Value="1">
                        <ei:ChangePropertyAction PropertyName="Content" Value="我是Interaction修改的"/>
                    </ei:DataTrigger>
                </i:Interaction.Triggers>
            </Button>
            <Button x:Name="btn3">
                <i:Interaction.Triggers>
                    <local:DataTrigger Binding="{Binding Text,ElementName=input,UpdateSourceTrigger=PropertyChanged}" Value="1" AutoRevert="True">
                        <local:ChangePropertyAction PropertyName="Content" Value="我是Custom Interaction修改的"/>
                    </local:DataTrigger>
                </i:Interaction.Triggers>
            </Button>
        </StackPanel>
    </Window>
      

  3.   

    用法说明:
    现在只改造了DataTrigger,只有这个触发器可以实现初始值恢复的功能。
    用的时候把DataTriger换成local:DataTrigger(或你的namespace),并且把它下面的ChangePropertyAction换成local:ChangePropertyAction。目前只实现了ChangePropertyAction的状态恢复功能。
    DataTrigger.AutoRevert是开关,false的时候就跟正常的是一样的。话说回来,如果按照一般性的做法和普通思路,是不需要用到自己去写这些扩展的(这些话你都听腻了吧,呵呵)。
    标准库里的trigger足够处理各种情况,配合一个好的view model的话。还可以用VisualState,这个也是专用于管理UI的各种状态的。