Анимация LayoutTransform на ScaleX и ScaleY нарушает связывание с ними
У меня есть собственный класс, скажем, "MyCanvas", полученный из класса wpf Canvas. MyCanvas имеет свойство зависимости "Масштаб", которое задает преобразование масштаба для холста. Теперь, когда значение Scale изменяется, я хочу анимировать преобразование из старого значения в новое. для этого я использую LayoutTransform.BeginAnimation(...)
метод.
Код:
//This represents the time it will take to zoom
Duration zoomDuration = new Duration(TimeSpan.Parse("0:0:0.3"));
//Set up animation for zooming
DoubleAnimationUsingKeyFrames scaleAnimation = new DoubleAnimationUsingKeyFrames();
scaleAnimation.Duration = zoomDuration;
scaleAnimation.KeyFrames = GetAnimationSplines(newScale);
scaleAnimation.Completed += new EventHandler(
(sender, e) => Scale = newScale);
// Start the scale (zoom) animations
LayoutTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
LayoutTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);
XMAL:
<Grid>
<ItemsControl x:Name="Items">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:MyCanvas Scale="{Binding Scale, Mode=TwoWay}">
<local:MyCanvas.LayoutTransform UseLayoutRounding="True">
<ScaleTransform ScaleX="{Binding Scale, Mode=TwoWay}"
ScaleY="{Binding Scale, Mode=TwoWay}"/>
</local:MyCanvas.LayoutTransform>
</local:MyCanvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
Но после выполнения этого кода, привязка ScaleX
а также ScaleY
с Scale
(свойство в viewmodel) нарушается, т.е. изменяется значение Scale
не меняет масштаб на холсте.
Сообщение об ошибке (используя Snoop):
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Scale; DataItem=null; target element is 'ScaleTransform' (HashCode=796423); target property is 'ScaleX' (type 'Double')
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Scale; DataItem=null; target element is 'ScaleTransform' (HashCode=796423); target property is 'ScaleY' (type 'Double')
Пожалуйста, дайте мне знать, если у кого-нибудь есть решение для этого. Спасибо
3 ответа
Что ж, сегодня я что-то пробовал, и вдруг проблема была решена. Я не понял, как это начинает работать. Я сделал следующие изменения в коде, которые я тоже попробовал ранее.
scaleAnimation.FillBehavior = FillBehavior.Stop;
Кто-нибудь может мне это объяснить. Благодарю.
Я могу подтвердить, что у меня тоже было такое, но я еще не нашел чистого решения. У меня был случай, как вы описали в одном из ваших ответов - касательно изменения ползунка, не затрагивающего связанный объект после запуска анимации (и да, у меня был FillBehavior
установлен в Stop
и / или запустить BeginAnimation(someProperty, null)
"отпустить" анимацию "держать" на свойстве. Чтобы проиллюстрировать, что я все еще могу редактировать свойство после анимации (но не с помощью ползунка, который был источником привязки), я установил кнопку, которая установит для свойства определенное значение. Эта кнопка действительно отлично работала, чтобы изменить это свойство после анимации. Кажется, что в некоторых случаях привязка WPF может прерваться в результате определенных анимаций.
Не очень чистый обходной путь может заключаться в восстановлении привязки в коде в анимации. Completed
обработчик.
Это не решение вышеуказанной проблемы, а рабочий образец WPF Application
воспроизвести вышеупомянутую проблему упоминания.
XAML:
<Window x:Class="TestWpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=zoomer, Path=Value}" ScaleY="{Binding ElementName=zoomer, Path=Value}" x:Name="scaleTx" />
</Grid.LayoutTransform>
<Border Background="Aqua" BorderThickness="3" BorderBrush="Blue" Height="50" Width="50" />
</Grid>
<StackPanel Orientation="Horizontal" Grid.Row="1">
<Slider x:Name="zoomer" Width="200" Value="1" Minimum="0.1" Maximum="3" TickFrequency="0.1" IsSnapToTickEnabled="True" Margin="3"/>
<Button Content="Animate" Click="Button_Click" Margin="3"/>
</StackPanel>
</Grid>
Код:
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//This represents the time it will take to zoom
Duration zoomDuration = new Duration(TimeSpan.Parse("0:0:0.5"));
//Set up animation for zooming
DoubleAnimationUsingKeyFrames scaleAnimation = new DoubleAnimationUsingKeyFrames();
scaleAnimation.Duration = zoomDuration;
scaleAnimation.KeyFrames = GetAnimationSplines(zoomer.Maximum);
scaleTx.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
scaleTx.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);
}
/// <summary>
/// This creates a spline for zooming with non-linear acceleration patterns.
/// </summary>
/// <param name="moveTo"></param>
/// <returns></returns>
protected DoubleKeyFrameCollection GetAnimationSplines(double moveTo)
{
DoubleKeyFrameCollection returnCollection = new DoubleKeyFrameCollection();
returnCollection.Add(new LinearDoubleKeyFrame(moveTo, KeyTime.FromPercent(1.0)));
return returnCollection;
}
}
The shape in the center of window will scale when slide is moved. Once you click animate button to apply animation, the zooming will animate but after that slider stops working.