EventTrigger有时无法触发 [英] EventTrigger sometimes fails to fire

查看:147
本文介绍了EventTrigger有时无法触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我再次感到困惑,希望有人可以帮忙. 提前对长代码表示歉意.

I'm yet again a bit stumped, and was hoping someone could please help. Apologies in advance to the long code.

问题-我有一个DataTrigger,它按预期启动,但最终失败了,我不知道为什么.在提供的示例中,它在画布"周围移动了一个矩形.每次单击按钮都会按此顺序移动它. N,NE,E,SE,S,SW,W,NW.然后,它从N开始再次开始该序列.一旦第一个序列完成,它就不会向北移动.它只会再次向西北移动(即最后一次成功移动).

Issue - I have a DataTrigger that starts off firing as expected, but it eventually fails and I can't work out why. In the example provided, it moves a rectangle around a Canvas. Each click of the button moves it in this sequence; N, NE, E, SE, S, SW, W, NW. Then it starts the sequence again, starting with N. Once the first sequence is completed, it won't move North. It will only ever move NW again (ie the last successful move).

触发DataTrigger的属性正在更新.

The property that triggers the DataTrigger is updating.

谢谢

XAML;

<Window.Resources>
    <Style x:Key="TestRectStyle" TargetType="{x:Type Rectangle}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding UI_DirectionOfMovement}" Value="North">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" By="-50" Duration="0:0:0.8" AutoReverse="False" />
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" By="0" Duration="0:0:0.8" AutoReverse="False" />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding UI_DirectionOfMovement}" Value="NorthEast">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" By="-50" Duration="0:0:0.8" AutoReverse="False" />
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" By="50" Duration="0:0:0.8" AutoReverse="False" />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding UI_DirectionOfMovement}" Value="East">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" By="0" Duration="0:0:0.8" AutoReverse="False" />
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" By="50" Duration="0:0:0.8" AutoReverse="False" />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding UI_DirectionOfMovement}" Value="SouthEast">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" By="50" Duration="0:0:0.8" AutoReverse="False" />
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" By="50" Duration="0:0:0.8" AutoReverse="False" />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding UI_DirectionOfMovement}" Value="South">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" By="50" Duration="0:0:0.8" AutoReverse="False" />
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" By="0" Duration="0:0:0.8" AutoReverse="False" />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding UI_DirectionOfMovement}" Value="SouthWest">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" By="50" Duration="0:0:0.8" AutoReverse="False" />
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" By="-50" Duration="0:0:0.8" AutoReverse="False" />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding UI_DirectionOfMovement}" Value="West">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" By="0" Duration="0:0:0.8" AutoReverse="False" />
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" By="-50" Duration="0:0:0.8" AutoReverse="False" />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
            <DataTrigger Binding="{Binding UI_DirectionOfMovement}" Value="NorthWest">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Top)" By="-50" Duration="0:0:0.8" AutoReverse="False" />
                            <DoubleAnimation Storyboard.TargetProperty="(Canvas.Left)" By="-50" Duration="0:0:0.8" AutoReverse="False" />
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
        </Style.Triggers>
    </Style>

    <DataTemplate x:Key="TestDataTemplate01" DataType="BO:MyPerson">
        <Canvas Width="1000" Height="1000" Background="Transparent">
            <Rectangle Width="50" Height="50" Fill="Red" Style="{StaticResource TestRectStyle}" Canvas.Top="300" Canvas.Left="300" />
        </Canvas>
    </DataTemplate>
</Window.Resources>

<Canvas Width="1000" Height="1000">
    <ItemsControl Name="ic_People" ItemTemplate="{StaticResource TestDataTemplate01}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Width="1000" Height="1000" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

    <Button Canvas.Right="0" Click="Button_Click_1" Width="120">Next Move</Button>
</Canvas>

隐藏代码;

public partial class Window1 : Window
{
    private ObservableCollection<MyPerson> _personList = new ObservableCollection<MyPerson>();

    public Window1()
    {
        InitializeComponent();

        MyPerson person1 = new MyPerson();
        _personList.Add(person1);
        ic_People.ItemsSource = _personList;
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        DoNextMove();
    }

    private int debugDirection = 0;
    private void DoNextMove()
    {
        if (debugDirection > 15)
            debugDirection = 0;

        _personList[0].MoveOneTile(debugDirection);
        debugDirection += 2; // increase by 2 to as I've not implemented the odd numbers yet
    }
}

MyPerson代码;

MyPerson code;

