Анимационный прямоугольник для перемещения в окно WPF
Я хочу анимировать изогнутый прямоугольник, который мне нужно переместить внутрь фактического компонента Window снаружи, и желательно, как если бы он только что появился на экране. До сих пор я видел предложения по прокрутке анимации ВНУТРИ холста, который находится ВНУТРИ окна. Я не знаю, смогу ли я заставить Canvas находиться за пределами реального окна. Нужно ли мне? Есть ли лучшие идеи там?
Вот мой XAML и его код на данный момент.
UserMenu.xaml:
<Window x:Class="ChatClient.UserMenu"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="UserMenu" Height="350" Width="525" Icon="media/favicon.gif" Background="#FF3C3636" Foreground="{x:Null}">
<Window.BorderBrush>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="#FF6F6D95" Offset="1"/>
</LinearGradientBrush>
</Window.BorderBrush>
<Grid x:Name="GridBody">
<Canvas Name="WindowMainCanvas">
<Rectangle x:Name="Menu" Fill="#755E5E83" HorizontalAlignment="Left" Height="273" Stroke="Black" VerticalAlignment="Top" Width="446" RadiusY="27.5" RadiusX="27.5" Canvas.Left="545" Canvas.Top="23"/>
<Button x:Name="ChatClientOnlyButton" Content="Chat (Clients Only)" HorizontalAlignment="Left" Height="80" Margin="132,65,0,0" Style="{DynamicResource OTonButtonStyle1}" VerticalAlignment="Top" Width="259" FontFamily="Impact" FontSize="26.667" Foreground="#FF1C045B" Click="chatClientsOnlyOption" Visibility="Hidden"/>
<TextBlock x:Name="MenuLabel" HorizontalAlignment="Left" Height="25" Margin="231,35,0,0" TextWrapping="Wrap" Text="Menu" VerticalAlignment="Top" Width="101" FontFamily="Copperplate Gothic Light" FontSize="20" Visibility="Hidden">
<TextBlock.Foreground>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF0A1D5F" Offset="0.374"/>
<GradientStop Color="#FF6E7FB9" Offset="1"/>
</LinearGradientBrush>
</TextBlock.Foreground>
</TextBlock>
<Canvas ClipToBounds="True" Name="errorCanvas" Width="446" Height="17" Margin="36,152,35,151">
<Rectangle x:Name="errorMarquee" Fill="#FF0A0A0C" HorizontalAlignment="Left" Height="17" Stroke="#FF5B1D1D" VerticalAlignment="Top" Width="446" Canvas.Left="-1" Visibility="Hidden"/>
<TextBlock x:Name="errorText" HorizontalAlignment="Left" Height="16" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="690" FontFamily="Copperplate Gothic Bold" FontSize="16" Foreground="#FF7E0202" Visibility="Hidden"/>
</Canvas>
</Canvas>
</Grid>
</Window>
UserMenu.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace ChatClient
{
/// <summary>
/// Interaction logic for UserMenu.xaml
/// </summary>
public partial class UserMenu : Window
{
public UserMenu()
{
InitializeComponent();
DoubleAnimation menuSlideInAnimation = new DoubleAnimation();
menuSlideInAnimation.From = Menu.Margin.Left;
menuSlideInAnimation.To = 35;
menuSlideInAnimation.Completed += (s, doneEvent) =>
{
//consider additional triggers
};
menuSlideInAnimation.Duration = new Duration(TimeSpan.FromSeconds(7.0));
errorText.BeginAnimation(Rectangle.MarginProperty, menuSlideInAnimation, HandoffBehavior.Compose);
}
private void chatClientsOnlyOption(object sender, RoutedEventArgs e)
{
MessageBox.Show("Not available just yet!");
}
}
}
Есть идеи?
1 ответ
Это довольно сложно сделать, но вы можете сделать это.
Оборачивая прямоугольник, который вы хотите анимировать в элементе управления границей, и переводя его содержимое в изображение.
Создание прозрачного всплывающего окна с границей за пределами вашего окна
Анимация изображения вашего прямоугольника во всплывающем окне
Закрытие всплывающего окна после завершения анимации.
Вот класс, который принимает пограничный контроль для анимации:
public class SlideInPopup
{
private Popup _popup;
public SlideInPopup()
{
}
public void SlideIn(Window parent, int heightOffset, Border animateControl, Duration duration)
{
if ((animateControl != null) && (parent != null))
{
int controlHeight = (int)animateControl.ActualHeight;
int controlWidth = (int)animateControl.ActualWidth;
_popup = new Popup();
double height = parent.Height;
double widthOffset = parent.Width;
double width = parent.Width * 2;
var fromMargin = new Thickness(animateControl.Margin.Left + widthOffset,
animateControl.Margin.Top,
animateControl.Margin.Right,
animateControl.Margin.Bottom);
var toMargin = animateControl.Margin;
Image animateImage = new Image();
animateImage.Name = "imgAnimate";
animateImage.Margin = fromMargin;
animateImage.Height = controlHeight;
animateImage.Width = controlWidth;
animateImage.HorizontalAlignment = HorizontalAlignment.Left;
animateImage.VerticalAlignment = VerticalAlignment.Top;
animateImage.Source = CaptureScreen(animateControl, controlWidth, controlHeight);
animateControl.Visibility = Visibility.Collapsed;
animateControl.Height = 0;
Grid child = new Grid();
child.Height = height;
child.Width = width;
child.Background = Brushes.Transparent;
child.Children.Add(animateImage);
var storyboard = new Storyboard();
ThicknessAnimation animation = new ThicknessAnimation(fromMargin, toMargin, duration);
animation.AccelerationRatio = 0.8;
storyboard.Children.Add(animation);
storyboard.Completed += (s, doneEvent) =>
{
_popup.IsOpen = false;
animateControl.Visibility = Visibility.Visible;
animateControl.Height = controlHeight;
};
Storyboard.SetTarget(animation, animateImage);
Storyboard.SetTargetProperty(animation, new PropertyPath("(Margin)"));
_popup.Height = height;
_popup.Width = width;
_popup.HorizontalOffset = parent.Left;
_popup.VerticalOffset = parent.Top + heightOffset;
_popup.AllowsTransparency = true;
_popup.Child = child;
_popup.IsOpen = true;
child.Resources.Add("sbSlideIn", storyboard);
storyboard.Begin();
}
}
private static BitmapSource CaptureScreen(Visual target, double dpiX, double dpiY)
{
if (target == null)
{
return null;
}
Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
RenderTargetBitmap rtb = new RenderTargetBitmap((int)(bounds.Width * dpiX / 96.0),
(int)(bounds.Height * dpiY / 96.0),
dpiX,
dpiY,
PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext ctx = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(target);
ctx.DrawRectangle(vb, null, new Rect(new Point(), bounds.Size));
}
rtb.Render(dv);
return rtb;
}
}
Затем в главном окне xaml вы можете обернуть прямоугольник с помощью элемента управления границей, а также удалить свойства позиционирования холста.
<Border x:Name="borderRect" Margin="35,23,0,0">
<Rectangle x:Name="Menu" Fill="#755E5E83" HorizontalAlignment="Left" Height="273" Stroke="Black" VerticalAlignment="Top" Width="446" RadiusY="27.5" RadiusX="27.5"/ >
</Border>
Затем вы можете запустить анимацию с помощью этого кода:
var slideInPopup = new SlideInPopup();
int heightOffset = (int)this.Height - (int)((FrameworkElement)this.Content).ActualHeight;
slideInPopup.SlideIn(this, heightOffset, borderRect, new Duration(TimeSpan.FromSeconds(1.0)));