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