鉴于:
<ScrollViewer VerticalScrollBarVisibility="Auto" >
<ItemsControl ItemsSource="{Binding Controls}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
其中“控件绑定(bind)”是包含某种用户控件的 View 模型中的 ObservableCollection。
由于 wrappanel 中的内容居中,因此当前行为如下:
向左移动,并将 UC C 添加到面板中。
我想要的是在添加新的用户控件时添加“移动”翻译/过渡,即我想在添加每个 UC 时向左侧显示 A/B..n 的过渡动画。
我更愿意在 XAML 中做尽可能多的事情,而不是破坏 MVVM 模式。
奖励,我也希望能够在删除 UC 时制作动画。
最佳答案
我将控件视为 FrameworkElement 的 ObservableCollection
您可以使用以下代码:
<Window x:Class="Marathonbet.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="MainWindow_OnLoaded" Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
<Storyboard x:Key="OnLoaded1">
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)" >
<EasingThicknessKeyFrame KeyTime="0" Value="20,0,0,0"/>
<EasingThicknessKeyFrame KeyTime="0:0:0.4" Value="5"/>
</ThicknessAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)" >
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="55"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" >
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="OnUnloaded1" >
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Width)">
<EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="55"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollViewer VerticalScrollBarVisibility="Auto" Grid.Row="0">
<ItemsControl ItemsSource="{Binding Controls}" x:Name="x">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel HorizontalAlignment="Center"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
<Button Grid.Row="1" Content="Add" Margin="5" HorizontalAlignment="Left" Padding="15,2,15,2" Click="btAdd_OnClick"/>
<Button Grid.Row="1" Content="Remove" Margin="64,5,0,5" HorizontalAlignment="Left" Padding="15,2,15,2" Click="btRemove_OnClick"/>
</Grid>
</Window>
背后的代码
public class MyObservableCollection : ObservableCollection<FrameworkElement>
{
private Storyboard unloadedStoryboard;
public Storyboard UnloadedSotryBoard
{
get { return unloadedStoryboard; }
set
{
unloadedStoryboard = value;
unloadedStoryboard.Completed += UnloadedStoryboardOnCompleted;
}
}
public Storyboard LoadedSotryBoard { get; set; }
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (FrameworkElement item in e.NewItems)
item.BeginStoryboard(LoadedSotryBoard);
}
base.OnCollectionChanged(e);
}
private HashSet<int> indexesToRemove = new HashSet<int>();
protected override void RemoveItem(int index)
{
indexesToRemove.Add(index);
var item = Items[index];
UnloadedSotryBoard.Begin(item);
}
private void UnloadedStoryboardOnCompleted(object sender, EventArgs eventArgs)
{
foreach (var i in new HashSet<int>(indexesToRemove))
{
base.RemoveItem(i);
indexesToRemove.Remove(i);
}
}
}
public partial class MainWindow
{
public MyObservableCollection Controls { get; set; }
#region Constructors
public MainWindow()
{
Controls = new MyObservableCollection();
InitializeComponent();
Controls.LoadedSotryBoard = (Storyboard) FindResource("OnLoaded1");
Controls.UnloadedSotryBoard = (Storyboard) FindResource("OnUnloaded1");
}
#endregion
#region Events
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
Controls.Add(new MyControl {DataContext = "A"});
Controls.Add(new MyControl {DataContext = "B"});
Controls.Add(new MyControl {DataContext = "C"});
}
private void btAdd_OnClick(object sender, RoutedEventArgs e)
{
Controls.Add(new MyControl {DataContext = (char) new Random().Next(0, Byte.MaxValue)});
}
private void btRemove_OnClick(object sender, RoutedEventArgs e)
{
if (Controls.Count == 0)
return;
Controls.RemoveAt(Controls.Count - 1);
}
#endregion
}
关于WPF/MVVM - ItemsControl 中的 WrapPanel,添加子项上的动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33756887/