public class MyPerson : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }

    private string _dirMov = "";
    public string UI_DirectionOfMovement
    {
        get { return _dirMov; }
        set
        {
            _dirMov = value;
            OnPropertyChanged("UI_DirectionOfMovement");
        }
    }

    public void MoveOneTile(int directionToMove)
    {
        this.UI_DirectionOfMovement = "clear"; // clearing it first forces an update

        switch (directionToMove)
        {
            case 0: { this.UI_DirectionOfMovement = "North"; break; }
            case 2: { this.UI_DirectionOfMovement = "NorthEast"; break; }
            case 4: { this.UI_DirectionOfMovement = "East"; break; }
            case 6: { this.UI_DirectionOfMovement = "SouthEast"; break; }
            case 8: { this.UI_DirectionOfMovement = "South"; break; }
            case 10: { this.UI_DirectionOfMovement = "SouthWest"; break; }
            case 12: { this.UI_DirectionOfMovement = "West"; break; }
            case 14: { this.UI_DirectionOfMovement = "NorthWest"; break; }
            default: { throw new Exception(); }
        }
    }

    public MyPerson()
    {
    }
}

推荐答案

这里的问题最终归结为以下事实:动画实际上并未更改Canvas.LeftCanvas.Top属性的值.它们似乎只是这样做,因为从动画获得的值会覆盖通过数据绑定获得的值.

The problem here ultimately comes down to the fact that animations don't actually change the values of the Canvas.Left and Canvas.Top properties. They only appear to do so, as values obtained from animation override values obtained via data binding.

每个动画完成后,动画将Canvas.LeftCanvas.Top依赖项属性的值保持"为其最终值.如果您获得了依赖项属性的值,则将返回此保留"值,并且该值将覆盖通过数据绑定设置的任何值.当您开始第二个动画时,依赖项属性的值是通过从上一个动画的保留值开始工作而获得的.随着越来越多的动画发生,WPF必须通过返回一系列越来越多的动画来确定矩形的位置.

After each animation finishes, the animation 'holds' the value of the Canvas.Left or Canvas.Top dependency properties at its final value. This 'held' value is what is returned if you get the value of the dependency property, and it overrides any value set via data binding. As you start a second animation, the dependency property's value is obtained by working from the previous animation's held value. As more and more animations happen, WPF has to determine the location of the rectangle by going back through a chain of more and more animations.

我不能说为什么在运行完所有动画后只运行最后一个(NW)动画.它很可能与依赖性属性值优先级有关.该页面没有说明如果在依赖项属性上有多个动画会发生什么,但是在这种情况下,我将假定从该属性开始的最后一个动画优先.我怀疑DataTrigger正在触发,但是由于某些原因,WPF依赖属性系统忽略了来自覆盖"动画的值.

I can't say why only the last (NW) animation runs after you've been run all of them. It quite probably has something to do with dependency property value precedence. This page doesn't say what happens if there are multiple animations on a dependency property, but in this situation I would assume that the last animation to start on that property takes precedence. I suspect that the DataTriggers are firing, but the WPF dependency property system for some reason is ignoring values coming from the 'overridden' animations.

我建议避免使用像这样的动画链.而是,更改您的Person对象以跟踪它们在画布上的位置,例如,通过添加LeftTop属性.然后,您可以将Canvas.LeftCanvas.Top绑定到这些属性.您的DoNextMove方法还应该将这些属性的值设置为动画将它们移动到的位置.更改UI_DirectionOfMovement属性的值后,执行此操作.最后,通过在每个DoubleAnimation上设置FillBehavior="Stop"来停止动画保留"最终值.

I would recommend avoiding having a chain of animations like this. Instead, change your Person objects to keep track of where they are on the canvas, for example, by adding Left and Top properties. You can then bind Canvas.Left and Canvas.Top to these properties. Your DoNextMove method should also set the values of these properties to where the animation moves them to. Do this after changing the value of theUI_DirectionOfMovement property. Finally, stop your animations from 'holding' their final values by setting FillBehavior="Stop" on each DoubleAnimation.

由于动画值优先于本地设置的值,因此在动画开始时设置LeftTop的属性值不是问题.动画运行时,Canvas.LeftCanvas.Top的动画值优先于通过数据绑定设置的任何值.动画结束时,动画释放对Canvas.LeftCanvas.Top依赖项属性的保留,并且矩形的位置恢复为通过数据绑定获得的位置.运气好的话,该位置将与动画结尾处的位置相同.

As animated values take precedence over locally-set values, it's not a problem to set the property values for Left and Top at the start of the animation. While the animation is running, the animated values for Canvas.Left and Canvas.Top take precedence over any value set via data binding. As the animation finishes, the animation releases its hold over the Canvas.Left and Canvas.Top dependency properties, and the location of the rectangle reverts to being obtained via data binding. With any luck, this location will be the same as at the end of the animation.

这篇关于EventTrigger有时无法触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