Элемент управления WPF Popup хорош, но, на мой взгляд, несколько ограничен. есть ли способ «перетащить» всплывающее окно при его открытии (например, с помощью метода окон DragMove ())?
можно ли это сделать без больших проблем или мне придется самому писать замену для всплывающего класса? Благодарность





Для PopUp нет DragMove. Небольшая работа, и вы можете добавить к этому много улучшений.
<Popup x:Name = "pop" IsOpen = "True" Height = "200" Placement = "AbsolutePoint" Width = "200">
<Rectangle Stretch = "Fill" Fill = "Red"/>
</Popup>
В коде добавьте это событие mousemove
pop.MouseMove += new MouseEventHandler(pop_MouseMove);
void pop_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
pop.PlacementRectangle = new Rect(new Point(e.GetPosition(this).X,
e.GetPosition(this).Y),new Point(200,200));
}
}
Я согласен, это решение, которое я дал, - это просто взлом. Как вы сказали, DragDelta более производительна, чем MoveMove.
Но что, если вы не хотите злоупотреблять всплывающим окном в качестве большого пальца (что, я думаю, я имел в виду в комментарии RedGlyphs), но хотите переместить более сложное всплывающее окно (например, наложение видео). использование явного окна не вариант в моем сценарии.
Private Point startPoint;
private void Window_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(null);
}
private void Window_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Point relative = e.GetPosition(null);
Point AbsolutePos = new Point(relative.X + this.Left, relative.Y + this.Top);
this.Top = AbsolutePos.Y - startPoint.Y;
this.Left = AbsolutePos.X - startPoint.X;
}
}
Это работает для перетаскивания моего окна, но, как было сказано, если я буду быстро перемещать мышь, она выйдет из окна и перестанет вызывать событие. Не говоря уже о том, что перетаскивание совсем не гладкое. Кто-нибудь знает, как сделать это правильно, красиво и плавно перетаскивать, не теряя при слишком быстром перетаскивании ??? Если возможно, опубликуйте простой пример, кроме целого учебника, который заставит новичков, таких как я, потеряться в коде. Спасибо!
вы можете захватить мышь, чтобы избежать проблемы, о которой вы упомянули, когда мышь выходит из окна
Другой способ добиться этого - установить для всплывающего окна значение MousePoint. Это заставляет всплывающее окно первоначально появляться в позиции курсора мыши.
Затем вы можете использовать событие Thumb или MouseMove, чтобы установить HorizontalOffset и VerticalOffset Popup. Эти свойства сдвигают всплывающее окно с исходного положения, когда пользователь перетаскивает его.
Не забудьте сбросить HorizontalOffset и VerticalOffset на ноль для следующего использования всплывающего окна!
Вот простое решение с использованием Thumb.
XAML:
<Popup x:Class = "PopupTest.DraggablePopup" ...>
<Canvas x:Name = "ContentCanvas">
</Canvas>
</Popup>
C#:
public partial class DraggablePopup : Popup
{
public DraggablePopup()
{
var thumb = new Thumb
{
Width = 0,
Height = 0,
};
ContentCanvas.Children.Add(thumb);
MouseDown += (sender, e) =>
{
thumb.RaiseEvent(e);
};
thumb.DragDelta += (sender, e) =>
{
HorizontalOffset += e.HorizontalChange;
VerticalOffset += e.VerticalChange;
};
}
}
Возможно, мне не хватает чего-то простого, что знал бы опытный разработчик WPF, но как это можно использовать повторно? Когда я помещаю элемент управления в другой контекст XAML (например, пытаюсь повторно использовать его в окне), любое указанное мной содержимое переопределяет элемент Canvas, к которому привязан ползунок.
Я пробовал это решение. Прекрасно работает! Спасибо, Джейкоб. Я столкнулся только с одной проблемой: у меня есть представление внутри этого пальца, и я могу нормально перетащить весь вид, однако, если в этом представлении есть полоса прокрутки, перетаскивание полосы прокрутки вызывает перетаскивание большого пальца и, следовательно, всего представления. Есть ли способ этого избежать?
Проблема с потерей мыши при слишком быстром движении могла быть решена
Это взято из msdn:
The new window contains the Child content of Popup.
The Popup control maintains a reference to its Child content as a logical child. When the new window is created, the content of Popup becomes a visual child of the window and remains the logical child of Popup. Conversely, Popup remains the logical parent of its Child content.
Другими словами, дочерний элемент всплывающего окна отображается в отдельном окне.
Итак при попытке сделать следующее: Popup.CaptureMouse() захватывает окно оболочки, а не само всплывающее окно. Вместо этого использование Popup.Child.CaptureMouse() захватывает фактическое всплывающее окно.
А все остальные события нужно регистрировать с помощью Popup.Child.
Как Popup.Child.MouseMove, Popup.Child.LostCapture и т. д.
Это было протестировано и отлично работает
Да, захват мыши - правильный способ справиться с перетаскиванием. Все это e.Leftbutton == Pressed немного лениво и вызывает некоторые побочные эффекты.
Основываясь на ответе Джоби Джой, я нашел решение многократного использования, которое позволяет вам добавлять в качестве элемента управления в xaml существующего элемента управления / страницы. Что было невозможно добавить как Xaml с именем, так как он имеет другую область видимости.
[ContentProperty("Child")]
[DefaultEvent("Opened")]
[DefaultProperty("Child")]
[Localizability(LocalizationCategory.None)]
public class DraggablePopup : Popup
{
public DraggablePopup()
{
MouseDown += (sender, e) =>
{
Thumb.RaiseEvent(e);
};
Thumb.DragDelta += (sender, e) =>
{
HorizontalOffset += e.HorizontalChange;
VerticalOffset += e.VerticalChange;
};
}
/// <summary>
/// The original child added via Xaml
/// </summary>
public UIElement TrueChild { get; private set; }
public Thumb Thumb { get; private set; } = new Thumb
{
Width = 0,
Height = 0,
};
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
TrueChild = Child;
var surrogateChild = new StackPanel();
RemoveLogicalChild(TrueChild);
surrogateChild.Children.Add(Thumb);
surrogateChild.Children.Add(TrueChild);
AddLogicalChild(surrogateChild);
Child = surrogateChild;
}
}
Thumbи его событиеDragDelta(выберитеDragStarted/DragCompleted, если вы хотите управлять состояниями). Это намного эффективнее, не будет фрагментировать память и не будет рисковать потерять мышь, как в примере выше. Вот так правильно делается перетаскивание :) См. Пример здесь.