Перетащите элемент управления всплывающим окном WPF
Вопрос
Элемент управления всплывающими окнами WPF хорош, но, на мой взгляд, несколько ограничен.Есть ли способ «перетащить» всплывающее окно, когда оно открыто (например, с помощью метода Windows DragMove())?
можно ли это сделать без больших проблем или мне придется самому написать замену всплывающему классу?Спасибо
Решение
Вот простое решение с использованием Thumb.
- Всплывающее окно подкласса в XAML и выделенном коде
- Добавьте Thumb с шириной/высотой, равной 0 (это также можно сделать в XAML).
- Прослушивайте события MouseDown во всплывающем окне и вызывайте то же событие в Thumb.
- Переместить всплывающее окно на DragDelta
КСАМЛ:
<Popup x:Class="PopupTest.DraggablePopup" ...>
<Canvas x:Name="ContentCanvas">
</Canvas>
</Popup>
С#:
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;
};
}
}
Другие советы
DragMove для PopUp отсутствует. Просто небольшая работа, есть много улучшений, которые вы можете добавить к этому. Р>
<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));
}
}
Еще один способ добиться этого - установить для вашего всплывающего окна значение MousePoint. Это заставляет всплывающее окно изначально появляться в позиции курсора мыши.
Затем вы можете использовать событие Thumb или MouseMove, чтобы установить PopOup «HorizontalOffset & amp; VerticalOffset. Эти свойства сдвигают всплывающее окно от его исходного положения, когда пользователь перетаскивает его.
Не забудьте сбросить HorizontalOffset и VerticalOffset обратно на ноль для следующего использования всплывающего окна!
Проблема с потерей мыши при слишком быстром перемещении может быть решена
<Ч>Это взято из MSDN:
<Ч>Новое окно содержит дочернее содержимое всплывающего окна. Р>
Элемент управления Popup поддерживает ссылку на свой дочерний контент как логический дочерний элемент. Когда новое окно создано, содержимое Popup становится визуальным дочерним элементом окна и остается логическим дочерним элементом Popup. И наоборот, Popup остается логическим родителем своего дочернего содержимого.
Другими словами, дочерний элемент всплывающего окна отображается в отдельном окне.
Поэтому при попытке сделать следующее:
Popup.CaptureMouse ()
захватывает окно оболочки, а не само всплывающее окно. Вместо этого использование Popup.Child.CaptureMouse ()
захватывает фактическое всплывающее окно.
И все остальные события должны быть зарегистрированы с помощью Popup.Child
.
Например, Popup.Child.MouseMove
, Popup.Child.LostCapture
и т. д.
Это было проверено и прекрасно работает
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;
}
}
Это работает для перетаскивания моего окна, но, как было сказано, если я переместлю мышь быстро, оно выйдет из окна и перестанет вызывать событие. Без упоминания перетаскивания не совсем гладко. Кто-нибудь знает, как сделать это правильно, красиво и плавно перетаскивая, не теряя при перетаскивании слишком быстро ??? Если возможно, опубликуйте простой пример, за исключением целого учебника, в котором начинающие, как я, потеряли в коде. Спасибо!
Опираясь на ответ Jobi Joy , я нашел повторно используемое решение, которое позволяет добавлять его как элемент управления в 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;
}
}