1

我又有点难过,希望有人能帮忙。提前向长代码道歉。

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

触发 DataTrigger 的属性正在更新。

谢谢

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
    }
}

我的个人代码;

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()
    {
    }
}
4

1 回答 1

1

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

在每个动画完成后,动画将Canvas.LeftCanvas.Top依赖属性的值“保持”在其最终值。如果您获得依赖属性的值,则返回此“保留”值,它会覆盖通过数据绑定设置的任何值。当您开始第二个动画时,依赖属性的值是通过使用前一个动画的保持值来获得的。随着越来越多的动画发生,WPF 必须通过返回越来越多的动画链来确定矩形的位置。

我不能说为什么只有最后一个(NW)动画在你运行完所有动画后才运行。它很可能与依赖属性值优先级有关。此页面没有说明如果依赖属性上有多个动画会发生什么,但在这种情况下,我会假设在该属性上启动的最后一个动画优先。我怀疑DataTriggers 正在触发,但 WPF 依赖属性系统出于某种原因忽略了来自“覆盖”动画的值。

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

由于动画值优先于本地设置的值,因此在动画开始时设置属性值不是Left问题Top。在动画运行时,动画值Canvas.LeftCanvas.Top优先于通过数据绑定设置的任何值。随着动画结束,动画释放它对Canvas.LeftCanvas.Top依赖属性的持有,并且矩形的位置恢复为通过数据绑定获得。运气好的话,这个位置将与动画结束时相同。

于 2013-03-27T14:35:04.550 回答