Я создаю раскрывающуюся кнопку, которая состоит из ToggleButton
и ContextMenu
. Меню открывается при нажатии кнопки и выравнивается по кнопке с помощью CustomPopupPlacementCallback
.
. Я применяю настраиваемую анимацию к меню при ее открытии, например:
private void ContextMenu_Opened(object sender, RoutedEventArgs e)
{
ContextMenu contextMenu = (ContextMenu)sender;
NameScope.SetNameScope(this, new NameScope());
TranslateTransform translation = new TranslateTransform();
RegisterName("TranslateTransform", translation);
contextMenu.RenderTransform = translation;
DoubleAnimation translationAnimation = new DoubleAnimation()
{
From = -20,
To = 0,
Duration = new Duration(new TimeSpan(0, 0, 0, 0, 200)),
EasingFunction = new PowerEase() { EasingMode = EasingMode.EaseOut, Power = 3 }
};
Storyboard.SetTargetProperty(translationAnimation, new PropertyPath(TranslateTransform.YProperty));
Storyboard.SetTargetName(translationAnimation, "TranslateTransform");
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(translationAnimation);
storyboard.Begin(this);
}
Это прекрасно работает и делает меню «выдвигающимся из кнопки»:
Примечания стороны:
- Я использую собственную анимацию, потому что значение по умолчанию
PopupAnimation.Slide
не соответствует моим потребностям с точки зрения времени - Я знаю, что я мог бы также анимировать
ContextMenu.VerticalOffsetProperty
, но это заставило бы меню перекрывать кнопку во время анимации. Анимация RenderTransform
, с другой стороны, похоже, делает то, что я хочу.
Теперь я добавил тень к меню, которая требует, чтобы у ContextMenu
был запас (в противном случае Тень будет обрезана). Этот вид нарушает выравнивание меню, потому что теперь оно перекрывает кнопку во время анимации (чего я хотел избежать в первую очередь):
Итак, мне пришла в голову идея убрать верхнее поле из меню во время анимации и восстановить его после этого, например так:
private void ContextMenu_Opened(object sender, RoutedEventArgs e)
{
Thickness originalMargin = contextMenu.Margin;
contextMenu.Margin = new Thickness(
contextMenu.Margin.Left, 0, contextMenu.Margin.Right, contextMenu.Margin.Bottom);
/* Prepare animation as shown before... */
storyboard.Completed += new EventHandler((animation, eventArgs) =>
{
contextMenu.Margin = originalMargin;
});
storyboard.Begin(this);
}
В большинстве случаев это работает как задумано - всплывающее окно идеально выровнен во время анимации, а тени падают наверху после завершения анимации. Однако при восстановлении поля всплывающее окно иногда ненадолго перемещается:
Я знаю, что изменение Margin
свойство ContextMenu
приведет к тому, что система верстки пересмотрит размещение всплывающего окна. Но я не знаю, почему иногда появляется этот промежуточный фрейм до обновления размещения. Кроме того, я не совсем понимаю, почему всплывающее окно прыгает вверх, когда верхнее поле фактически увеличивается.
Обновление: По иронии судьбы, на более медленных машинах поведение наблюдается значительно реже. ..
Могу ли я что-нибудь сделать с этим вопросом?
Как всегда, большое спасибо заранее!